diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2013-02-05 15:50:06 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2013-02-05 15:50:06 +0200 |
commit | 2b856f69d490f6cedffac03ecbed8fef318ecc43 (patch) | |
tree | 0876ef0d3539bb313a9dd66659e805e6980399aa /odb/vector-impl.hxx | |
parent | 20daa3c4285c91dfcd35361f6550f80315e008a5 (diff) |
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.
Diffstat (limited to 'odb/vector-impl.hxx')
-rw-r--r-- | odb/vector-impl.hxx | 222 |
1 files changed, 222 insertions, 0 deletions
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 <odb/pre.hxx> +#include <odb/details/config.hxx> // ODB_CXX11 + +#include <new> +#include <cstddef> // std::size_t + +#include <odb/transaction.hxx> +#include <odb/details/export.hxx> + +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 <odb/vector-impl.ixx> + +#include <odb/post.hxx> + +#endif // ODB_VECTOR_IMPL_HXX |