diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-01-12 12:06:51 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-01-12 12:06:51 +0200 |
commit | ce492a427632cc7da9607a6a5a53a7a996411226 (patch) | |
tree | efa3f11e673a58174ab1b6d7389e5f783220f77c | |
parent | 9a81c308f2d4217592630ef41a18a8998bd66f5c (diff) |
Add small_vector workaround for VC
-rw-r--r-- | butl/small-vector | 38 | ||||
-rw-r--r-- | tests/small-vector/driver.cxx | 64 |
2 files changed, 69 insertions, 33 deletions
diff --git a/butl/small-vector b/butl/small-vector index bcb2ddb..8880ffe 100644 --- a/butl/small-vector +++ b/butl/small-vector @@ -55,9 +55,10 @@ namespace butl T* allocate(std::size_t n) { + assert (n >= N); // We should never be asked for less than N. + if (n <= N) { - assert (buf_->free_); // Why would we need another small buffer? buf_->free_ = false; return reinterpret_cast<T*> (buf_->data_); } @@ -198,15 +199,6 @@ namespace butl static_cast<base_type&> (*this) = v; } - small_vector (small_vector&& v) - : base_type (allocator_type (this)) - { - if (v.size () <= N) - reserve (); - - static_cast<base_type&> (*this) = std::move (v); - } - small_vector& operator= (const small_vector& v) { @@ -216,12 +208,38 @@ namespace butl return *this; } + small_vector (small_vector&& v) + : base_type (allocator_type (this)) + { + if (v.size () <= N) + reserve (); + + *this = std::move (v); // Delegate to operator=(&&). + } + small_vector& operator= (small_vector&& v) { + // VC's implementation of operator=(&&) (both 14 and 15) frees the + // memory and then reallocated with capacity equal to v.size(). This is + // clearly sub-optimal (the existing buffer could be reused) so we hope + // this will be fixed eventually. + // +#if defined(_MSC_VER) && _MSC_VER <= 1910 + if (v.size () < N) + { + clear (); + for (T& x: v) + push_back (std::move (x)); + v.clear (); + } + else +#endif + // Note: propagate_on_container_move_assignment = false // static_cast<base_type&> (*this) = std::move (v); + return *this; } diff --git a/tests/small-vector/driver.cxx b/tests/small-vector/driver.cxx index ae9e2a6..f4914de 100644 --- a/tests/small-vector/driver.cxx +++ b/tests/small-vector/driver.cxx @@ -24,14 +24,17 @@ small (const small_vector<T, N>& v) int main () { - using vector = small_vector<string, 1>; + using vector = small_vector<string, 2>; { vector v; - assert (v.capacity () == 1 && small (v)); + assert (v.capacity () == 2 && small (v)); v.push_back ("abc"); - assert (v[0] == "abc" && v.capacity () == 1 && small (v)); + assert (v[0] == "abc" && v.capacity () == 2 && small (v)); + + v.push_back ("ABC"); + assert (v[1] == "ABC" && v.capacity () == 2 && small (v)); string* d (v.data ()); // Small buffer... @@ -49,10 +52,10 @@ main () vector v1, v2; assert (v1.get_allocator () != v2.get_allocator ()); // stack/stack - v1.assign ({"abc", "xyz"}); + v1.assign ({"abc", "ABC", "xyz"}); assert (v1.get_allocator () != v2.get_allocator ()); // heap/stack - v2.assign ({"abc", "xyz"}); + v2.assign ({"abc", "ABC", "xyz"}); assert (v1.get_allocator () == v2.get_allocator ()); // heap/heap v1.pop_back (); @@ -68,9 +71,9 @@ main () // { vector s1 ({"abc"}), s2 (s1); - assert (s1 == s2 && s2.capacity () == 1 && small (s2)); + assert (s1 == s2 && s2.capacity () == 2 && small (s2)); - vector l1 ({"abc", "xyz"}), l2 (l1); + vector l1 ({"abc", "ABC", "xyz"}), l2 (l1); assert (l1 == l2 && !small (l2)); } @@ -89,15 +92,30 @@ main () mstring& operator= (const mstring&) = delete; }; - using vector = small_vector<mstring, 1>; + using vector = small_vector<mstring, 2>; - vector s1; s1.emplace_back ("abc"); - vector s2 (move (s1)); - assert (s2[0] == "abc" && s2.capacity () == 1 && small (s2)); + { + vector s1; + s1.emplace_back ("abc"); + vector s2 (move (s1)); + assert (s2[0] == "abc" && s2.capacity () == 2 && small (s2)); + } - vector l1; l1.emplace_back ("abc"); l1.emplace_back ("xyz"); + { + vector s1; + s1.emplace_back ("abc"); + s1.emplace_back ("ABC"); + vector s2 (move (s1)); + assert (s2[0] == "abc" && s2[1] == "ABC" && + s2.capacity () == 2 && small (s2)); + } + + vector l1; + l1.emplace_back ("abc"); + l1.emplace_back ("ABC"); + l1.emplace_back ("xyz"); vector l2 (move (l1)); - assert (l2[0] == "abc" && l2[1] == "xyz" && !small (l2)); + assert (l2[0] == "abc" && l2[1] == "ABC" && l2[2] == "xyz" && !small (l2)); } // Other constructors. @@ -105,28 +123,28 @@ main () { const char* sa[] = {"abc"}; - const char* la[] = {"abc", "xyz"}; + const char* la[] = {"abc", "ABC", "xyz"}; vector s (sa, sa + 1); - assert (s[0] == "abc" && s.capacity () == 1 && small (s)); + assert (s[0] == "abc" && s.capacity () == 2 && small (s)); - vector l (la, la + 2); - assert (l[0] == "abc" && l[1] == "xyz" && !small (l)); + vector l (la, la + 3); + assert (l[0] == "abc" && l[1] == "ABC" && l[2] == "xyz" && !small (l)); } { vector s (1, "abc"); - assert (s[0] == "abc" && s.capacity () == 1 && small (s)); + assert (s[0] == "abc" && s.capacity () == 2 && small (s)); - vector l (2, "abc"); - assert (l[0] == "abc" && l[1] == "abc" && !small (l)); + vector l (3, "abc"); + assert (l[0] == "abc" && l[2] == "abc" && !small (l)); } { vector s (1); - assert (s[0] == "" && s.capacity () == 1 && small (s)); + assert (s[0] == "" && s.capacity () == 2 && small (s)); - vector l (2); - assert (l[0] == "" && l[1] == "" && !small (l)); + vector l (3); + assert (l[0] == "" && l[2] == "" && !small (l)); } } |