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:
Yury Melnichek 2011-05-16 23:54:51 +02:00 committed by Alex Zolotarev
parent e399f99981
commit 70294b4efa
2 changed files with 202 additions and 98 deletions

View file

@ -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(), ());
}
}

View file

@ -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());
}