From 2b856f69d490f6cedffac03ecbed8fef318ecc43 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 5 Feb 2013 15:50:06 +0200 Subject: Add support for change-tracking containers ODB now supports "smart" ordered containers. Such containers get extra functions for updating and deleting individual elements. Based on this functionality implement two change-tracking containers: odb::vector (equivalent to std::vector) and QOdbList (equivalent to QList). New tests: common/container/change-tracking and qt/common/container/change- tracking. --- odb/container-traits.hxx | 142 +++++----- odb/details/config-vc.h | 2 + odb/details/config.hxx | 4 + odb/makefile | 1 + odb/std-array-traits.hxx | 13 +- odb/std-forward-list-traits.hxx | 13 +- odb/std-list-traits.hxx | 13 +- odb/std-map-traits.hxx | 26 +- odb/std-set-traits.hxx | 26 +- odb/std-unordered-map-traits.hxx | 26 +- odb/std-unordered-set-traits.hxx | 26 +- odb/std-vector-traits.hxx | 13 +- odb/vector-impl.cxx | 229 ++++++++++++++++ odb/vector-impl.hxx | 222 ++++++++++++++++ odb/vector-impl.ixx | 169 ++++++++++++ odb/vector-traits.hxx | 104 ++++++++ odb/vector-traits.txx | 73 ++++++ odb/vector.hxx | 546 +++++++++++++++++++++++++++++++++++++++ odb/vector.ixx | 397 ++++++++++++++++++++++++++++ 19 files changed, 1909 insertions(+), 136 deletions(-) create mode 100644 odb/vector-impl.cxx create mode 100644 odb/vector-impl.hxx create mode 100644 odb/vector-impl.ixx create mode 100644 odb/vector-traits.hxx create mode 100644 odb/vector-traits.txx create mode 100644 odb/vector.hxx create mode 100644 odb/vector.ixx (limited to 'odb') diff --git a/odb/container-traits.hxx b/odb/container-traits.hxx index 85cf512..18645e6 100644 --- a/odb/container-traits.hxx +++ b/odb/container-traits.hxx @@ -46,50 +46,82 @@ namespace odb } void - insert_one (I index, const V& value) const + insert (I index, const V& value) const { - insert_one_ (index, value, data_); + insert_ (index, value, data_); } bool - load_all (I& next_index, V& next_value) const + select (I& next_index, V& next_value) const { - return load_all_ (next_index, next_value, data_); + return select_ (next_index, next_value, data_); } void - delete_all () const + delete_ () const { - delete_all_ (data_); + delete__ (data_); } // Implementation details. // public: - typedef void (*insert_one_type) (I, const V&, void*); - typedef bool (*load_all_type) (I&, V&, void*); - typedef void (*delete_all_type) (void*); - - ordered_functions (void* data, - insert_one_type io, - load_all_type la, - delete_all_type da) - : data_ (data), insert_one_ (io), load_all_ (la), delete_all_ (da) + ordered_functions (void* data): data_ (data) {} + + public: + void* data_; + bool ordered_; + + void (*insert_) (I, const V&, void*); + bool (*select_) (I&, V&, void*); + void (*delete__) (void*); + }; + + template + struct smart_ordered_functions + { + typedef I index_type; + typedef V value_type; + + void + insert (I index, const V& value) const { + insert_ (index, value, data_); + } + + bool + select (I& next_index, V& next_value) const + { + return select_ (next_index, next_value, data_); } void - ordered (bool v) + update (I index, const V& value) const { - ordered_ = v; + update_ (index, value, data_); } - private: + // Delete all the elements starting with the specified index. To + // delete everything, pass 0. + // + void + delete_ (I start_index) const + { + delete__ (start_index, data_); + } + + // Implementation details. + // + public: + smart_ordered_functions (void* data) : data_ (data) {} + + public: void* data_; - bool ordered_; - insert_one_type insert_one_; - load_all_type load_all_; - delete_all_type delete_all_; + + void (*insert_) (I, const V&, void*); + bool (*select_) (I&, V&, void*); + void (*update_) (I, const V&, void*); + void (*delete__) (I, void*); }; // Set/multiset containers. @@ -100,43 +132,34 @@ namespace odb typedef V value_type; void - insert_one (const V& value) const + insert (const V& value) const { - insert_one_ (value, data_); + insert_ (value, data_); } bool - load_all (V& next_value) const + select (V& next_value) const { - return load_all_ (next_value, data_); + return select_ (next_value, data_); } void - delete_all () const + delete_ () const { - delete_all_ (data_); + delete__ (data_); } // Implementation details. // public: - typedef void (*insert_one_type) (const V&, void*); - typedef bool (*load_all_type) (V&, void*); - typedef void (*delete_all_type) (void*); - - set_functions (void* data, - insert_one_type io, - load_all_type la, - delete_all_type da) - : data_ (data), insert_one_ (io), load_all_ (la), delete_all_ (da) - { - } + set_functions (void* data): data_ (data) {} - private: + public: void* data_; - insert_one_type insert_one_; - load_all_type load_all_; - delete_all_type delete_all_; + + void (*insert_) (const V&, void*); + bool (*select_) (V&, void*); + void (*delete__) (void*); }; // Map/multimap containers. @@ -148,43 +171,34 @@ namespace odb typedef V value_type; void - insert_one (const K& key, const V& value) const + insert (const K& key, const V& value) const { - insert_one_ (key, value, data_); + insert_ (key, value, data_); } bool - load_all (K& next_key, V& next_value) const + select (K& next_key, V& next_value) const { - return load_all_ (next_key, next_value, data_); + return select_ (next_key, next_value, data_); } void - delete_all () const + delete_ () const { - delete_all_ (data_); + delete__ (data_); } // Implementation details. // public: - typedef void (*insert_one_type) (const K&, const V&, void*); - typedef bool (*load_all_type) (K&, V&, void*); - typedef void (*delete_all_type) (void*); - - map_functions (void* data, - insert_one_type io, - load_all_type la, - delete_all_type da) - : data_ (data), insert_one_ (io), load_all_ (la), delete_all_ (da) - { - } + map_functions (void* data): data_ (data) {} - private: + public: void* data_; - insert_one_type insert_one_; - load_all_type load_all_; - delete_all_type delete_all_; + + void (*insert_) (const K&, const V&, void*); + bool (*select_) (K&, V&, void*); + void (*delete__) (void*); }; } diff --git a/odb/details/config-vc.h b/odb/details/config-vc.h index 2c2990a..6c7ed6d 100644 --- a/odb/details/config-vc.h +++ b/odb/details/config-vc.h @@ -19,6 +19,8 @@ //# define ODB_CXX11_DELETED_FUNCTION //# define ODB_CXX11_EXPLICIT_CONVERSION_OPERATOR //# define ODB_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGUMENT +//# define ODB_CXX11_VARIADIC_TEMPLATES +//# define ODB_CXX11_INITIALIZER_LIST #endif #endif /* ODB_DETAILS_CONFIG_VC_H */ diff --git a/odb/details/config.hxx b/odb/details/config.hxx index 36a8e3a..ddba5b7 100644 --- a/odb/details/config.hxx +++ b/odb/details/config.hxx @@ -20,6 +20,8 @@ # define ODB_CXX11_DELETED_FUNCTION # define ODB_CXX11_EXPLICIT_CONVERSION_OPERATOR # define ODB_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGUMENT +# define ODB_CXX11_VARIADIC_TEMPLATE +# define ODB_CXX11_INITIALIZER_LIST # endif #else # include @@ -35,6 +37,8 @@ # define ODB_CXX11_DELETED_FUNCTION # define ODB_CXX11_EXPLICIT_CONVERSION_OPERATOR # define ODB_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGUMENT +# define ODB_CXX11_VARIADIC_TEMPLATE +# define ODB_CXX11_INITIALIZER_LIST # endif #endif diff --git a/odb/makefile b/odb/makefile index c630e7c..ac7355a 100644 --- a/odb/makefile +++ b/odb/makefile @@ -8,6 +8,7 @@ cxx := \ callback.cxx \ exceptions.cxx \ database.cxx \ +vector-impl.cxx \ connection.cxx \ lazy-ptr-impl.cxx \ prepared-query.cxx \ diff --git a/odb/std-array-traits.hxx b/odb/std-array-traits.hxx index a6cb5e3..438665a 100644 --- a/odb/std-array-traits.hxx +++ b/odb/std-array-traits.hxx @@ -19,7 +19,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_ordered; + static const container_kind kind = ck_ordered; + static const bool smart = false; typedef std::array container_type; @@ -33,7 +34,7 @@ namespace odb persist (const container_type& c, const functions& f) { for (index_type i (0); i < N; ++i) - f.insert_one (i, c[i]); + f.insert (i, c[i]); } static void @@ -44,7 +45,7 @@ namespace odb for (; more && i < N; ++i) { index_type dummy; - more = f.load_all (dummy, c[i]); + more = f.select (dummy, c[i]); } assert (!more && i == N); @@ -53,16 +54,16 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (index_type i (0); i < N; ++i) - f.insert_one (i, c[i]); + f.insert (i, c[i]); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-forward-list-traits.hxx b/odb/std-forward-list-traits.hxx index a86524b..1e88abc 100644 --- a/odb/std-forward-list-traits.hxx +++ b/odb/std-forward-list-traits.hxx @@ -17,7 +17,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_ordered; + static const container_kind kind = ck_ordered; + static const bool smart = false; typedef std::forward_list container_type; @@ -33,7 +34,7 @@ namespace odb index_type i (0); for (typename container_type::const_iterator j (c.begin ()), e (c.end ()); j != e; ++j) - f.insert_one (i++, *j); + f.insert (i++, *j); } static void @@ -45,25 +46,25 @@ namespace odb { index_type dummy; i = c.insert_after (i, value_type ()); - more = f.load_all (dummy, *i); + more = f.select (dummy, *i); } } static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); index_type i (0); for (typename container_type::const_iterator j (c.begin ()), e (c.end ()); j != e; ++j) - f.insert_one (i++, *j); + f.insert (i++, *j); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-list-traits.hxx b/odb/std-list-traits.hxx index 9289c67..ec570e2 100644 --- a/odb/std-list-traits.hxx +++ b/odb/std-list-traits.hxx @@ -17,7 +17,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_ordered; + static const container_kind kind = ck_ordered; + static const bool smart = false; typedef std::list container_type; @@ -33,7 +34,7 @@ namespace odb index_type i (0); for (typename container_type::const_iterator j (c.begin ()), e (c.end ()); j != e; ++j) - f.insert_one (i++, *j); + f.insert (i++, *j); } static void @@ -45,25 +46,25 @@ namespace odb { index_type dummy; c.push_back (value_type ()); - more = f.load_all (dummy, c.back ()); + more = f.select (dummy, c.back ()); } } static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); index_type i (0); for (typename container_type::const_iterator j (c.begin ()), e (c.end ()); j != e; ++j) - f.insert_one (i++, *j); + f.insert (i++, *j); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-map-traits.hxx b/odb/std-map-traits.hxx index a30b13e..7347172 100644 --- a/odb/std-map-traits.hxx +++ b/odb/std-map-traits.hxx @@ -19,7 +19,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_map; + static const container_kind kind = ck_map; + static const bool smart = false; typedef std::map container_type; @@ -35,7 +36,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void @@ -47,7 +48,7 @@ namespace odb { key_type k; value_type v; - more = f.load_all (k, v); + more = f.select (k, v); #ifdef ODB_CXX11 c.insert (pair_type (std::move (k), std::move (v))); #else @@ -59,17 +60,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; @@ -81,7 +82,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_multimap; + static const container_kind kind = ck_multimap; + static const bool smart = false; typedef std::multimap container_type; @@ -97,7 +99,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void @@ -109,7 +111,7 @@ namespace odb { key_type k; value_type v; - more = f.load_all (k, v); + more = f.select (k, v); #ifdef ODB_CXX11 c.insert (pair_type (std::move (k), std::move (v))); #else @@ -121,17 +123,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-set-traits.hxx b/odb/std-set-traits.hxx index e6b4853..6df5c61 100644 --- a/odb/std-set-traits.hxx +++ b/odb/std-set-traits.hxx @@ -19,7 +19,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_set; + static const container_kind kind = ck_set; + static const bool smart = false; typedef std::set container_type; typedef V value_type; @@ -32,7 +33,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void @@ -43,7 +44,7 @@ namespace odb while (more) { value_type v; - more = f.load_all (v); + more = f.select (v); #ifdef ODB_CXX11 c.insert (std::move (v)); #else @@ -55,17 +56,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; @@ -77,7 +78,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_multiset; + static const container_kind kind = ck_multiset; + static const bool smart = false; typedef std::multiset container_type; typedef V value_type; @@ -90,7 +92,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void @@ -101,7 +103,7 @@ namespace odb while (more) { value_type v; - more = f.load_all (v); + more = f.select (v); #ifdef ODB_CXX11 c.insert (std::move (v)); #else @@ -113,17 +115,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-unordered-map-traits.hxx b/odb/std-unordered-map-traits.hxx index 072d345..6045d4c 100644 --- a/odb/std-unordered-map-traits.hxx +++ b/odb/std-unordered-map-traits.hxx @@ -18,7 +18,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_map; + static const container_kind kind = ck_map; + static const bool smart = false; typedef std::unordered_map container_type; @@ -34,7 +35,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void @@ -46,7 +47,7 @@ namespace odb { key_type k; value_type v; - more = f.load_all (k, v); + more = f.select (k, v); c.insert (pair_type (std::move (k), std::move (v))); } } @@ -54,17 +55,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; @@ -76,7 +77,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_multimap; + static const container_kind kind = ck_multimap; + static const bool smart = false; typedef std::unordered_multimap container_type; @@ -92,7 +94,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void @@ -104,7 +106,7 @@ namespace odb { key_type k; value_type v; - more = f.load_all (k, v); + more = f.select (k, v); c.insert (pair_type (std::move (k), std::move (v))); } } @@ -112,17 +114,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (i->first, i->second); + f.insert (i->first, i->second); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-unordered-set-traits.hxx b/odb/std-unordered-set-traits.hxx index 6f8e6a8..3033519 100644 --- a/odb/std-unordered-set-traits.hxx +++ b/odb/std-unordered-set-traits.hxx @@ -18,7 +18,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_set; + static const container_kind kind = ck_set; + static const bool smart = false; typedef std::unordered_set container_type; typedef V value_type; @@ -31,7 +32,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void @@ -42,7 +43,7 @@ namespace odb while (more) { value_type v; - more = f.load_all (v); + more = f.select (v); c.insert (std::move (v)); } } @@ -50,17 +51,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; @@ -72,7 +73,8 @@ namespace odb class access::container_traits> { public: - static container_kind const kind = ck_multiset; + static const container_kind kind = ck_multiset; + static const bool smart = false; typedef std::unordered_multiset container_type; typedef V value_type; @@ -85,7 +87,7 @@ namespace odb { for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void @@ -96,7 +98,7 @@ namespace odb while (more) { value_type v; - more = f.load_all (v); + more = f.select (v); c.insert (std::move (v)); } } @@ -104,17 +106,17 @@ namespace odb static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (typename container_type::const_iterator i (c.begin ()), e (c.end ()); i != e; ++i) - f.insert_one (*i); + f.insert (*i); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/std-vector-traits.hxx b/odb/std-vector-traits.hxx index b0a2992..381db36 100644 --- a/odb/std-vector-traits.hxx +++ b/odb/std-vector-traits.hxx @@ -17,7 +17,8 @@ namespace odb class access::container_traits > { public: - static container_kind const kind = ck_ordered; + static const container_kind kind = ck_ordered; + static const bool smart = false; typedef std::vector container_type; @@ -31,7 +32,7 @@ namespace odb persist (const container_type& c, const functions& f) { for (index_type i (0), n (c.size ()); i < n; ++i) - f.insert_one (i, c[i]); + f.insert (i, c[i]); } static void @@ -43,23 +44,23 @@ namespace odb { index_type dummy; c.push_back (value_type ()); - more = f.load_all (dummy, c.back ()); + more = f.select (dummy, c.back ()); } } static void update (const container_type& c, const functions& f) { - f.delete_all (); + f.delete_ (); for (index_type i (0), n (c.size ()); i < n; ++i) - f.insert_one (i, c[i]); + f.insert (i, c[i]); } static void erase (const functions& f) { - f.delete_all (); + f.delete_ (); } }; } diff --git a/odb/vector-impl.cxx b/odb/vector-impl.cxx new file mode 100644 index 0000000..9fd38f3 --- /dev/null +++ b/odb/vector-impl.cxx @@ -0,0 +1,229 @@ +// file : odb/vector-impl.cxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +#include // std::memcpy, std::memset + +#ifdef ODB_CXX11 +# include // std::swap, std::move +#else +# include // std::swap +#endif + +#include // @@ tmp + +using namespace std; + +namespace odb +{ + // vector_impl + // + const unsigned char vector_impl::mask_[4] = {0x3, 0xC, 0x30, 0xC0}; + const unsigned char vector_impl::shift_[4] = {0, 2, 4, 6}; + + vector_impl:: + vector_impl (const vector_impl& x) + : state_ (x.state_), size_ (0), tail_ (0), capacity_ (0), data_ (0) + { + // Copy the data over if we are tracking. + // + if (state_ == state_tracking && size_ != 0) + { + realloc (x.size_ < 1024 ? 1024 : x.size_); + memcpy (data_, x.data_, x.size_ / 4 + (x.size_ % 4 == 0 ? 0 : 1)); + size_ = x.size_; + tail_ = x.tail_; + } + } + + void vector_impl:: + realloc (size_t n) + { + // The new capacity can be less or greater than the old one, but + // it cannot be less than size. + // + size_t b (n / 4 + (n % 4 == 0 ? 0 : 1)); + + if (b != capacity_ * 4) + { + unsigned char* d (static_cast (operator new (b))); + + if (size_ != 0) + memcpy (d, data_, size_ / 4 + (size_ % 4 == 0 ? 0 : 1)); + + if (data_ != 0) + operator delete (data_); + + data_ = d; + capacity_ = b * 4; + } + } + + void vector_impl:: + shrink_to_fit () + { + if (size_ != capacity_) + { + if (size_ != 0) + realloc (size_); + else + { + operator delete (data_); + data_ = 0; + capacity_ = 0; + } + } + } + + void vector_impl:: + start (size_t n) + { + if (n != 0) + { + if (capacity_ < n) + { + size_ = 0; + realloc (n < 1024 ? 1024 : n); + } + + memset (data_, 0, n / 4 + (n % 4 == 0 ? 0 : 1)); + } + + state_ = state_tracking; + size_ = tail_ = n; + } + + void vector_impl:: + push_back (size_t n) + { + for (; n != 0; --n) + { + size_t i (tail_); + + element_state_type s; + if (i != size_) + // We have an erased element we can reuse. + // + s = state_updated; + else + { + if (size_ == capacity_) + { + size_t c (capacity_ == 0 ? 1024 : capacity_ * 2); + if (c < size_ + n) + c = size_ + n; + realloc (c); + } + + s = state_inserted; + size_++; + } + + set (i, s); + tail_++; + } + } + + void vector_impl:: + pop_back (size_t n) + { + for (; n != 0; --n) + { + size_t i (tail_ - 1); + + if (state (i) != state_inserted) + set (i, state_erased); + else + size_--; // tail_ == size_ + + tail_--; + } + } + + void vector_impl:: + insert (size_t i, size_t n) + { + for (; i != tail_; ++i) + if (state (i) != state_inserted) + set (i, state_updated); + + push_back (n); + } + + void vector_impl:: + erase (size_t i, size_t n) + { + pop_back (n); + + for (; i != tail_; ++i) + if (state (i) != state_inserted) + set (i, state_updated); + } + + void vector_impl:: + clear () + { + // The idea is to drop any inserted elements from the back and + // set everything else to erased. + // + if (tail_ == size_) + { + while (size_ != 0 && state (size_ - 1) == state_inserted) + size_--; + + tail_ = size_; + } + + if (tail_ != 0) + memset (data_, 0xFF, tail_ / 4 + (tail_ % 4 == 0 ? 0 : 1)); + + tail_ = 0; + } + + // vector_base + // +#ifdef ODB_CXX11 + vector_base:: + vector_base (vector_base&& x) + : impl_ (std::move (x.impl_)), tran_ (0) + { + if (x.tran_ != 0) + { + x.tran_->unregister (&x); + _arm (*x.tran_); + } + } +#endif + + void vector_base:: + rollback (unsigned short, void* key, unsigned long long) + { + // Mark as changed. + // + static_cast (key)->impl_.change (); + } + + void vector_base:: + swap_tran (vector_base& x) + { + // If either instance is armed, then we need to update the + // callback registration. + // + transaction* t (x.tran_); + if (tran_ != 0) + { + tran_->unregister (this); + x._arm (*tran_); + } + + if (t != 0) + { + t->unregister (&x); + _arm (*t); + } + + std::swap (tran_, x.tran_); + } +} diff --git a/odb/vector-impl.hxx b/odb/vector-impl.hxx new file mode 100644 index 0000000..a6be505 --- /dev/null +++ b/odb/vector-impl.hxx @@ -0,0 +1,222 @@ +// file : odb/vector-impl.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_VECTOR_IMPL_HXX +#define ODB_VECTOR_IMPL_HXX + +#include +#include // ODB_CXX11 + +#include +#include // std::size_t + +#include +#include + +namespace odb +{ + // Change tracking vector implementation details. + // + class LIBODB_EXPORT vector_impl + { + public: + enum element_state_type + { + state_unchanged, + state_inserted, + state_updated, + state_erased + }; + + enum container_state_type + { + state_tracking, + state_not_tracking, + state_changed // Container has changed but individual changes + // were not tracked. + }; + + vector_impl (); + ~vector_impl (); + + // The copy constructor will copy the state. The idea is that the + // copy keeps tracking changes, just like the original. + // + vector_impl (const vector_impl&); + +#ifdef ODB_CXX11 + vector_impl (vector_impl&&); +#endif + + void + swap (vector_impl& x); + + // Allocate enough memory to store the specified number of + // elements. + // + void + reserve (std::size_t); + + // Reduce capacity to size. + // + void + shrink_to_fit (); + + // Capacity (each entry takes 2 bits). + // + std::size_t + capacity () const; + + // (Re)start tracking changes for a vector with n elements. + // + void + start (std::size_t); + + // Stop tracking changes. + // + void + stop (); + + // Mark the container as changed without tracking the changes. + // This state is useful as a fallback mechnism for situations + // where the change information has been discarded (e.g., after + // its state has been updated in the database) but the container + // should remain changed (e.g., after the transaction is rolled + // back). + // + void + change (); + + // Get the state of the container. + // + container_state_type + state () const; + + // Shortcut for state() == state_tracking. + // + bool + tracking () const; + + // Note that the returned size can be greater than the actual, + // parallel vector size. In this case the difference is the + // erased elements at the back. + // + std::size_t + size () const; + + // Get the change state of the specified element. + // + element_state_type + state (std::size_t) const; + + // Change notifications. + // + void + push_back (std::size_t n = 1); + + void + pop_back (std::size_t n = 1); + + void + insert (std::size_t, std::size_t n = 1); + + void + erase (std::size_t, std::size_t n = 1); + + void + modify (std::size_t, std::size_t n = 1); + + void + clear (); + + void + assign (std::size_t n); + + void + resize (std::size_t n); + + private: + // Assignment does not make sense (it is changing of the content). + // + vector_impl& operator= (const vector_impl&); + + private: + void + realloc (std::size_t); + + void + set (std::size_t, element_state_type); + + static const unsigned char mask_[4]; + static const unsigned char shift_[4]; + + container_state_type state_; + + // Size, tail, and capacity are in 2-bit blocks. Size is the number + // of elements we have in data. Tail is the position of the first + // erased element at the back. If there are no erased elements, then + // tail is equal size. Capacity is the number of elements we can + // store in data. + // + std::size_t size_; + std::size_t tail_; + std::size_t capacity_; + unsigned char* data_; + }; + + // Base class that provides a change tracking interface and + // handles the rollback callback. The only function that's + // missing is _start() which needs to know the number of + // elements currently in the vector. + // + class LIBODB_EXPORT vector_base + { + public: + void + _stop () const {impl_.stop ();} + + bool + _tracking () const {return impl_.tracking ();} + + void + _arm (transaction& t) const; + + vector_impl& + _impl () const {return impl_;} + + private: + // Assignment is changing of the content. + // + vector_base& operator= (const vector_base&); + + protected: + vector_base (): tran_ (0) {} + ~vector_base () {if (tran_ != 0) tran_->unregister (this);} + vector_base (const vector_base&); + +#ifdef ODB_CXX11 + vector_base (vector_base&&); +#endif + + void + swap (vector_base&); + + static void + rollback (unsigned short, void* key, unsigned long long); + + private: + void + swap_tran (vector_base&); + + protected: + mutable vector_impl impl_; + mutable transaction* tran_; + }; +} + +#include + +#include + +#endif // ODB_VECTOR_IMPL_HXX diff --git a/odb/vector-impl.ixx b/odb/vector-impl.ixx new file mode 100644 index 0000000..5a859c4 --- /dev/null +++ b/odb/vector-impl.ixx @@ -0,0 +1,169 @@ +// file : odb/vector-impl.ixx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifdef ODB_CXX11 +# include // std::swap +#else +# include // std::swap +#endif + +namespace odb +{ + // vector_impl + // + inline vector_impl:: + vector_impl () + : state_ (state_not_tracking), + size_ (0), tail_ (0), capacity_ (0), data_ (0) + { + } + +#ifdef ODB_CXX11 + inline vector_impl:: + vector_impl (vector_impl&& x) + : state_ (state_not_tracking), + size_ (0), tail_ (0), capacity_ (0), data_ (0) + { + swap (x); + } +#endif + + inline vector_impl:: + ~vector_impl () + { + if (data_ != 0) + operator delete (data_); + } + + inline void vector_impl:: + swap (vector_impl& x) + { + std::swap (state_, x.state_); + std::swap (size_, x.size_); + std::swap (tail_, x.tail_); + std::swap (capacity_, x.capacity_); + std::swap (data_, x.data_); + } + + inline void vector_impl:: + reserve (std::size_t n) + { + if (n > capacity_) + realloc (n); + } + + inline void vector_impl:: + stop () + { + state_ = state_not_tracking; + size_ = tail_ = 0; + } + + inline void vector_impl:: + change () + { + state_ = state_changed; + size_ = tail_ = 0; + } + + inline vector_impl::container_state_type vector_impl:: + state () const + { + return state_; + } + + inline bool vector_impl:: + tracking () const + { + return state_ == state_tracking; + } + + inline std::size_t vector_impl:: + size () const + { + return size_; + } + + inline std::size_t vector_impl:: + capacity () const + { + return capacity_; + } + + inline vector_impl::element_state_type vector_impl:: + state (std::size_t i) const + { + std::size_t r (i % 4); + unsigned char v (data_[i / 4]); + return static_cast ((v & mask_[r]) >> shift_[r]); + } + + inline void vector_impl:: + modify (std::size_t i, std::size_t n) + { + for (; n != 0; --n, ++i) + if (state (i) != state_inserted) + set (i, state_updated); + } + + inline void vector_impl:: + assign (std::size_t n) + { + if (tail_ != 0) + clear (); + + push_back (n); + } + + inline void vector_impl:: + resize (size_t n) + { + if (n < tail_) + pop_back (tail_ - n); + else if (n > tail_) + push_back (n - tail_); + } + + inline void vector_impl:: + set (std::size_t i, element_state_type s) + { + std::size_t r (i % 4); + i /= 4; + unsigned char v (static_cast (s)); + v <<= shift_[r]; + data_[i] = (data_[i] & ~mask_[r]) | v; + } + + // vector_base + // + inline void vector_base:: + _arm (transaction& t) const + { + tran_ = &t; + t.register_ (&rollback, + const_cast (this), + transaction::event_rollback, + 0, + &tran_); + } + + inline vector_base:: + vector_base (const vector_base& x) + : impl_ (x.impl_), tran_ (0) + { + // If the original is armed, then arm ourselves as well. + // + if (x.tran_ != 0) + _arm (*x.tran_); + } + + inline void vector_base:: + swap (vector_base& x) + { + impl_.swap (x.impl_); + + if (tran_ != 0 || x.tran_ != 0) + swap_tran (x); + } +} diff --git a/odb/vector-traits.hxx b/odb/vector-traits.hxx new file mode 100644 index 0000000..874480b --- /dev/null +++ b/odb/vector-traits.hxx @@ -0,0 +1,104 @@ +// file : odb/vector-traits.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_VECTOR_TRAITS_HXX +#define ODB_VECTOR_TRAITS_HXX + +#include + +#include +#include +#include +#include + +namespace odb +{ + template + class access::container_traits > + { + public: + static const container_kind kind = ck_ordered; + static const bool smart = true; + + typedef vector container_type; + + typedef V value_type; + typedef typename container_type::size_type index_type; + + typedef smart_ordered_functions functions; + typedef ordered_functions dumb_functions; + + public: + static void + persist (const container_type& c, const functions& f) + { + for (index_type i (0), n (c.size ()); i < n; ++i) + f.insert (i, c[i]); + + // Now that this container is persistent, start tracking changes. + // + c._start (); + } + + static void + load (container_type& c, bool more, const functions& f) + { + // Stop tracking changes. + // + c._stop (); + + // Load. + // + c.clear (); + while (more) + { + index_type dummy; + c.push_back (value_type ()); + more = f.select (dummy, c.modify_back ()); + } + + // Start tracking changes. + // + c._start (); + } + + static void + update (const container_type&, const functions&); + + static void + erase (const container_type* c, const functions& f) + { + f.delete_ (0); + + // Stop tracking changes. + // + if (c != 0) + c->_stop (); + } + + // Version of load() for dumb functions. Used to support + // inverse members of the container type. The implementation + // is identical to the smart one except we don't turn off/on + // change tracking. + // + static void + load (container_type& c, bool more, const dumb_functions& f) + { + c.clear (); + + while (more) + { + index_type dummy; + c.push_back (value_type ()); + more = f.select (dummy, c.modify_back ()); + } + } + }; +} + +#include + +#include + +#endif // ODB_VECTOR_TRAITS_HXX diff --git a/odb/vector-traits.txx b/odb/vector-traits.txx new file mode 100644 index 0000000..255b074 --- /dev/null +++ b/odb/vector-traits.txx @@ -0,0 +1,73 @@ +// file : odb/vector-traits.txx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + template + void access::container_traits >:: + update (const container_type& c, const functions& f) + { + bool u (false); // Updated flag. + + if (c._tracking ()) + { + const vector_impl& impl (c._impl ()); + + for (std::size_t i (0), n (impl.size ()); i < n; ++i) + { + vector_impl::element_state_type s (impl.state (i)); + + switch (s) + { + case vector_impl::state_unchanged: + { + break; + } + case vector_impl::state_inserted: + { + f.insert (i, c[static_cast (i)]); + u = u || true; + break; + } + case vector_impl::state_updated: + { + f.update (i, c[static_cast (i)]); + u = u || true; + break; + } + case vector_impl::state_erased: + { + f.delete_ (i); // Delete from i onwards. + u = u || true; + break; + } + } + + // We delete all trailing elements in one go. + // + if (s == vector_impl::state_erased) + break; + } + } + else + { + // Fall back to delete all/insert all. + // + f.delete_ (0); + + for (index_type i (0), n (c.size ()); i < n; ++i) + f.insert (i, c[i]); + + u = true; + } + + // Arm the rollback callback and (re)start change tracking. + // + if (u) + { + c._arm (transaction::current ()); + c._start (); + } + } +} diff --git a/odb/vector.hxx b/odb/vector.hxx new file mode 100644 index 0000000..17f8653 --- /dev/null +++ b/odb/vector.hxx @@ -0,0 +1,546 @@ +// file : odb/vector.hxx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_VECTOR_HXX +#define ODB_VECTOR_HXX + +#include +#include // ODB_CXX11 + +#include +#include + +#ifdef ODB_CXX11 +# include // std::move, std::forward +# ifdef ODB_CXX11_INITIALIZER_LIST +# include +# endif +#endif + +#include + +namespace odb +{ + // An std::vector-like container that keeps track of changes. + // + // Note that the style and order of definitions is as appears + // in the standard. + // + template + class vector_iterator; + + template > + class vector: public vector_base + { + public: + typedef std::vector base_vector_type; + typedef typename base_vector_type::iterator base_iterator_type; + typedef typename base_vector_type::reverse_iterator + base_reverse_iterator_type; + // types: + // + typedef typename base_vector_type::reference reference; + typedef typename base_vector_type::const_reference const_reference; + typedef vector_iterator iterator; + typedef typename base_vector_type::const_iterator const_iterator; + typedef typename base_vector_type::size_type size_type; + typedef typename base_vector_type::difference_type difference_type; + typedef T value_type; + typedef A allocator_type; + typedef typename base_vector_type::pointer pointer; + typedef typename base_vector_type::const_pointer const_pointer; + typedef vector_iterator + reverse_iterator; + typedef typename base_vector_type::const_reverse_iterator + const_reverse_iterator; + // construct/copy/destroy: + // + explicit vector(const A& a = A()): v_ (a) {} + explicit vector(size_type n): v_ (n) {} // C++11 + vector(size_type n, const T& v, const A& a = A()): v_ (n, v, a) {} + template + vector(I f, I l, const A& a = A()) : v_ (f, l, a) {} + vector(const vector& x): vector_base (x), v_ (x.v_) {} + // ~vector() {} + vector& operator=(const vector&); + template + void assign(I f, I l); + void assign(size_type n, const T& u); + allocator_type get_allocator() const /*noexcept*/ + {return v_.get_allocator ();} + +#ifdef ODB_CXX11 + vector(vector&& x): vector_base (std::move (x)), v_ (std::move (x.v_)) {} + vector(const vector& x, const A& a): vector_base (x), v_ (x.v_, a) {} + vector(vector&& x, const A& a) + : vector_base (std::move (x)), v_ (std::move (x.v_), a) {} + vector& operator=(vector&&); +#ifdef ODB_CXX11_INITIALIZER_LIST + vector(std::initializer_list il, const A& a = A()): v_ (il, a) {} + vector& operator=(std::initializer_list); + void assign(std::initializer_list); +#endif +#endif + + // iterators: (all /*noexcept*/) + // + iterator begin() {return iterator (this, v_.begin ());} + const_iterator begin() const {return v_.begin ();} + iterator end() {return iterator (this, v_.end ());} + const_iterator end() const {return v_.end ();} + reverse_iterator rbegin() {return reverse_iterator (this, v_.rbegin ());} + const_reverse_iterator rbegin() const {return v_.rbegin ();} + reverse_iterator rend() {return reverse_iterator (this, v_.rend ());} + const_reverse_iterator rend() const {return v_.rend ();} + + // Return standard vector iterators. The begin() functions mark all + // the elements as modified. + // + base_iterator_type mbegin (); + base_iterator_type mend () {return v_.end ();} + base_reverse_iterator_type mrbegin (); + base_reverse_iterator_type mrend () {return v_.rend ();} + +#ifdef ODB_CXX11 + const_iterator cbegin() const {return v_.cbegin ();} + const_iterator cend() const {return v_.cend ();} + const_reverse_iterator crbegin() const {return v_.crbegin ();} + const_reverse_iterator crend() const {return v_.crend ();} +#endif + + // capacity: + // + size_type size() const /*noexcept*/ {return v_.size ();} + size_type max_size() const /*noexcept*/ {return v_.max_size ();} + void resize(size_type); // C++11 + void resize(size_type, const T&); + size_type capacity() const /*noexcept*/ {return v_.capacity ();} + bool empty() const /*noexcept*/ {return v_.empty ();} + void reserve(size_type); + +#ifdef ODB_CXX11 + void shrink_to_fit(); +#endif + + // element access: + // + //reference operator[](size_type n); + reference modify(size_type n); + const_reference operator[](size_type n) const {return v_[n];} + //reference at(size_type n); + reference modify_at(size_type n); + const_reference at(size_type n) const {return v_.at (n);} + //reference front(); + reference modify_front(); + const_reference front() const {return v_.front ();} + //reference back(); + reference modify_back(); + const_reference back() const {return v_.back ();} + + // data access: + // +#ifdef ODB_CXX11 + //T* data() noexcept; + T* modify_data() /*noexcept*/; + const T* data() const /*noexcept*/ {return v_.data ();} +#endif + + // modifiers: + // + void push_back(const T& x); + void pop_back(); + iterator insert(iterator position, const T& x); + void insert(iterator position, size_type n, const T& x); + template + void insert(iterator position, I first, I last); + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + void swap(vector&); + void clear() /*noexcept*/; + +#ifdef ODB_CXX11 + // In C++11 all modifiers use const_iterator instead of iterator + // to represent position. However, some standard libraries (notably + // GCC's) still use iterator and so we will do that as well, for now. + // + void push_back(T&& x); + iterator insert(iterator position, T&& x); + +#ifdef ODB_CXX11_VARIADIC_TEMPLATE + template + void emplace_back(Args&&... args); + template + iterator emplace(iterator position, Args&&... args); +#endif +#endif + + // Interfacing with the base vector. + // + vector (const base_vector_type& x): v_ (x) {} + vector& operator= (const base_vector_type&); + operator const base_vector_type& () const {return v_;} + base_vector_type& base () {return v_;} + const base_vector_type& base () const {return v_;} + +#ifdef ODB_CXX11 + vector (base_vector_type&& x): v_ (std::move (x)) {} + vector& operator= (base_vector_type&&); +#endif + + // Change tracking (the rest comes from vector_base). + // + public: + void + _start () const {impl_.start (v_.size ());} + + private: + base_vector_type v_; + }; + + namespace core + { + using odb::vector; + } + + template + inline bool operator==(const vector& x, const vector& y) + {return x.base () == y.base ();} + + template + inline bool operator==(const vector& x, const std::vector& y) + {return x.base () == y;} + + template + inline bool operator==(const std::vector& x, const vector& y) + {return x == y.base ();} + + template + inline bool operator< (const vector& x, const vector& y) + {return x.base () < y.base ();} + + template + inline bool operator<(const vector& x, const std::vector& y) + {return x.base () < y;} + + template + inline bool operator<(const std::vector& x, const vector& y) + {return x < y.base ();} + + template + inline bool operator!=(const vector& x, const vector& y) + {return x.base () != y.base ();} + + template + inline bool operator!=(const vector& x, const std::vector& y) + {return x.base () != y;} + + template + inline bool operator!=(const std::vector& x, const vector& y) + {return x != y.base ();} + + template + inline bool operator> (const vector& x, const vector& y) + {return x.base () > y.base ();} + + template + inline bool operator>=(const vector& x, const vector& y) + {return x.base () >= y.base ();} + + template + inline bool operator>=(const vector& x, const std::vector& y) + {return x.base () >= y;} + + template + inline bool operator>=(const std::vector& x, const vector& y) + {return x >= y.base ();} + + template + inline bool operator<=(const vector& x, const vector& y) + {return x.base () <= y.base ();} + + template + inline bool operator<=(const vector& x, const std::vector& y) + {return x.base () <= y;} + + template + inline bool operator<=(const std::vector& x, const vector& y) + {return x <= y.base ();} + + template + class vector_iterator + { + public: + typedef V vector_type; + typedef I base_iterator_type; + typedef typename vector_type::const_iterator const_iterator_type; + typedef std::iterator_traits base_iterator_traits; + + typedef typename base_iterator_traits::value_type value_type; + typedef typename base_iterator_traits::difference_type difference_type; + typedef typename base_iterator_traits::pointer pointer; + typedef typename base_iterator_traits::reference reference; + typedef typename base_iterator_traits::iterator_category iterator_category; + + typedef typename vector_type::size_type size_type; + typedef typename vector_type::const_reference const_reference; + typedef typename vector_type::const_pointer const_pointer; + + vector_iterator (): v_ (0), i_ () {} + vector_iterator (vector_type* v, const base_iterator_type& i) + : v_ (v), i_ (i) {} + operator const_iterator_type () const {return i_;} + base_iterator_type base () const {return i_;} + vector_type* vector () const {return v_;} + + // Note: const_{reference,pointer}. + // + const_reference operator* () const {return *i_;} + const_pointer operator-> () const {return i_.operator -> ();} + const_reference operator[] (difference_type n) const {return i_[n];} + + // Modifiers. + // + reference modify () const; + reference modify (difference_type n) const; + + vector_iterator& operator++ () {++i_; return *this;} + vector_iterator operator++ (int) {return vector_iterator (v_, i_++);} + vector_iterator& operator-- () {--i_; return *this;} + vector_iterator operator-- (int) {return vector_iterator (v_, i_--);} + + vector_iterator operator+ (difference_type n) const + {return vector_iterator (v_, i_ + n);} + vector_iterator& operator+= (difference_type n) {i_ += n; return *this;} + vector_iterator operator- (difference_type n) const + {return vector_iterator (v_, i_ - n);} + vector_iterator& operator-= (difference_type n) {i_ -= n; return *this;} + + // Implementation details. + // + public: + base_iterator_type _base () const {return i_;} // Same as base (). + + private: + vector_type* v_; + base_iterator_type i_; + }; + + template + class vector_iterator > + { + public: + typedef V vector_type; + typedef std::reverse_iterator base_iterator_type; + typedef typename vector_type::const_reverse_iterator const_iterator_type; + typedef std::iterator_traits base_iterator_traits; + + typedef typename vector_type::iterator iterator_type; + typedef typename base_iterator_traits::value_type value_type; + typedef typename base_iterator_traits::difference_type difference_type; + typedef typename base_iterator_traits::pointer pointer; + typedef typename base_iterator_traits::reference reference; + typedef typename base_iterator_traits::iterator_category iterator_category; + + typedef typename vector_type::size_type size_type; + typedef typename vector_type::const_reference const_reference; + typedef typename vector_type::const_pointer const_pointer; + + vector_iterator (): v_ (0), i_ () {} + explicit vector_iterator (const iterator_type& i) + : v_ (i.vector ()), i_ (i.base ()) {} + vector_iterator (vector_type* v, const base_iterator_type& i) + : v_ (v), i_ (i) {} + operator const_iterator_type () const {return i_;} + iterator_type base () const {return iterator_type (v_, i_.base ());} + base_iterator_type rbase () const {return i_;} + vector_type* vector () const {return v_;} + + // Note: const_{reference,pointer}. + // + const_reference operator* () const {return *i_;} + const_pointer operator-> () const {return i_.operator -> ();} + const_reference operator[] (difference_type n) const {return i_[n];} + + // Modifiers. + // + reference modify () const; + reference modify (difference_type n) const; + + vector_iterator& operator++ () {++i_; return *this;} + vector_iterator operator++ (int) {return vector_iterator (v_, i_++);} + vector_iterator& operator-- () {--i_; return *this;} + vector_iterator operator-- (int) {return vector_iterator (v_, i_--);} + + vector_iterator operator+ (difference_type n) const + {return vector_iterator (v_, i_ + n);} + vector_iterator& operator+= (difference_type n) {i_ += n; return *this;} + vector_iterator operator- (difference_type n) const + {return vector_iterator (v_, i_ - n);} + vector_iterator& operator-= (difference_type n) {i_ -= n; return *this;} + + // Implementation details. + // + public: + base_iterator_type _base () const {return i_;} // Same as rbase(). + + private: + vector_type* v_; + base_iterator_type i_; + }; + + // operator== + // + template + inline bool + operator== (const vector_iterator& x, const vector_iterator& y) + {return x._base () == y._base ();} + + template + inline bool + operator== (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () == y;} + + template + inline bool + operator== (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x == y._base ();} + + // operator< + // + template + inline bool + operator< (const vector_iterator& x, const vector_iterator& y) + {return x._base () < y._base ();} + + template + inline bool + operator< (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () < y;} + + template + inline bool + operator< (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x < y._base ();} + + // operator!= + // + template + inline bool + operator!= (const vector_iterator& x, const vector_iterator& y) + {return x._base () != y._base ();} + + template + inline bool + operator!= (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () != y;} + + template + inline bool + operator!= (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x != y._base ();} + + // operator> + // + template + inline bool + operator> (const vector_iterator& x, const vector_iterator& y) + {return x._base () > y._base ();} + + template + inline bool + operator> (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () > y;} + + template + inline bool + operator> (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x > y._base ();} + + // operator>= + // + template + inline bool + operator>= (const vector_iterator& x, const vector_iterator& y) + {return x._base () >= y._base ();} + + template + inline bool + operator>= (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () >= y;} + + template + inline bool + operator>= (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x >= y._base ();} + + // operator<= + // + template + inline bool + operator<= (const vector_iterator& x, const vector_iterator& y) + {return x._base () <= y._base ();} + + template + inline bool + operator<= (const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () <= y;} + + template + inline bool + operator<= (const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x <= y._base ();} + + // operator- + // + template + inline typename vector_iterator::difference_type + operator-(const vector_iterator& x, const vector_iterator& y) + {return x._base () - y._base ();} + + template + inline typename vector_iterator::difference_type + operator-(const vector_iterator& x, + const typename vector_iterator::const_iterator_type& y) + {return x._base () - y;} + + template + inline typename vector_iterator::difference_type + operator-(const typename vector_iterator::const_iterator_type& x, + const vector_iterator& y) + {return x - y._base ();} + + // operator+ + // + template + inline vector_iterator + operator+(typename vector_iterator::difference_type n, + const vector_iterator& x) + {return vector_iterator (x.vector (), n + x._base ());} +} + +namespace std +{ + template + inline void swap(odb::vector& x, odb::vector& y) {x.swap (y);} +} + +#include + +#include + +#include + +#endif // ODB_VECTOR_HXX diff --git a/odb/vector.ixx b/odb/vector.ixx new file mode 100644 index 0000000..1e36fe1 --- /dev/null +++ b/odb/vector.ixx @@ -0,0 +1,397 @@ +// file : odb/vector.ixx +// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + // + // vector + // + + // construct/copy/destroy: + // + template + inline vector& vector:: + operator= (const vector& x) + { + v_ = x.v_; + if (_tracking ()) + impl_.assign (v_.size ()); + return *this; + } + + template + template + inline void vector:: + assign (I f, I l) + { + v_.assign (f, l); + if (_tracking ()) + impl_.assign (v_.size ()); + } + + template + inline void vector:: + assign (size_type n, const T& u) + { + v_.assign (n, u); + if (_tracking ()) + impl_.assign (n); + } + +#ifdef ODB_CXX11 + template + inline vector& vector:: + vector& operator=(vector&& x) + { + v_ = std::move (x.v_); + if (_tracking ()) + impl_.assign (v_.size ()); + return *this; + } + +#ifdef ODB_CXX11_INITIALIZER_LIST + template + inline vector& vector:: + operator= (std::initializer_list il) + { + v_ = il; + if (_tracking ()) + impl_.assign (v_.size ()); + return *this; + } + + template + inline void vector:: + assign (std::initializer_list il) + { + v_.assign (il); + if (_tracking ()) + impl_.assign (v_.size ()); + } +#endif +#endif + + // iterators: + // + template + inline typename vector::base_iterator_type vector:: + mbegin () + { + if (_tracking ()) + impl_.modify (0, v_.size ()); + return v_.begin (); + } + + template + inline typename vector::base_reverse_iterator_type vector:: + mrbegin () + { + if (_tracking ()) + impl_.modify (0, v_.size ()); + return v_.rbegin (); + } + + // capacity: + // + template + inline void vector:: + resize (size_type n) + { + v_.resize (n); + if (_tracking ()) + impl_.resize (n); + } + + template + inline void vector:: + resize (size_type n, const T& c) + { + v_.resize (n, c); + if (_tracking ()) + impl_.resize (n); + } + + template + inline void vector:: + reserve (size_type n) + { + v_.reserve (n); + if (_tracking ()) + impl_.reserve (n); + } + +#ifdef ODB_CXX11 + template + inline void vector:: + shrink_to_fit () + { + v_.shrink_to_fit (); + impl_.shrink_to_fit (); + } +#endif + + // element access: + // + template + inline typename vector::reference vector:: + modify (size_type n) + { + reference& r (v_[n]); + if (_tracking ()) + impl_.modify (n); + return r; + } + + template + inline typename vector::reference vector:: + modify_at (size_type n) + { + reference& r (v_.at (n)); + if (_tracking ()) + impl_.modify (n); + return r; + } + + template + inline typename vector::reference vector:: + modify_front () + { + reference& r (v_.front ()); + if (_tracking ()) + impl_.modify (0); + return r; + } + + template + inline typename vector::reference vector:: + modify_back () + { + reference& r (v_.back ()); + if (_tracking ()) + impl_.modify (v_.size () - 1); + return r; + } + +#ifdef ODB_CXX11 + template + inline T* vector:: + modify_data() /*noexcept*/ + { + if (_tracking ()) + impl_.modify (0, v_.size ()); + return v_.data (); + } +#endif + + // modifiers: + // + template + inline void vector:: + push_back (const T& x) + { + v_.push_back (x); + if (_tracking ()) + impl_.push_back (); + } + + template + inline void vector:: + pop_back () + { + v_.pop_back (); + if (_tracking ()) + impl_.pop_back (); + } + + template + inline typename vector::iterator vector:: + insert (iterator p, const T& x) + { + if (_tracking ()) + impl_.insert (static_cast (p.base () - v_.begin ())); + return iterator (this, v_.insert (p.base (), x)); + } + + template + inline void vector:: + insert (iterator p, size_type n, const T& x) + { + if (_tracking ()) + impl_.insert (static_cast (p.base () - v_.begin ()), n); + v_.insert (p.base (), n, x); + } + + template + template + inline void vector:: + insert (iterator p, I f, I l) + { + size_type i, n; + if (_tracking ()) + { + i = static_cast (p.base () - v_.begin ()); + n = v_.size (); + } + + v_.insert (p.base (), f, l); + + if (_tracking ()) + impl_.insert (i, v_.size () - n); + } + + template + inline typename vector::iterator vector:: + erase (iterator p) + { + if (_tracking ()) + impl_.erase (static_cast (p.base () - v_.begin ())); + return iterator (this, v_.erase (p.base ())); + } + + template + inline typename vector::iterator vector:: + erase (iterator f, iterator l) + { + if (_tracking ()) + impl_.erase (static_cast (f.base () - v_.begin ()), + static_cast (l - f)); + return iterator (this, v_.erase (f.base (), l.base ())); + } + + template + inline void vector:: + swap (vector& x) + { + v_.swap (x.v_); + vector_base::swap (x); + } + + template + inline void vector:: + clear () + { + v_.clear (); + if (_tracking ()) + impl_.clear (); + } + +#ifdef ODB_CXX11 + template + inline void vector:: + push_back(T&& x) + { + v_.push_back (std::move (x)); + if (_tracking ()) + impl_.push_back (); + } + + template + inline typename vector::iterator vector:: + insert (iterator p, T&& x) + { + base_iterator_type r (v_.insert (p.base (), std::move (x))); + if (_tracking ()) + impl_.insert (static_cast (r - v_.begin ())); + return iterator (this, r); + } + +#ifdef ODB_CXX11_VARIADIC_TEMPLATE + template + template + inline void vector:: + emplace_back (Args&&... args) + { + v_.push_back (std::forward (args)...); + if (_tracking ()) + impl_.push_back (); + } + + template + template + inline typename vector::iterator vector:: + emplace (iterator p, Args&&... args) + { + base_iterator_type r ( + v_.emplace (p.base (), std::forward (args)...)); + if (_tracking ()) + impl_.insert (static_cast (r - v_.begin ())); + return iterator (this, r); + } +#endif +#endif + + // Interfacing with base vector. + // + template + inline vector& vector:: + operator= (const base_vector_type& x) + { + v_ = x; + if (_tracking ()) + impl_.assign (v_.size ()); + return *this; + } + +#ifdef ODB_CXX11 + template + inline vector& vector:: + operator= (base_vector_type&& x) + { + v_ = std::move (x); + if (_tracking ()) + impl_.assign (v_.size ()); + return *this; + } +#endif + + // + // vector_iterator + // + + template + inline typename vector_iterator::reference vector_iterator:: + modify () const + { + if (v_->_tracking ()) + v_->_impl ().modify (static_cast (i_ - v_->base ().begin ())); + return *i_; + } + + template + inline typename vector_iterator::reference vector_iterator:: + modify (difference_type n) const + { + if (v_->_tracking ()) + v_->_impl ().modify ( + static_cast (i_ - v_->base ().begin () + n)); + return i_[n]; + } + + // + // vector_iterator + // + + template + inline typename vector_iterator >::reference + vector_iterator >:: + modify () const + { + if (v_->_tracking ()) + v_->_impl ().modify ( + static_cast (v_->base ().rend () - i_ - 1)); + return *i_; + } + + template + inline typename vector_iterator >::reference + vector_iterator >:: + modify (difference_type n) const + { + if (v_->_tracking ()) + // Note: going in the opposite direction. + v_->_impl ().modify ( + static_cast (v_->base ().rend () - i_ - 1 - n)); + return i_[n]; + } +} -- cgit v1.1