diff options
Diffstat (limited to 'odb/context.hxx')
-rw-r--r-- | odb/context.hxx | 305 |
1 files changed, 300 insertions, 5 deletions
diff --git a/odb/context.hxx b/odb/context.hxx index 306d2e4..862b74e 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -9,6 +9,7 @@ #include <map> #include <set> +#include <list> #include <stack> #include <vector> #include <string> @@ -267,6 +268,236 @@ struct model_version bool open; }; +// Sections. +// +struct object_section +{ + virtual bool + compare (object_section const&) const = 0; + + virtual bool + separate_load () const = 0; + + virtual bool + separate_update () const = 0; +}; + +inline bool +operator== (object_section const& x, object_section const& y) +{ + return x.compare (y); +} + +inline bool +operator!= (object_section const& x, object_section const& y) +{ + return !x.compare (y); +} + +// Main section. +// +struct main_section_type: object_section +{ + virtual bool + compare (object_section const& s) const; + + virtual bool + separate_load () const {return false;} + + virtual bool + separate_update () const {return false;} +}; + +inline bool +operator== (main_section_type const&, main_section_type const&) +{ + return true; // There is only one main section. +} + +extern main_section_type main_section; + +// User-defined section. +// +struct user_section: object_section +{ + enum load_type + { + load_eager, + load_lazy + }; + + enum update_type + { + update_always, + update_change, + update_manual + }; + + enum special_type + { + special_ordinary, + special_version // Fake section for optimistic version update. + }; + + user_section (semantics::data_member& m, + semantics::class_& o, + std::size_t i, + load_type l, + update_type u, + special_type s = special_ordinary) + : member (&m), object (&o), base (0), index (i), + load (l), update (u), special (s), + total (0), inverse (0), readonly (0), + containers (false), readwrite_containers (false) {} + + virtual bool + compare (object_section const& s) const; + + virtual bool + separate_load () const {return load != load_eager;} + + virtual bool + separate_update () const + { + // A separately-loaded section is always separately-updated since + // it might not be loaded when update is requested. + // + return separate_load () || update != update_always; + } + + bool + load_empty () const; + + bool + update_empty () const; + + bool + empty () const + { + return load_empty () && update_empty (); + } + + // A section is optimistic if the object that contains it is optimistic. + // For polymorphic hierarchies, only sections contained in the root are + // considered optimistic. + // + bool + optimistic () const; + + semantics::data_member* member; // Data member of this section. + semantics::class_* object; // Object containing this section. + user_section* base; // Base of this section. + std::size_t index; // Index of this sections. + + load_type load; + update_type update; + special_type special; + + // Column counts. + // + std::size_t total; + std::size_t inverse; + std::size_t readonly; + + bool containers; + bool readwrite_containers; + + // Total counts across overrides. + // + std::size_t + total_total () const + { + user_section* b (total_base ()); + return total + (b == 0 ? 0 : b->total_total ()); + } + + std::size_t + total_inverse () const + { + user_section* b (total_base ()); + return inverse + (b == 0 ? 0 : b->total_inverse ()); + } + + std::size_t + total_readonly () const + { + user_section* b (total_base ()); + return readonly + (b == 0 ? 0 : b->total_readonly ()); + } + + bool + total_containers () + { + user_section* b (total_base ()); + return containers || (b != 0 && b->total_containers ()); + } + + bool + total_readwrite_containers () + { + user_section* b (total_base ()); + return readwrite_containers || + (b != 0 && b->total_readwrite_containers ()); + } + +private: + user_section* + total_base () const; +}; + +inline bool +operator== (user_section const& x, user_section const& y) +{ + return x.member == y.member; +} + +// Using list for pointer for element stability (see user_section::base). +// +struct user_sections: std::list<user_section> +{ + // Count sections that have something to load. + // + static unsigned short const count_load = 0x01; + + // Count sections that are non-eager but have nothing to load. + // + static unsigned short const count_load_empty = 0x02; + + // Count sections that have something to update. + // + static unsigned short const count_update = 0x04; + + // Count sections that have nothing to update. + // + static unsigned short const count_update_empty = 0x08; + + // Count sections that are optimistic. + // + static unsigned short const count_optimistic = 0x10; + + // Don't exclude fake optimistic version update section from the count. + // + static unsigned short const count_special_version = 0x20; + + // Count all sections, including special. + // + static unsigned short const count_all = count_update | + count_update_empty | + count_special_version; + + static unsigned short const count_new = 0x1000; + static unsigned short const count_override = 0x2000; + static unsigned short const count_total = 0x4000; + + std::size_t + count (unsigned short flags) const; + + user_sections (semantics::class_& o): object (&o) {}; + semantics::class_* object; +}; + +// Context. +// class context { public: @@ -555,6 +786,12 @@ public: return m.count ("version"); } + static bool + version (const data_member_path& mp) + { + return mp.size () == 1 && mp.back ()->count ("version"); + } + // Polymorphic inheritance. Return root of the hierarchy or NULL if // not polymorphic. // @@ -605,6 +842,51 @@ public: return unit.get<model_version> ("model-version"); } + // Object sections. + // + static object_section& + section (semantics::data_member& m) + { + object_section* s (m.get<object_section*> ("section", 0)); + return s == 0 ? main_section : *s; + } + + static object_section& + section (data_member_path const& mp) + { + // The direct member of the object specifies the section. + // + return section (*mp.front ()); + } + + // Member belongs to a section that is loaded separately. + // + static bool + separate_load (semantics::data_member& m) + { + return section (m).separate_load (); + } + + static bool + separate_load (data_member_path const& mp) + { + return section (mp).separate_load (); + } + + // Member belongs to a section that is updated separately. + // + static bool + separate_update (semantics::data_member& m) + { + return section (m).separate_update (); + } + + static bool + separate_update (data_member_path const& mp) + { + return section (mp).separate_update (); + } + // // typedef ::class_kind class_kind_type; @@ -813,7 +1095,9 @@ public: inverse (0), readonly (0), optimistic_managed (0), - discriminator (0) + discriminator (0), + separate_load (0), + separate_update (0) { } @@ -823,10 +1107,13 @@ public: size_t readonly; size_t optimistic_managed; size_t discriminator; + + size_t separate_load; + size_t separate_update; // Only readwrite. }; static column_count_type - column_count (semantics::class_&); + column_count (semantics::class_&, object_section* = 0); static semantics::data_member* id_member (semantics::class_& c) @@ -932,7 +1219,7 @@ public: return false; } - // The 'is a' and 'has a' tests. The has_a test currently does not + // The 'is a' and 'has a' tests. The has_a() test currently does not // cross the container boundaries. // public: @@ -943,7 +1230,13 @@ public: static unsigned short const test_straight_container = 0x10; static unsigned short const test_inverse_container = 0x20; static unsigned short const test_readonly_container = 0x40; - static unsigned short const test_smart_container = 0x80; + static unsigned short const test_readwrite_container = 0x80; + static unsigned short const test_smart_container = 0x100; + + // Treat eager loaded members as belonging to the main section. + // If this flag is specified, then section must be main_section. + // + static unsigned short const include_eager_load = 0x2000; // By default the test goes into bases for non-polymorphic // hierarchies and doesn't go for polymorphic. The following @@ -971,7 +1264,7 @@ public: // a bool value (0 means no match). // size_t - has_a (semantics::class_&, unsigned short flags); + has_a (semantics::class_&, unsigned short flags, object_section* = 0); public: // Process include path by adding the prefix, putting it through @@ -1193,4 +1486,6 @@ has (Y& y) return false; } +#include <odb/context.ixx> + #endif // ODB_CONTEXT_HXX |