aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-01-12 12:06:51 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-01-12 12:06:51 +0200
commitce492a427632cc7da9607a6a5a53a7a996411226 (patch)
treeefa3f11e673a58174ab1b6d7389e5f783220f77c
parent9a81c308f2d4217592630ef41a18a8998bd66f5c (diff)
Add small_vector workaround for VC
-rw-r--r--butl/small-vector38
-rw-r--r--tests/small-vector/driver.cxx64
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));
}
}