From a482f1c4dd4efab83d3b19309900f1cbf54383a5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 15 Oct 2013 07:01:17 +0200 Subject: Automatically map C++11 enum classes (strong enums) --- NEWS | 4 ++ doc/manual.xhtml | 138 +++++++++++++++++++++++++++++++------- odb/context.cxx | 15 ++++- odb/parser.cxx | 39 +++++++++-- odb/relational/mssql/context.cxx | 9 +-- odb/relational/mysql/context.cxx | 59 ++++++++-------- odb/relational/oracle/context.cxx | 9 +-- odb/relational/pgsql/context.cxx | 9 +-- odb/relational/sqlite/context.cxx | 9 +-- odb/semantics/elements.hxx | 7 +- odb/semantics/enum.cxx | 21 +++++- odb/semantics/enum.hxx | 90 +++++++++++++++++++++++-- odb/semantics/fundamental.cxx | 68 +++++++++++++++---- odb/semantics/fundamental.hxx | 61 +++++++++++------ odb/traversal/enum.cxx | 21 ++++++ odb/traversal/enum.hxx | 23 +++++-- 16 files changed, 439 insertions(+), 143 deletions(-) diff --git a/NEWS b/NEWS index eb0a28f..0deac8f 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,10 @@ Version 2.3.0 to Chapter 9, "Sections" in the ODB manual as well as the 'section' example in the odb-examples package. + * Support for automatic mapping of C++11 enum classes in addition to the + "old" enums. For more information, refer to the ODB manual "Type Mapping" + sections for each database system. + * Support for pattern matching (SQL LIKE operator) in the C++-integrated queries. For more information, refer to Section 4.1, "ODB Query Language" in the ODB manual. diff --git a/doc/manual.xhtml b/doc/manual.xhtml index 79722db..9537121 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -15809,10 +15809,11 @@ class person

Default values specified as enumerators are only supported for members that are mapped to an ENUM or an integer type in the database, which is the case for the automatic - mapping of C++ enums to suitable database types as performed - by the ODB compiler. If you have mapped a C++ enum to another - database type, then you should use a literal corresponding - to that type to specify the default value. For example:

+ mapping of C++ enums and enum classes to suitable database + types as performed by the ODB compiler. If you have mapped + a C++ enum or enum class to another database type, then you + should use a literal corresponding to that type to specify + the default value. For example:

 enum gender {male, female, undisclosed};
@@ -18670,16 +18671,18 @@ person.hxx
      to the VARCHAR(255) MySQL type. Otherwise,
      it is mapped to TEXT.

-

Additionally, by default, C++ enumerations are automatically - mapped to a suitable MySQL type. Contiguous enumerations with - the zero first enumerator are mapped to the MySQL ENUM - type. All other enumerations are mapped to INT or - INT UNSIGNED. In both cases the default NULL - semantics is NOT NULL. For example:

+

Additionally, by default, C++ enums and C++11 enum classes are + automatically mapped to suitable MySQL types. Contiguous + enumerations with the zero first enumerator are mapped to + the MySQL ENUM type. All other enumerations + are mapped to the MySQL types corresponding to their + underlying integral types (see table above). In both + cases the default NULL semantics is + NOT NULL. For example:

 enum color {red, green, blue};
-enum taste
+enum class taste: unsigned char
 {
   bitter = 1, // Non-zero first enumerator.
   sweet,
@@ -18693,7 +18696,7 @@ class object
   ...
 
   color color_; // Mapped to ENUM ('red', 'green', 'blue') NOT NULL.
-  taste taste_; // Mapped to INT UNSIGNED NOT NULL.
+  taste taste_; // Mapped to TINYNT UNSIGNED NOT NULL.
 };
   
@@ -19433,9 +19436,30 @@ class object db not_null pragma (Section 14.4.6, "null/not_null").

-

Additionally, by default, C++ enumerations are automatically mapped to - the SQLite INTEGER type with the default NULL - semantics being NOT NULL.

+

Additionally, by default, C++ enums and C++11 enum classes are + automatically mapped to the SQLite INTEGER type with + the default NULL semantics being NOT NULL. + For example:

