diff options
-rw-r--r-- | manifest | 6 | ||||
-rw-r--r-- | odb/details/buffer.hxx | 16 | ||||
-rw-r--r-- | odb/lazy-ptr-impl.ixx | 4 | ||||
-rw-r--r-- | odb/nested-container.hxx | 169 | ||||
-rw-r--r-- | odb/schema-catalog.cxx | 3 | ||||
-rw-r--r-- | odb/version-build2.hxx.in | 2 | ||||
-rw-r--r-- | odb/version.hxx | 8 | ||||
-rw-r--r-- | version | 1 |
8 files changed, 161 insertions, 48 deletions
@@ -1,6 +1,6 @@ : 1 name: libodb -version: 2.5.0-b.20.z +version: 2.5.0-b.22.z project: odb summary: Common ODB runtime library license: GPL-2.0-only @@ -15,5 +15,5 @@ email: odb-users@codesynthesis.com build-warning-email: odb-builds@codesynthesis.com builds: all requires: c++11 -depends: * build2 >= 0.13.0 -depends: * bpkg >= 0.13.0 +depends: * build2 >= 0.14.0- +depends: * bpkg >= 0.14.0- diff --git a/odb/details/buffer.hxx b/odb/details/buffer.hxx index 2b26e8c..558be9b 100644 --- a/odb/details/buffer.hxx +++ b/odb/details/buffer.hxx @@ -64,6 +64,22 @@ namespace odb { return static_cast<T*> (data_); } + + // Note that strictly speaking the return type should be void* const* + // but that would make using this function too awkward since we often + // store the result as void*. + // + void** + data_ptr () + { + return &data_; + } + + const void* const* + data_ptr () const + { + return &data_; + } }; typedef basic_buffer<char> buffer; diff --git a/odb/lazy-ptr-impl.ixx b/odb/lazy-ptr-impl.ixx index d69b8e4..7843dc9 100644 --- a/odb/lazy-ptr-impl.ixx +++ b/odb/lazy-ptr-impl.ixx @@ -84,14 +84,14 @@ namespace odb { reset_id (); id_ = r.id_; - db_ = r.db_; - loader_ = r.loader_; free_ = r.free_; copy_ = r.copy_; r.id_ = 0; } + db_ = r.db_; + loader_ = r.loader_; return *this; } #endif diff --git a/odb/nested-container.hxx b/odb/nested-container.hxx index c7627ed..82abf0b 100644 --- a/odb/nested-container.hxx +++ b/odb/nested-container.hxx @@ -19,22 +19,24 @@ namespace odb { // Nested container emulation support for ODB. // - // Note that the outer key in the inner container should strictly - // speaking be a foreign key pointing to the key of the outer - // container. The only way to achieve this currently is to manually - // add the constraint via ALTER TABLE ADD CONSTRAINT. Note, however, - // that as long as we only modify these tables via the ODB container - // interface, not having the foreign key (and not having ON DELETE - // CASCADE) should be harmless (since we have a foreign key pointing - // to the object id). + // In a nutshell, the idea is to represent a nested container, for example, + // vector<vector<V>>, as map<nested_key, V> where nested_key is a composite + // key consisting of the outer and inner container indexes. // - - // Map key that is used to emulate nested container mapping in ODB. - // Template parameter T is a tag that allows us to distinguish keys - // for unrelated containers in order to assign column names, etc. - // Use inner container type for T. + // Note that the outer key in the inner container should strictly speaking + // be a foreign key pointing to the key of the outer container. The only way + // to achieve this currently is to manually add the constraint via ALTER + // TABLE ADD CONSTRAINT. Note, however, that as long as we only modify these + // tables via the ODB container interface, not having the foreign key (and + // not having ON DELETE CASCADE) should be harmless (since we have a foreign + // key pointing to the object id). + + // Map key that is used to emulate 1-level nested container mapping (for + // example, vector<vector<V>>). Template parameter IC is a tag that allows + // us to distinguish keys for unrelated containers in order to assign column + // names, etc. Use the inner container type (for example, vector<V>) for IC. // - template <typename T, + template <typename IC, typename O = std::size_t, typename I = std::size_t> struct nested_key @@ -54,10 +56,40 @@ namespace odb return outer < v.outer || (outer == v.outer && inner < v.inner); } }; + + // Map key that is used to emulate 2-level nested container mapping (for + // example, vector<vector<vector<V>>>>). Use the middle container type for + // MC (for example, vector<vector<V>>). + // + template <typename MC, + typename O = std::size_t, + typename M = std::size_t, + typename I = std::size_t> + struct nested2_key + { + using outer_type = O; + using middle_type = M; + using inner_type = I; + + outer_type outer; + middle_type middle; + inner_type inner; + + nested2_key () = default; + nested2_key (outer_type o, middle_type m, inner_type i) + : outer (o), middle (m), inner (i) {} + + bool + operator< (const nested2_key& v) const + { + return outer != v.outer ? outer < v.outer : + middle != v.middle ? middle < v.middle : + inner < v.inner ; + } + }; } #include <map> -#include <vector> #include <cstddef> // size_t #include <utility> // move(), declval() #include <cassert> @@ -65,46 +97,109 @@ namespace odb namespace odb { - // vector<vector<>> - // - template <typename IC> - struct nested_value_type: - std::remove_reference<decltype (std::declval<IC> ()[0])> {}; + template <typename C> + struct nested1_type: + std::remove_reference<decltype (std::declval<C> ()[0])> {}; + + template <typename C> + struct nested2_type: + std::remove_reference<decltype (std::declval<C> ()[0][0])> {}; + + template <typename C> + struct nested3_type: + std::remove_reference<decltype (std::declval<C> ()[0][0][0])> {}; - template <typename IC> - std::map<nested_key<IC>, typename nested_value_type<IC>::type> - nested_get (const std::vector<IC>& v) + // 1-level nesting. + // + template <typename OC> // For example, OC = vector<vector<V>>. + std::map<nested_key<typename nested1_type<OC>::type>, + typename nested2_type<OC>::type> + nested_get (const OC& oc) { using namespace std; - using I = typename nested_value_type<IC>::type; + using IC = typename nested1_type<OC>::type; + using V = typename nested2_type<OC>::type; using K = nested_key<IC>; - map<K, I> r; - for (size_t n (0); n != v.size (); ++n) + map<K, V> r; + for (size_t o (0); o != oc.size (); ++o) { - const IC& o (v[n]); - for (size_t m (0); m != o.size (); ++m) - r.emplace (K (n, m), o[m]); + const IC& ic (oc[o]); + for (size_t i (0); i != ic.size (); ++i) + r.emplace (K (o, i), ic[i]); } return r; } - template <typename K, typename I, typename IC> + template <typename K, typename V, typename OC> void - nested_set (std::vector<IC>& v, std::map<K, I>&& r) + nested_set (OC& oc, std::map<K, V>&& r) { using namespace std; for (auto& p: r) { - size_t n (p.first.outer); - size_t m (p.first.inner); - I& i (p.second); + size_t o (p.first.outer); + size_t i (p.first.inner); + V& v (p.second); + + assert (o < oc.size ()); + assert (i == oc[o].size ()); + oc[o].push_back (move (v)); + } + } + + // 2-level nesting. + // + template <typename OC> // For example, OC = vector<vector<vector<V>>>. + std::map<nested2_key<typename nested1_type<OC>::type>, + typename nested3_type<OC>::type> + nested2_get (const OC& oc) + { + using namespace std; + + using MC = typename nested1_type<OC>::type; + using V = typename nested3_type<OC>::type; + using K = nested2_key<MC>; + + map<K, V> r; + for (size_t o (0); o != oc.size (); ++o) + { + const auto& mc (oc[o]); + for (size_t m (0); m != mc.size (); ++m) + { + const auto& ic (mc[m]); + for (size_t i (0); i != ic.size (); ++i) + r.emplace (K (o, m, i), ic[i]); + } + } + return r; + } + + template <typename K, typename V, typename OC> + void + nested2_set (OC& oc, std::map<K, V>&& r) + { + using namespace std; + + for (auto& p: r) + { + size_t o (p.first.outer); + size_t m (p.first.middle); + size_t i (p.first.inner); + V& v (p.second); + + assert (o < oc.size ()); + + auto& mc (oc[o]); + + if (m >= mc.size ()) + mc.resize (m + 1); + + assert (i == mc[m].size ()); - assert (n < v.size ()); - assert (m == v[n].size ()); - v[n].push_back (move (i)); + mc[m].push_back (move (v)); } } } diff --git a/odb/schema-catalog.cxx b/odb/schema-catalog.cxx index fb3ab82..1bdc112 100644 --- a/odb/schema-catalog.cxx +++ b/odb/schema-catalog.cxx @@ -267,6 +267,9 @@ namespace odb schema_version i (db.schema_version (name)); + if (i > v) + throw unknown_schema_version (i); // Database too new. + // If there is no schema, then "migrate" by creating it. // if (i == 0) diff --git a/odb/version-build2.hxx.in b/odb/version-build2.hxx.in index 5b4a37d..77a2924 100644 --- a/odb/version-build2.hxx.in +++ b/odb/version-build2.hxx.in @@ -5,7 +5,7 @@ // For the ODB compiler (temporary). // -#define ODB_VERSION 20470 +#define ODB_VERSION 20472 // The numeric version format is AAAAABBBBBCCCCCDDDE where: // diff --git a/odb/version.hxx b/odb/version.hxx index 38b347f..c607f92 100644 --- a/odb/version.hxx +++ b/odb/version.hxx @@ -29,13 +29,13 @@ // ODB interface version: minor, major, and alpha/beta versions. // -#define ODB_VERSION 20470 -#define ODB_VERSION_STR "2.5-b.20" +#define ODB_VERSION 20472 +#define ODB_VERSION_STR "2.5-b.22" // libodb version: interface version plus the bugfix version. // -#define LIBODB_VERSION 2049970 -#define LIBODB_VERSION_STR "2.5.0-b.20" +#define LIBODB_VERSION 2049972 +#define LIBODB_VERSION_STR "2.5.0-b.22" #include <odb/post.hxx> diff --git a/version b/version deleted file mode 100644 index a60117f..0000000 --- a/version +++ /dev/null @@ -1 +0,0 @@ -2.5.0-b.20 |