aboutsummaryrefslogtreecommitdiff
path: root/odb/vector-impl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/vector-impl.cxx')
-rw-r--r--odb/vector-impl.cxx229
1 files changed, 229 insertions, 0 deletions
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 <odb/vector-impl.hxx>
+
+#include <cstring> // std::memcpy, std::memset
+
+#ifdef ODB_CXX11
+# include <utility> // std::swap, std::move
+#else
+# include <algorithm> // std::swap
+#endif
+
+#include <iostream> // @@ 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<unsigned char*> (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<vector_base*> (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_);
+ }
+}