+ +
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+  bitter = 1,
+  sweet,
+  sour = 4,
+  salty
+};
+
+#pragma db object
+class object
+{
+  ...
+
+  color color_; // Automatically mapped to INTEGER.
+  taste taste_; // Automatically mapped to INTEGER.
+};
+  

Note also that SQLite only operates with signed integers and the largest value that an SQLite database can store is a signed 64-bit integer. As @@ -20406,9 +20430,31 @@ class object db type pragma (Section 14.4.3, "type").

-

Additionally, by default, C++ enumerations are automatically - mapped to INTEGER with the default NULL - semantics being NOT NULL.

+

Additionally, by default, C++ enums and C++11 enum classes are + automatically mapped to the PostgreSQL types corresponding to their + underlying integral types (see table above). The default + NULL semantics is NOT NULL. For + example:

+ +
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+  bitter = 1,
+  sweet,
+  sour = 4,
+  salty
+};
+
+#pragma db object
+class object
+{
+  ...
+
+  color color_; // Automatically mapped to INTEGER.
+  taste taste_; // Automatically mapped to SMALLINT.
+};
+  

Note also that because PostgreSQL does not support unsigned integers, the unsigned short, unsigned int, and @@ -21174,9 +21220,31 @@ class object object ids that are mapped to these Oracle types, an empty string is an invalid value.

-

Additionally, by default, C++ enumerations are automatically - mapped to NUMBER(10) with the default NULL - semantics being NOT NULL.

+

Additionally, by default, C++ enums and C++11 enum classes are + automatically mapped to the Oracle types corresponding to their + underlying integral types (see table above). The default + NULL semantics is NOT NULL. For + example:

+ +
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+  bitter = 1,
+  sweet,
+  sour = 4,
+  salty
+};
+
+#pragma db object
+class object
+{
+  ...
+
+  color color_; // Automatically mapped to NUMBER(10).
+  taste taste_; // Automatically mapped to NUMBER(3).
+};
+  

It is also possible to add support for additional Oracle types, such as XML, geospatial types, user-defined types, @@ -22114,9 +22182,31 @@ class object always change this mapping using the db type pragma (Section 14.4.3, "type").

-

Additionally, by default, C++ enumerations are automatically - mapped to INT with the default NULL - semantics being NOT NULL.

+

Additionally, by default, C++ enums and C++11 enum classes are + automatically mapped to the SQL Server types corresponding to their + underlying integral types (see table above). The default + NULL semantics is NOT NULL. For + example:

+ +
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+  bitter = 1,
+  sweet,
+  sour = 4,
+  salty
+};
+
+#pragma db object
+class object
+{
+  ...
+
+  color color_; // Automatically mapped to INT.
+  taste taste_; // Automatically mapped to TINYINT.
+};
+  

