From 833ded9fc5e0678cff9fdaaef99f56206ce38e1b Mon Sep 17 00:00:00 2001 From: vng Date: Sat, 15 Jan 2011 13:32:16 +0200 Subject: [PATCH] Add buffer_vector and use it in FeatureType for geometry storing. --- base/base.pro | 11 +- base/base_tests/base_tests.pro | 6 +- base/base_tests/buffer_vector_test.cpp | 99 +++++++++++++++ base/buffer_vector.hpp | 141 ++++++++++++++++++++++ base/stl_add.hpp | 10 +- indexer/feature.cpp | 11 +- indexer/feature.hpp | 14 +-- indexer/feature_impl.hpp | 30 ++--- indexer/indexer_tests/feature_routine.cpp | 2 + 9 files changed, 286 insertions(+), 38 deletions(-) create mode 100644 base/base_tests/buffer_vector_test.cpp create mode 100644 base/buffer_vector.hpp diff --git a/base/base.pro b/base/base.pro index 9b26ce8a41..69f2f9f9c6 100644 --- a/base/base.pro +++ b/base/base.pro @@ -8,7 +8,8 @@ DEPENDENCIES = include($$ROOT_DIR/common.pri) -SOURCES += base.cpp \ +SOURCES += \ + base.cpp \ internal/debug_new.cpp \ logging.cpp \ thread.cpp \ @@ -16,9 +17,10 @@ SOURCES += base.cpp \ profiler.cpp \ commands_queue.cpp \ shared_buffer_manager.cpp \ - memory_mapped_file.cpp + memory_mapped_file.cpp \ -HEADERS += SRC_FIRST.hpp \ +HEADERS += \ + SRC_FIRST.hpp \ assert.hpp \ const_helper.hpp \ internal/debug_new.hpp \ @@ -55,4 +57,5 @@ HEADERS += SRC_FIRST.hpp \ stats.hpp \ monitor.hpp \ shared_buffer_manager.hpp \ - memory_mapped_file.hpp + memory_mapped_file.hpp \ + buffer_vector.hpp \ diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro index 0d9d16674b..8c66fff5b7 100644 --- a/base/base_tests/base_tests.pro +++ b/base/base_tests/base_tests.pro @@ -14,7 +14,8 @@ win32-g++ { LIBS += -lpthread } -SOURCES += ../../testing/testingmain.cpp \ +SOURCES += \ + ../../testing/testingmain.cpp \ const_helper.cpp \ math_test.cpp \ scope_guard_test.cpp \ @@ -26,6 +27,7 @@ SOURCES += ../../testing/testingmain.cpp \ stl_add_test.cpp \ string_utils_test.cpp \ matrix_test.cpp \ - commands_queue_test.cpp + commands_queue_test.cpp \ + buffer_vector_test.cpp \ HEADERS += diff --git a/base/base_tests/buffer_vector_test.cpp b/base/base_tests/buffer_vector_test.cpp new file mode 100644 index 0000000000..9b3e6f2be6 --- /dev/null +++ b/base/base_tests/buffer_vector_test.cpp @@ -0,0 +1,99 @@ +#include "../SRC_FIRST.hpp" + +#include "../../testing/testing.hpp" + +#include "../buffer_vector.hpp" + + +namespace +{ + template + void CheckVector(TCont & cont, size_t count) + { + CHECK_EQUAL ( cont.size(), count, () ); + for (size_t i = 0; i < count; ++i) + CHECK_EQUAL ( cont[i], i, () ); + } +} + +UNIT_TEST(BufferVectorBounds) +{ + buffer_vector v; + + for (size_t i = 0; i < 5; ++i) + { + v.push_back(i); + CheckVector(v, i+1); + } + + v.resize(2); + CheckVector(v, 2); + + v.resize(3); + v[2] = 2; + CheckVector(v, 3); + + v.resize(4); + v[3] = 3; + CheckVector(v, 4); + + v.resize(1); + CheckVector(v, 1); + + v.resize(0); + CheckVector(v, 0); +} + +UNIT_TEST(BufferVectorSwap) +{ + typedef buffer_vector value_t; + buffer_vector v1, v2; + + for (size_t i = 0; i < 5; ++i) + { + v1.push_back(value_t()); + v2.push_back(value_t()); + } + + // check swap of vectors + value_t const * d1 = v1.data(); + value_t const * d2 = v2.data(); + + swap(v1, v2); + CHECK_EQUAL ( d1, v2.data(), () ); + CHECK_EQUAL ( d2, v1.data(), () ); + + // check swap in resized data + { + v1[0].push_back(666); + + // inner static buffer doesn't swap + int const * dd1 = v1[0].data(); + + v1.resize(1); + CHECK_EQUAL ( v1[0].size(), 1, () ); + CHECK_EQUAL ( v1[0][0], 666, () ); + CHECK_NOT_EQUAL ( dd1, v1[0].data(), () ); + + v1.resize(7); + CHECK_EQUAL ( v1[0].size(), 1, () ); + CHECK_EQUAL ( v1[0][0], 666, () ); + CHECK_NOT_EQUAL ( dd1, v1[0].data(), () ); + } + + { + for (size_t i = 0; i < 5; ++i) + v2[0].push_back(i); + + // inner dynamic buffer should be swapped + int const * dd2 = v2[0].data(); + + v2.resize(1); + CHECK_EQUAL ( v2[0].size(), 5, () ); + CHECK_EQUAL ( dd2, v2[0].data(), () ); + + v1.resize(7); + CHECK_EQUAL ( v2[0].size(), 5, () ); + CHECK_EQUAL ( dd2, v2[0].data(), () ); + } +} diff --git a/base/buffer_vector.hpp b/base/buffer_vector.hpp new file mode 100644 index 0000000000..fd4de51c52 --- /dev/null +++ b/base/buffer_vector.hpp @@ -0,0 +1,141 @@ +#pragma once + +#include "assert.hpp" + +#include "../std/array.hpp" +#include "../std/vector.hpp" + + +namespace detail +{ + template void swap_adl_inner(T & r1, T & r2) + { + swap(r1, r2); + } +} + +template class buffer_vector +{ + array m_static; + vector m_dynamic; + 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(); + } + } + +public: + typedef T value_type; + + buffer_vector() : m_size(0) {} + buffer_vector(size_t n) : m_size(0) + { + resize(n); + } + + void reserve(size_t n) + { + if (n > N) + m_dynamic.reserve(n); + } + + void resize(size_t n) + { + if (n > N) + { + m_dynamic.resize(n); + flush_to_dynamic(); + } + else + flush_to_static(n); + + m_size = n; + } + + void clear() + { + m_size = 0; + m_dynamic.clear(); + } + + 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; } + + T const & front() const + { + ASSERT ( !empty(), () ); + return (m_size > N ? m_dynamic.front() : m_static.front()); + } + T const & back() const + { + ASSERT ( !empty(), () ); + return (m_size > N ? m_dynamic.back() : m_static[m_size-1]); + } + + T const & operator[](size_t i) const + { + return (m_size > N ? m_dynamic[i] : m_static[i]); + } + T & operator[](size_t i) + { + return (m_size > N ? m_dynamic[i] : m_static[i]); + } + + void push_back(T const & t) + { + if (m_size < N) + m_static[m_size] = t; + else + { + flush_to_dynamic(); + m_dynamic.push_back(t); + } + + ++m_size; + } + + void swap(buffer_vector & rhs) + { + m_static.swap(rhs.m_static); + m_dynamic.swap(rhs.m_dynamic); + std::swap(m_size, rhs.m_size); + } +}; + +template +void swap(buffer_vector & r1, buffer_vector & r2) { r1.swap(r2); } diff --git a/base/stl_add.hpp b/base/stl_add.hpp index c2a3e6e88e..a17dd0e023 100644 --- a/base/stl_add.hpp +++ b/base/stl_add.hpp @@ -4,17 +4,15 @@ template class BackInsertFunctor { + ContainerT & m_Container; public: explicit BackInsertFunctor(ContainerT & container) : m_Container(container) { } - void operator() (typename ContainerT::value_type const & t) const { - m_Container.insert(m_Container.end(), t); + m_Container.push_back(t); } -private: - ContainerT & m_Container; }; template @@ -25,17 +23,15 @@ BackInsertFunctor MakeBackInsertFunctor(ContainerT & container) template class InsertFunctor { + ContainerT & m_Container; public: explicit InsertFunctor(ContainerT & container) : m_Container(container) { } - void operator() (typename ContainerT::value_type const & t) const { m_Container.insert(t); } -private: - ContainerT & m_Container; }; template diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 2094966e60..9ddbc87aff 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -5,6 +5,8 @@ #include "feature_visibility.hpp" #include "scales.hpp" +#include "../storage/defines.hpp" // just for file extensions + #include "../geometry/rect2d.hpp" #include "../coding/byte_stream.hpp" @@ -253,7 +255,8 @@ void FeatureBuilder1::Serialize(buffer_t & data) const namespace { - void CalcRect(vector const & points, m2::RectD & rect) + template + void CalcRect(TCont const & points, m2::RectD & rect) { for (size_t i = 0; i < points.size(); ++i) rect.Add(points[i]); @@ -564,6 +567,7 @@ void FeatureType::Deserialize(read_source_t & src) m_Points.clear(); m_Triangles.clear(); + m_InnerPoints.clear(); m_bHeader2Parsed = m_bPointsParsed = m_bTrianglesParsed = false; m_ptsSimpMask = 0; @@ -618,7 +622,8 @@ int FeatureType::GetScaleIndex(int scale, offsets_t const & offsets) namespace { - void Points2String(string & s, vector const & points) + template + void Points2String(string & s, TCont const & points) { for (size_t i = 0; i < points.size(); ++i) s += debug_print(points[i]) + " "; @@ -874,7 +879,7 @@ void FeatureType::ReadOffsets(ArrayByteSource & src, uint8_t mask, offsets_t & o } } -void FeatureType::ReadInnerPoints(ArrayByteSource & src, vector & points, uint8_t count) const +void FeatureType::ReadInnerPoints(ArrayByteSource & src, points_t & points, uint8_t count) const { src = ArrayByteSource(feature::LoadPointsSimple(src.Ptr(), count, points)); CalcRect(points, m_LimitRect); diff --git a/indexer/feature.hpp b/indexer/feature.hpp index 9c90faec78..053069c070 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -2,20 +2,18 @@ #include "cell_id.hpp" -#include "../storage/defines.hpp" // just for file extensions - #include "../geometry/point2d.hpp" #include "../geometry/rect2d.hpp" #include "../coding/file_container.hpp" #include "../base/base.hpp" +#include "../base/buffer_vector.hpp" #include "../std/string.hpp" -#include "../std/vector.hpp" -#include "../std/array.hpp" #include "../std/bind.hpp" + class ArrayByteSource; class FeatureBase; @@ -426,8 +424,10 @@ private: void ParseAll(int scale) const; - mutable vector m_InnerPoints; - mutable vector m_Points, m_Triangles; + mutable buffer_vector m_InnerPoints; + + typedef buffer_vector points_t; + mutable points_t m_Points, m_Triangles; FilesContainerR * m_cont; @@ -440,7 +440,7 @@ private: typedef array offsets_t; // should be synchronized with ARRAY_SIZE(g_arrScales) static void ReadOffsets(ArrayByteSource & src, uint8_t mask, offsets_t & offsets); - void ReadInnerPoints(ArrayByteSource & src, vector & points, uint8_t count) const; + void ReadInnerPoints(ArrayByteSource & src, points_t & points, uint8_t count) const; static int GetScaleIndex(int scale); static int GetScaleIndex(int scale, offsets_t const & offset); diff --git a/indexer/feature_impl.hpp b/indexer/feature_impl.hpp index bcac9155a1..47219bab17 100644 --- a/indexer/feature_impl.hpp +++ b/indexer/feature_impl.hpp @@ -51,13 +51,13 @@ namespace feature sink.Write(&buffer[0], count); } - class points_emitter + template class points_emitter { - vector & m_points; + TCont & m_points; int64_t m_id; public: - points_emitter(vector & points, uint32_t count) + points_emitter(TCont & points, uint32_t count) : m_points(points), m_id(0) { m_points.reserve(count); @@ -68,21 +68,21 @@ namespace feature } }; - inline void const * ReadPointsSimple( void const * p, size_t count, - vector & points) + template + void const * ReadPointsSimple(void const * p, size_t count, TCont & points) { - return ReadVarInt64Array(p, count, points_emitter(points, count)); + return ReadVarInt64Array(p, count, points_emitter(points, count)); } - template - void ReadPoints(vector & points, TSource & src) + template + void ReadPoints(TCont & points, TSource & src) { uint32_t const count = ReadVarUint(src); vector buffer(count); char * p = &buffer[0]; src.Read(p, count); - ReadVarInt64Array(p, p + count, points_emitter(points, count / 2)); + ReadVarInt64Array(p, p + count, points_emitter(points, count / 2)); } } @@ -108,8 +108,8 @@ namespace feature detail::WriteCells(cells, sink); } - inline void const * LoadPointsSimple( void const * p, size_t count, - vector & points) + template + void const * LoadPointsSimple(void const * p, size_t count, TCont & points) { ASSERT_GREATER ( count, 1, () ); void const * ret = detail::ReadPointsSimple(p, count, points); @@ -117,8 +117,8 @@ namespace feature return ret; } - template - void LoadPoints(vector & points, TSource & src) + template + void LoadPoints(TCont & points, TSource & src) { detail::ReadPoints(points, src); @@ -138,8 +138,8 @@ namespace feature detail::WriteCells(cells, sink); } - template - void LoadTriangles(vector & points, TSource & src) + template + void LoadTriangles(TCont & points, TSource & src) { detail::ReadPoints(points, src); diff --git a/indexer/indexer_tests/feature_routine.cpp b/indexer/indexer_tests/feature_routine.cpp index 4934420d55..85202d37cd 100644 --- a/indexer/indexer_tests/feature_routine.cpp +++ b/indexer/indexer_tests/feature_routine.cpp @@ -2,6 +2,8 @@ #include "feature_routine.hpp" +#include "../../storage/defines.hpp" // just for file extensions + #include "../feature_impl.hpp" #include "../../coding/file_writer.hpp"