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/vector-impl.cxx | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 odb/vector-impl.cxx (limited to 'odb/vector-impl.cxx') 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_); + } +} -- cgit v1.1