Update buffer_vector: 1. Fix bug with initialization of elements in resize(). 2. Add insert() and pop_back(). 3. Don't switch back to static array after dynamic one was used.
This commit is contained in:
parent
e399f99981
commit
70294b4efa
2 changed files with 202 additions and 98 deletions
|
@ -5,7 +5,7 @@
|
|||
#include "../buffer_vector.hpp"
|
||||
|
||||
|
||||
namespace
|
||||
namespace
|
||||
{
|
||||
template <class TCont>
|
||||
void CheckVector(TCont & cont, size_t count)
|
||||
|
@ -73,13 +73,12 @@ UNIT_TEST(BufferVectorSwap)
|
|||
v1.resize(1);
|
||||
TEST_EQUAL ( v1[0].size(), 1, () );
|
||||
TEST_EQUAL ( v1[0][0], 666, () );
|
||||
TEST_NOT_EQUAL ( dd1, v1[0].data(), () );
|
||||
TEST_EQUAL ( dd1, v1[0].data(), () );
|
||||
|
||||
v1.resize(7);
|
||||
TEST_EQUAL ( v1[0].size(), 1, () );
|
||||
TEST_EQUAL ( v1[0][0], 666, () );
|
||||
// stl implementation can reuse buffer of vector after clear
|
||||
//TEST_NOT_EQUAL ( dd1, v1[0].data(), () );
|
||||
TEST_NOT_EQUAL ( dd1, v1[0].data(), () );
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -98,3 +97,74 @@ UNIT_TEST(BufferVectorSwap)
|
|||
TEST_EQUAL ( dd2, v2[0].data(), () );
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVectorZeroInitialized)
|
||||
{
|
||||
for (size_t size = 0; size < 20; ++size)
|
||||
{
|
||||
buffer_vector<int, 5> v(size);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
TEST_EQUAL(v[i], 0, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVectorResize)
|
||||
{
|
||||
for (size_t size = 0; size < 20; ++size)
|
||||
{
|
||||
buffer_vector<int, 5> v;
|
||||
v.resize(size, 3);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
TEST_EQUAL(v[i], 3, ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVectorInsert)
|
||||
{
|
||||
for (size_t initialLength = 0; initialLength < 20; ++initialLength)
|
||||
{
|
||||
for (size_t insertLength = 0; insertLength < 20; ++insertLength)
|
||||
{
|
||||
for (size_t insertPos = 0; insertPos <= initialLength; ++insertPos)
|
||||
{
|
||||
buffer_vector<char, 5> b;
|
||||
vector<char> v;
|
||||
for (size_t i = 0; i < initialLength; ++i)
|
||||
{
|
||||
b.push_back('A' + i);
|
||||
v.push_back('A' + i);
|
||||
}
|
||||
|
||||
vector<int> dataToInsert(insertLength);
|
||||
for (size_t i = 0; i < insertLength; ++i)
|
||||
dataToInsert[i] = 'a' + i;
|
||||
|
||||
b.insert(b.begin() + insertPos, dataToInsert.begin(), dataToInsert.end());
|
||||
v.insert(v.begin() + insertPos, dataToInsert.begin(), dataToInsert.end());
|
||||
|
||||
vector<char> result(b.begin(), b.end());
|
||||
TEST_EQUAL(v, result, (initialLength, insertLength, insertPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(BufferVectorPopBack)
|
||||
{
|
||||
for (size_t len = 1; len < 6; ++len)
|
||||
{
|
||||
buffer_vector<int, 3> v;
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
v.push_back(i);
|
||||
for (size_t i = len; i > 0; --i)
|
||||
{
|
||||
TEST(!v.empty(), (len, i));
|
||||
TEST_EQUAL(v.size(), i, ());
|
||||
TEST_EQUAL(v.front(), 0, ());
|
||||
TEST_EQUAL(v.back(), i-1, ());
|
||||
v.pop_back();
|
||||
TEST_EQUAL(v.size(), i-1, ());
|
||||
}
|
||||
TEST(v.empty(), ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include "../std/array.hpp"
|
||||
#include "../std/algorithm.hpp"
|
||||
#include "../std/vector.hpp"
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class T> void swap_adl_inner(T & r1, T & r2)
|
||||
{
|
||||
swap(r1, r2);
|
||||
}
|
||||
}
|
||||
#include "../base/assert.hpp"
|
||||
#include "../base/swap.hpp"
|
||||
|
||||
template <class T, size_t N> class buffer_vector
|
||||
{
|
||||
array<T, N> m_static;
|
||||
vector<T> m_dynamic;
|
||||
private:
|
||||
enum { USE_DYNAMIC = N + 1 };
|
||||
T m_static[N];
|
||||
size_t m_size;
|
||||
|
||||
void swap_elements(size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
detail::swap_adl_inner(m_static[i], m_dynamic[i]);
|
||||
}
|
||||
|
||||
// call before new size applied (in growing)
|
||||
void flush_to_dynamic()
|
||||
{
|
||||
if (m_size > 0 && m_size <= N)
|
||||
{
|
||||
if (m_dynamic.size() >= m_size)
|
||||
swap_elements(m_size);
|
||||
else
|
||||
{
|
||||
ASSERT ( m_dynamic.empty(), () );
|
||||
m_dynamic.clear();
|
||||
m_dynamic.insert(m_dynamic.end(), m_static.data(), m_static.data() + m_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call before new size applied (in reducing)
|
||||
void flush_to_static(size_t n)
|
||||
{
|
||||
if (m_size > N)
|
||||
{
|
||||
ASSERT_LESS_OR_EQUAL ( n, N, () );
|
||||
swap_elements(n);
|
||||
m_dynamic.clear();
|
||||
}
|
||||
}
|
||||
|
||||
T * data_private()
|
||||
{
|
||||
return (m_size > N ? &m_dynamic[0] : m_static.data());
|
||||
}
|
||||
vector<T> m_dynamic;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
@ -64,88 +19,167 @@ public:
|
|||
typedef T & reference;
|
||||
|
||||
buffer_vector() : m_size(0) {}
|
||||
buffer_vector(size_t n) : m_size(0)
|
||||
explicit buffer_vector(size_t n, T c = T()) : m_size(0)
|
||||
{
|
||||
resize(n);
|
||||
resize(n, c);
|
||||
}
|
||||
|
||||
void reserve(size_t n)
|
||||
{
|
||||
if (n > N)
|
||||
if (m_size == USE_DYNAMIC || n > N)
|
||||
m_dynamic.reserve(n);
|
||||
}
|
||||
|
||||
void resize(size_t n)
|
||||
void resize(size_t n, T c = T())
|
||||
{
|
||||
if (n > N)
|
||||
{
|
||||
if (m_size == USE_DYNAMIC)
|
||||
m_dynamic.resize(n);
|
||||
flush_to_dynamic();
|
||||
}
|
||||
else
|
||||
flush_to_static(n);
|
||||
|
||||
m_size = n;
|
||||
{
|
||||
if (n <= N)
|
||||
{
|
||||
for (size_t i = m_size; i < n; ++i)
|
||||
m_static[i] = c;
|
||||
m_size = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dynamic.reserve(n);
|
||||
size_t const oldSize = m_size;
|
||||
SwitchToDynamic();
|
||||
m_dynamic.insert(m_dynamic.end(), n - oldSize, c);
|
||||
ASSERT_EQUAL(m_dynamic.size(), n, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
m_dynamic.clear();
|
||||
if (m_size == USE_DYNAMIC)
|
||||
m_dynamic.clear();
|
||||
else
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
T const * data() const { return m_size == USE_DYNAMIC ? &m_dynamic[0] : &m_static[0]; }
|
||||
T * data() { return m_size == USE_DYNAMIC ? &m_dynamic[0] : &m_static[0]; }
|
||||
|
||||
T const * begin() const { return data(); }
|
||||
T const * end() const { return (data() + m_size); }
|
||||
T * begin() { return data_private(); }
|
||||
T * end() { return (data_private() + m_size); }
|
||||
T * begin() { return data(); }
|
||||
T const * end() const { return data() + size(); }
|
||||
T * end() { return data() + size(); }
|
||||
|
||||
T const * data() const
|
||||
{
|
||||
return (m_size > N ? &m_dynamic[0] : m_static.data());
|
||||
}
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
bool empty() const { return m_size == USE_DYNAMIC ? m_dynamic.empty() : m_size == 0; }
|
||||
size_t size() const { return m_size == USE_DYNAMIC ? m_dynamic.size() : m_size; }
|
||||
|
||||
T const & front() const
|
||||
{
|
||||
ASSERT ( !empty(), () );
|
||||
return (m_size > N ? m_dynamic.front() : m_static.front());
|
||||
ASSERT(!empty(), ());
|
||||
return *begin();
|
||||
}
|
||||
T & front()
|
||||
{
|
||||
ASSERT(!empty(), ());
|
||||
return *begin();
|
||||
}
|
||||
T const & back() const
|
||||
{
|
||||
ASSERT ( !empty(), () );
|
||||
return (m_size > N ? m_dynamic.back() : m_static[m_size-1]);
|
||||
ASSERT(!empty(), ());
|
||||
return *(end() - 1);
|
||||
}
|
||||
T & back()
|
||||
{
|
||||
ASSERT(!empty(), ());
|
||||
return *(end() - 1);
|
||||
}
|
||||
|
||||
T const & operator[](size_t i) const
|
||||
{
|
||||
return (m_size > N ? m_dynamic[i] : m_static[i]);
|
||||
ASSERT_LESS(i, size(), ());
|
||||
return *(begin() + i);
|
||||
}
|
||||
T & operator[](size_t i)
|
||||
{
|
||||
return (m_size > N ? m_dynamic[i] : m_static[i]);
|
||||
ASSERT_LESS(i, size(), ());
|
||||
return *(begin() + i);
|
||||
}
|
||||
|
||||
void swap(buffer_vector<T, N> & rhs)
|
||||
{
|
||||
m_dynamic.swap(rhs.m_dynamic);
|
||||
Swap(m_size, rhs.m_size);
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
Swap(m_static[i], rhs.m_static[i]);
|
||||
}
|
||||
|
||||
void push_back(T const & t)
|
||||
{
|
||||
if (m_size < N)
|
||||
m_static[m_size] = t;
|
||||
if (m_size == USE_DYNAMIC)
|
||||
m_dynamic.push_back(t);
|
||||
else
|
||||
{
|
||||
flush_to_dynamic();
|
||||
m_dynamic.push_back(t);
|
||||
if (m_size < N)
|
||||
m_static[m_size++] = t;
|
||||
else
|
||||
{
|
||||
ASSERT_EQUAL(m_size, N, ());
|
||||
m_dynamic.reserve(N + 1);
|
||||
SwitchToDynamic();
|
||||
m_dynamic.push_back(t);
|
||||
ASSERT_EQUAL(m_dynamic.size(), N + 1, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++m_size;
|
||||
}
|
||||
|
||||
void swap(buffer_vector & rhs)
|
||||
void pop_back()
|
||||
{
|
||||
m_static.swap(rhs.m_static);
|
||||
m_dynamic.swap(rhs.m_dynamic);
|
||||
std::swap(m_size, rhs.m_size);
|
||||
if (m_size == USE_DYNAMIC)
|
||||
m_dynamic.pop_back();
|
||||
else
|
||||
{
|
||||
ASSERT_GREATER(m_size, 0, ());
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IterT> void insert(T const * where, IterT beg, IterT end)
|
||||
{
|
||||
ptrdiff_t const pos = where - data();
|
||||
ASSERT_GREATER_OR_EQUAL(pos, 0, ());
|
||||
ASSERT_LESS_OR_EQUAL(pos, size(), ());
|
||||
if (m_size == USE_DYNAMIC)
|
||||
m_dynamic.insert(m_dynamic.begin() + pos, beg, end);
|
||||
else
|
||||
{
|
||||
size_t const n = end - beg;
|
||||
if (m_size + n <= N)
|
||||
{
|
||||
if (pos != m_size)
|
||||
for (ptrdiff_t i = m_size - 1; i >= pos; --i)
|
||||
Swap(m_static[i], m_static[i + n]);
|
||||
|
||||
m_size += n;
|
||||
T * writableWhere = &m_static[0] + pos;
|
||||
ASSERT_EQUAL(where, writableWhere, ());
|
||||
while (beg != end)
|
||||
*(writableWhere++) = *(beg++);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dynamic.reserve(m_size + n);
|
||||
SwitchToDynamic();
|
||||
m_dynamic.insert(m_dynamic.begin() + pos, beg, end);
|
||||
ASSERT_EQUAL(m_dynamic.size(), m_dynamic.capacity(), ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void SwitchToDynamic()
|
||||
{
|
||||
for (size_t i = 0; i < m_size; ++i)
|
||||
m_dynamic.push_back(m_static[i]);
|
||||
m_size = USE_DYNAMIC;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -155,5 +189,5 @@ void swap(buffer_vector<T, N> & r1, buffer_vector<T, N> & r2) { r1.swap(r2); }
|
|||
template <typename T, size_t N>
|
||||
inline string debug_print(buffer_vector<T, N> const & v)
|
||||
{
|
||||
return ::my::impl::DebugPrintSequence(v.begin(), v.end());
|
||||
return ::my::impl::DebugPrintSequence(v.data(), v.data() + v.size());
|
||||
}
|
||||
|
|
Reference in a new issue