Note also that because SQL Server does not support unsigned integers, the unsigned short, unsigned int, and diff --git a/odb/context.cxx b/odb/context.cxx index 4db15a0..352cb51 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -1926,16 +1926,25 @@ database_type_impl (semantics::type& t, bool id, bool* null) { - type_map_type::const_iterator i (data_->type_map_.find (t, hint)); + using semantics::enum_; + + // By default map an enum as its underlying type. + // + if (enum_* e = dynamic_cast (&t)) + return database_type_impl ( + e->underlying_type (), e->underlying_type_hint (), id, null); + // Built-in type mapping. + // + type_map_type::const_iterator i (data_->type_map_.find (t, hint)); if (i != data_->type_map_.end ()) { if (null != 0) *null = i->second.null; return id ? i->second.id_type : i->second.type; } - else - return string (); + + return string (); } static string diff --git a/odb/parser.cxx b/odb/parser.cxx index 14dd81a..140e09e 100644 --- a/odb/parser.cxx +++ b/odb/parser.cxx @@ -746,7 +746,7 @@ parse (tree global_scope, path const& main_file) define_fund (char_type_node); define_fund (wchar_type_node); - if (ops_.std () == cxx_version::cxx11) + if (ops_.std () >= cxx_version::cxx11) { define_fund (char16_type_node); define_fund (char32_type_node); @@ -1422,8 +1422,29 @@ emit_enum (tree e, e_node = &dynamic_cast (*n); else { - e_node = &unit_->new_node ( - file, line, clmn, e, TYPE_UNSIGNED (e) != 0); + e_node = &unit_->new_node (file, line, clmn, e); + + // Set the underlying type even for incomplete (forward-declared) enums. + // + tree ut (ENUM_UNDERLYING_TYPE (e)); + names* hint (unit_->find_hint (ut)); + integral_type* un = dynamic_cast ( + unit_->find (TYPE_MAIN_VARIANT (ut))); + + // For "old" enums GCC creates a distinct type node and the only way to + // get to one of the known integrals is via its name. + // + if (un == 0) + { + ut = TREE_TYPE (TYPE_NAME (ut)); + un = dynamic_cast (unit_->find (TYPE_MAIN_VARIANT (ut))); + } + + underlies& edge (unit_->new_edge (*un, *e_node)); + + if (hint != 0) + edge.hint (*hint); + unit_->insert (e, *e_node); } @@ -1459,9 +1480,17 @@ emit_enum (tree e, unit_->new_edge (*e_node, er_node); unit_->insert (decl, er_node); - // Inject enumerators into the outer scope. + // In C++11 the enumerators are always available in the enum's + // scope, even for old enums. + // + if (ops_.std () >= cxx_version::cxx11) + unit_->new_edge (*e_node, er_node, name, access::public_); + + // Inject enumerators into the outer scope unless this is an + // enum class. // - unit_->new_edge (*scope_, er_node, name, access); + if (UNSCOPED_ENUM_P (e)) + unit_->new_edge (*scope_, er_node, name, access); if (trace) ts << "\tenumerator " << name << " at " << file << ":" << line << endl; diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx index 1df235d..a0037eb 100644 --- a/odb/relational/mssql/context.cxx +++ b/odb/relational/mssql/context.cxx @@ -156,18 +156,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INT"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); bool c (bt.is_a ()); diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx index 75b71e9..55dd4f7 100644 --- a/odb/relational/mysql/context.cxx +++ b/odb/relational/mysql/context.cxx @@ -286,15 +286,12 @@ namespace relational bool id, bool* null) { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - using semantics::enum_; using semantics::enumerator; using semantics::array; + string r; + // Enum mapping. // if (enum_* e = dynamic_cast (&t)) @@ -302,43 +299,41 @@ namespace relational // We can only map to ENUM if the C++ enumeration is contiguous // and starts with 0. // - if (e->unsigned_ ()) + enum_::enumerates_iterator i (e->enumerates_begin ()), + end (e->enumerates_end ()); + + if (i != end) { - enum_::enumerates_iterator i (e->enumerates_begin ()), - end (e->enumerates_end ()); + r += "ENUM("; - if (i != end) + for (unsigned long long j (0); i != end; ++i, ++j) { - r += "ENUM("; - - for (unsigned long long j (0); i != end; ++i, ++j) - { - enumerator const& er (i->enumerator ()); + enumerator const& er (i->enumerator ()); - if (er.value () != j) - break; - - if (j != 0) - r += ", "; + if (er.value () != j) + break; - r += quote_string (er.name ()); - } + if (j != 0) + r += ", "; - if (i == end) - r += ")"; - else - r.clear (); + r += quote_string (er.name ()); } - } - - if (r.empty ()) - { - r = "INT"; - if (e->unsigned_ ()) - r += " UNSIGNED"; + if (i == end) + r += ")"; + else + r.clear (); } + + if (!r.empty ()) + return r; } + + r = base_context::database_type_impl (t, hint, id, null); + + if (!r.empty ()) + return r; + // char[N] mapping. // else if (array* a = dynamic_cast (&t)) diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx index f885564..98cda52 100644 --- a/odb/relational/oracle/context.cxx +++ b/odb/relational/oracle/context.cxx @@ -152,18 +152,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "NUMBER(10)"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a ()) diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx index 947c6bd..d09fa2c 100644 --- a/odb/relational/pgsql/context.cxx +++ b/odb/relational/pgsql/context.cxx @@ -252,18 +252,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INTEGER"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a ()) diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx index 664af35..f347d30 100644 --- a/odb/relational/sqlite/context.cxx +++ b/odb/relational/sqlite/context.cxx @@ -242,18 +242,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INTEGER"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a () || diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx index 1199c0c..059b639 100644 --- a/odb/semantics/elements.hxx +++ b/odb/semantics/elements.hxx @@ -178,9 +178,10 @@ namespace semantics // edges. // void - add_edge_right (edge&) - { - } + add_edge_left (edge&) {} + + void + add_edge_right (edge&) {} protected: // For virtual inheritance. Should never be actually called. diff --git a/odb/semantics/enum.cxx b/odb/semantics/enum.cxx index 7cffe30..dd8b905 100644 --- a/odb/semantics/enum.cxx +++ b/odb/semantics/enum.cxx @@ -22,13 +22,18 @@ namespace semantics { } + underlies:: + underlies () + : type_ (0), enum__ (0), hint_ (0) + { + } + enum_:: enum_ (path const& file, size_t line, size_t column, - tree tn, - bool unsigned_) - : node (file, line, column, tn), unsigned__ (unsigned_) + tree tn) + : node (file, line, column, tn) { } @@ -54,15 +59,25 @@ namespace semantics // { type_info ti (typeid (enumerator)); + ti.add_base (typeid (nameable)); ti.add_base (typeid (instance)); insert (ti); } + // underlies + // + { + type_info ti (typeid (underlies)); + ti.add_base (typeid (edge)); + insert (ti); + } + // enum_ // { type_info ti (typeid (enum_)); ti.add_base (typeid (type)); + ti.add_base (typeid (scope)); insert (ti); } } diff --git a/odb/semantics/enum.hxx b/odb/semantics/enum.hxx index de07885..02f2b27 100644 --- a/odb/semantics/enum.hxx +++ b/odb/semantics/enum.hxx @@ -7,6 +7,7 @@ #include #include +#include namespace semantics { @@ -101,7 +102,62 @@ namespace semantics // // - class enum_: public type + class underlies: public edge + { + public: + typedef semantics::enum_ enum_type; + + integral_type& + type () const + { + return *type_; + } + + enum_type& + enum_ () const + { + return *enum__; + } + + // Names edge in terms of which this edge was defined. Can be NULL. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + underlies (); + + void + set_left_node (integral_type& n) + { + type_ = &n; + } + + void + set_right_node (enum_type& n) + { + enum__ = &n; + } + + protected: + integral_type* type_; + enum_type* enum__; + names* hint_; + }; + + // + // + class enum_: public type, public scope { private: typedef std::vector enumerates_list; @@ -123,14 +179,38 @@ namespace semantics return enumerates_.end (); } + underlies& + underlied () const + { + return *underlied_; + } + + integral_type& + underlying_type () const + { + return underlied_->type (); + } + + names* + underlying_type_hint () const + { + return underlied_->hint (); + } + bool unsigned_ () const { - return unsigned__; + return underlying_type ().unsigned_ (); } public: - enum_ (path const&, size_t line, size_t column, tree, bool unsigned_); + enum_ (path const&, size_t line, size_t column, tree); + + void + add_edge_right (underlies& e) + { + underlied_ = &e; + } void add_edge_left (enumerates& e) @@ -138,9 +218,11 @@ namespace semantics enumerates_.push_back (&e); } + using scope::add_edge_left; + private: - bool unsigned__; enumerates_list enumerates_; + underlies* underlied_; }; } diff --git a/odb/semantics/fundamental.cxx b/odb/semantics/fundamental.cxx index 537a5cf..4a3bd69 100644 --- a/odb/semantics/fundamental.cxx +++ b/odb/semantics/fundamental.cxx @@ -2,6 +2,8 @@ // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file +#include + #include #include @@ -22,6 +24,22 @@ namespace semantics return type::fq_name (hint); } + // char + // + bool fund_char:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + + // wchar_t + // + bool fund_wchar:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + // type info // namespace @@ -48,11 +66,19 @@ namespace semantics insert (ti); } + // integral_type + // + { + type_info ti (typeid (integral_type)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + // fund_bool // { type_info ti (typeid (fund_bool)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -60,7 +86,7 @@ namespace semantics // { type_info ti (typeid (fund_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -68,7 +94,23 @@ namespace semantics // { type_info ti (typeid (fund_wchar)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char16 + // + { + type_info ti (typeid (fund_char16)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char32 + // + { + type_info ti (typeid (fund_char32)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -76,7 +118,7 @@ namespace semantics // { type_info ti (typeid (fund_signed_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -84,7 +126,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -92,7 +134,7 @@ namespace semantics // { type_info ti (typeid (fund_short)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -100,7 +142,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_short)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -108,7 +150,7 @@ namespace semantics // { type_info ti (typeid (fund_int)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -116,7 +158,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_int)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -124,7 +166,7 @@ namespace semantics // { type_info ti (typeid (fund_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -132,7 +174,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -140,7 +182,7 @@ namespace semantics // { type_info ti (typeid (fund_long_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -148,7 +190,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_long_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } diff --git a/odb/semantics/fundamental.hxx b/odb/semantics/fundamental.hxx index 55ce322..75cbbf5 100644 --- a/odb/semantics/fundamental.hxx +++ b/odb/semantics/fundamental.hxx @@ -13,7 +13,7 @@ namespace semantics // Fundamental C++ types. // - struct fund_type: public type + struct fund_type: type { virtual string fq_name () const; @@ -27,84 +27,105 @@ namespace semantics fund_void (tree tn): node (path (""), 0, 0, tn) {} }; - struct fund_bool: fund_type - { - fund_bool (tree tn): node (path (""), 0, 0, tn) {} - }; - // // Integral. // - struct fund_char: fund_type + struct integral_type: fund_type + { + virtual bool + unsigned_ () const = 0; + }; + + struct fund_bool: integral_type + { + fund_bool (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_char: integral_type { fund_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const; }; - struct fund_wchar: fund_type + struct fund_wchar: integral_type { fund_wchar (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const; }; - struct fund_char16: fund_type + struct fund_char16: integral_type { fund_char16 (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_char32: fund_type + struct fund_char32: integral_type { fund_char32 (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_signed_char: fund_type + struct fund_signed_char: integral_type { fund_signed_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_char: fund_type + struct fund_unsigned_char: integral_type { fund_unsigned_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_short: fund_type + struct fund_short: integral_type { fund_short (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_short: fund_type + struct fund_unsigned_short: integral_type { fund_unsigned_short (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_int: fund_type + struct fund_int: integral_type { fund_int (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_int: fund_type + struct fund_unsigned_int: integral_type { fund_unsigned_int (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_long: fund_type + struct fund_long: integral_type { fund_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_long: fund_type + struct fund_unsigned_long: integral_type { fund_unsigned_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_long_long: fund_type + struct fund_long_long: integral_type { fund_long_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_long_long: fund_type + struct fund_unsigned_long_long: integral_type { fund_unsigned_long_long (tree tn) : node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; // diff --git a/odb/traversal/enum.cxx b/odb/traversal/enum.cxx index 149f962..fd4ff89 100644 --- a/odb/traversal/enum.cxx +++ b/odb/traversal/enum.cxx @@ -14,13 +14,34 @@ namespace traversal // // + void underlies:: + traverse (type& u) + { + dispatch (u.type ()); + } + + // + // void enum_:: traverse (type& e) { + underlied (e); enumerates (e); } void enum_:: + underlied (type& e) + { + underlied (e, *this); + } + + void enum_:: + underlied (type& e, edge_dispatcher& d) + { + d.dispatch (e.underlied ()); + } + + void enum_:: enumerates (type& e) { enumerates (e, *this); diff --git a/odb/traversal/enum.hxx b/odb/traversal/enum.hxx index 1efccaa..c949934 100644 --- a/odb/traversal/enum.hxx +++ b/odb/traversal/enum.hxx @@ -12,10 +12,7 @@ namespace traversal { struct enumerates: edge { - enumerates () - { - } - + enumerates () {} enumerates (node_dispatcher& n) { node_traverser (n); @@ -27,12 +24,30 @@ namespace traversal struct enumerator: node {}; + struct underlies: edge + { + underlies () {} + underlies (node_dispatcher& n) + { + node_traverser (n); + } + + virtual void + traverse (type&); + }; + struct enum_: node { virtual void traverse (type&); virtual void + underlied (type&); + + virtual void + underlied (type&, edge_dispatcher&); + + virtual void enumerates (type&); virtual void -- cgit v1.1