@@ -38,7 +38,7 @@ class alias_declaration;
3838#line 807 "reflect.h2"
3939class value_member_info ;
4040
41- #line 1030 "reflect.h2"
41+ #line 1115 "reflect.h2"
4242}
4343}
4444
@@ -627,7 +627,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
627627 cpp2::in<bool > bitwise
628628 ) -> basic_enum__ret;
629629
630- #line 967 "reflect.h2"
630+ #line 974 "reflect.h2"
631631// -----------------------------------------------------------------------
632632//
633633// "An enum[...] is a totally ordered value type that stores a
@@ -639,7 +639,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
639639//
640640auto cpp2_enum (meta::type_declaration& t) -> void;
641641
642- #line 992 "reflect.h2"
642+ #line 999 "reflect.h2"
643643// -----------------------------------------------------------------------
644644//
645645// "flag_enum expresses an enumeration that stores values
@@ -652,8 +652,34 @@ auto cpp2_enum(meta::type_declaration& t) -> void;
652652//
653653auto flag_enum (meta::type_declaration& t) -> void;
654654
655- #line 1027 "reflect.h2"
655+ #line 1034 "reflect.h2"
656+ // -----------------------------------------------------------------------
657+ //
658+ // "As with void*, programmers should know that unions [...] are
659+ // inherently dangerous, should be avoided wherever possible,
660+ // and should be handled with special care when actually needed."
661+ //
662+ // -- Stroustrup (The Design and Evolution of C++, 14.3.4.1)
663+ //
664+ // "C++17 needs a type-safe union... The implications of the
665+ // consensus `variant` design are well understood and have been
666+ // explored over several LEWG discussions, over a thousand emails,
667+ // a joint LEWG/EWG session, and not to mention 12 years of
668+ // experience with Boost and other libraries."
669+ //
670+ // -- Axel Naumann, in P0088 (wg21.link/p0088),
671+ // the adopted proposal for C++17 std::variant
672+ //
673+ // -----------------------------------------------------------------------
674+ //
675+ // union
676+ //
677+ // a type that contains exactly one of a fixed set of values at a time
656678//
679+
680+ auto cpp2_union (meta::type_declaration& t) -> void;
681+
682+ #line 1113 "reflect.h2"
657683// =======================================================================
658684// Switch to Cpp1 and close subnamespace meta
659685}
@@ -722,8 +748,11 @@ auto parser::apply_type_meta_functions( declaration_node& n )
722748 else if (name == " flag_enum" ) {
723749 flag_enum ( rtype );
724750 }
751+ else if (name == " union" ) {
752+ cpp2_union ( rtype );
753+ }
725754 else {
726- error ( " (temporary alpha limitation) unrecognized metafunction name '" + name + " ' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum" );
755+ error ( " (temporary alpha limitation) unrecognized metafunction name '" + name + " ' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum, union " );
727756 return false ;
728757 }
729758 }
@@ -1442,16 +1471,23 @@ cpp2::i64 value = -1;
14421471 to_string += " ret: std::string = ();\n " ;
14431472 auto first {true };
14441473
1474+ if (bitwise) {
1475+ to_string += " comma: std::string = ();\n " ;
1476+ }
1477+
14451478 for (
14461479
14471480 auto const & e : enumerators ) { do {
14481481 if (bitwise) {
1449- std::string comma {" std::string(\" , \" ) + " };
14501482 if (first) {
14511483 to_string += " ret = \" (\" ;\n " ;
1452- comma = " " ;
14531484 }
1454- to_string += " if value & (" + cpp2::to_string (e.name ) + " ) { ret += " + cpp2::to_string (comma) + " \" " + cpp2::to_string (e.name ) + " \" ; }\n " ;
1485+ if (e.name == " none" ) { // a "none" flag should match if no bits set
1486+ to_string += " if value == " + cpp2::to_string (e.name ) + " { ret += comma + \" " + cpp2::to_string (e.name ) + " \" ; comma = \" , \" ; }\n " ;
1487+ }
1488+ else { // other flags need to be &-ed
1489+ to_string += " if (value & " + cpp2::to_string (e.name ) + " ) == " + cpp2::to_string (e.name ) + " { ret += comma + \" " + cpp2::to_string (e.name ) + " \" ; comma = \" , \" ; }\n " ;
1490+ }
14551491 }
14561492 else {
14571493 std::string else_ {" else " };
@@ -1477,13 +1513,13 @@ cpp2::i64 value = -1;
14771513 CPP2_UFCS (require, t, CPP2_UFCS (add_member, t, " to_string: (this) -> std::string = { return " + cpp2::to_string (CPP2_UFCS_0 (name, t)) + " ::to_string(this); }" ),
14781514 " could not add to_string member function" );
14791515
1480- #line 961 "reflect.h2"
1516+ #line 968 "reflect.h2"
14811517 // 3. A basic_enum is-a value type
14821518
14831519 CPP2_UFCS_0 (basic_value, t);
14841520return { std::move (underlying_type), std::move (strict_underlying_type.value ()) }; }
14851521
1486- #line 976 "reflect.h2"
1522+ #line 983 "reflect.h2"
14871523auto cpp2_enum (meta::type_declaration& t) -> void
14881524{
14891525 // Let basic_enum do its thing, with an incrementing value generator
@@ -1499,7 +1535,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void
14991535 ));
15001536}
15011537
1502- #line 1002 "reflect.h2"
1538+ #line 1009 "reflect.h2"
15031539auto flag_enum (meta::type_declaration& t) -> void
15041540{
15051541 // Add "none" member as a regular name to signify "no flags set"
@@ -1524,7 +1560,63 @@ auto flag_enum(meta::type_declaration& t) -> void
15241560 ));
15251561}
15261562
1527- #line 1030 "reflect.h2"
1563+ #line 1058 "reflect.h2"
1564+ auto cpp2_union (meta::type_declaration& t) -> void
1565+ {
1566+ std::vector<value_member_info> alternatives {};
1567+
1568+ // 1. Gather: All the user-written members, and find/compute the max size
1569+
1570+ // (copy first := true)
1571+ for (
1572+ // next first = false
1573+ auto const & m : CPP2_UFCS_0 (get_members, t) )
1574+ {
1575+ CPP2_UFCS (require, m, (CPP2_UFCS_0 (is_public, m) || CPP2_UFCS_0 (is_default_access, m)) && CPP2_UFCS_0 (is_object, m),
1576+ " a union alternative cannot be protected or private" );
1577+
1578+ if (CPP2_UFCS_0 (is_object, m)) {
1579+ auto mo {CPP2_UFCS_0 (as_object, m)};
1580+
1581+ // Adding local variable 'e' to work around a Clang warning
1582+ value_member_info e {cpp2::as_<std::string>(CPP2_UFCS_0 (name, mo)), CPP2_UFCS_0 (type, mo), cpp2::as_<std::string>(CPP2_UFCS_0 (initializer, mo))};
1583+ CPP2_UFCS (push_back, alternatives, e);
1584+ }
1585+ }
1586+
1587+ #line 1082 "reflect.h2"
1588+ // 2. Replace: Erase the contents and replace with modified contents
1589+
1590+ CPP2_UFCS_0 (remove_all_members, t);
1591+
1592+ // Compute the size
1593+ std::string Size {" Size :== cpp2::max( " };
1594+ {
1595+ std::string comma = " " ;
1596+
1597+ #line 1090 "reflect.h2"
1598+ for (
1599+
1600+ auto const & e : alternatives ) { do {
1601+ Size += comma + " sizeof(" + cpp2::to_string (e.type ) + " )" ;
1602+ } while (false ); comma = " , " ; }
1603+ }
1604+
1605+ #line 1096 "reflect.h2"
1606+ Size += " );\n " ;
1607+ CPP2_UFCS (require, t, CPP2_UFCS (add_member, t, std::move (Size)),
1608+ " could not add Size" );
1609+
1610+ #line 1102 "reflect.h2"
1611+ // TODO
1612+
1613+ #line 1106 "reflect.h2"
1614+ // // 3. A basic_enum is-a value
1615+
1616+ // t.value();
1617+ }
1618+
1619+ #line 1115 "reflect.h2"
15281620}
15291621}
15301622
0 commit comments