summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorGeir Storli <geirst@yahoo-inc.com>2017-01-05 14:16:05 +0100
committerGeir Storli <geirst@yahoo-inc.com>2017-01-05 14:16:05 +0100
commite3c7468a6744d9f979bf98c3a7b74592dedf672a (patch)
tree7430fa2d40f83eeb72b1420d15153eaaf9990b3b /vespalib
parentc872abddea00836006c2fd402a6c2b6654d8a6b9 (diff)
Implement try_unreserve() on Array to reduce underlying memory buffer inplace.
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/array/array_test.cpp29
-rw-r--r--vespalib/src/vespa/vespalib/util/array.h6
-rw-r--r--vespalib/src/vespa/vespalib/util/array.hpp12
3 files changed, 47 insertions, 0 deletions
diff --git a/vespalib/src/tests/array/array_test.cpp b/vespalib/src/tests/array/array_test.cpp
index b7357512d89..13e46111bfb 100644
--- a/vespalib/src/tests/array/array_test.cpp
+++ b/vespalib/src/tests/array/array_test.cpp
@@ -320,4 +320,33 @@ TEST("test move assignment")
}
}
+struct UnreserveFixture {
+ Array<int> arr;
+ UnreserveFixture() : arr(1025, 7, alloc::Alloc::allocMMap(0))
+ {
+ EXPECT_EQUAL(1025u, arr.size());
+ EXPECT_EQUAL(2048u, arr.capacity());
+ }
+};
+
+TEST_F("require that try_unreserve() fails if wanted capacity >= current capacity", UnreserveFixture)
+{
+ EXPECT_FALSE(f.arr.try_unreserve(2048));
+}
+
+TEST_F("require that try_unreserve() fails if wanted capacity < current size", UnreserveFixture)
+{
+ EXPECT_FALSE(f.arr.try_unreserve(1024));
+}
+
+TEST_F("require that try_unreserve() succeedes if mmap can be shrinked", UnreserveFixture)
+{
+ int *oldPtr = &f.arr[0];
+ f.arr.resize(512);
+ EXPECT_TRUE(f.arr.try_unreserve(1023));
+ EXPECT_EQUAL(1024u, f.arr.capacity());
+ int *newPtr = &f.arr[0];
+ EXPECT_EQUAL(oldPtr, newPtr);
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/vespa/vespalib/util/array.h b/vespalib/src/vespa/vespalib/util/array.h
index 269bf67bc26..4ca09bd093a 100644
--- a/vespalib/src/vespa/vespalib/util/array.h
+++ b/vespalib/src/vespa/vespalib/util/array.h
@@ -106,6 +106,12 @@ public:
void resize(size_t n);
void assign(const_iterator begin_, const_iterator end_);
void reserve(size_t n);
+ /**
+ * Try to unreserve memory from the underlying memory buffer inplace down to the given limit.
+ * The existing memory buffer is unmodified up to the new size (no copying occurs).
+ * Returns true if it was possible to unreserve memory, false if not.
+ */
+ bool try_unreserve(size_t n);
void push_back(const T & v) { std::_Construct(push_back(), v); }
iterator push_back() { extend(size()+1); return array(_sz++); }
iterator push_back_fast() { return array(_sz++); }
diff --git a/vespalib/src/vespa/vespalib/util/array.hpp b/vespalib/src/vespa/vespalib/util/array.hpp
index dbdda73ad66..ec418d7d566 100644
--- a/vespalib/src/vespa/vespalib/util/array.hpp
+++ b/vespalib/src/vespa/vespalib/util/array.hpp
@@ -94,6 +94,18 @@ void Array<T>::reserve(size_t n) {
}
template <typename T>
+bool Array<T>::try_unreserve(size_t n)
+{
+ if (n >= capacity()) {
+ return false;
+ }
+ if (n < size()) {
+ return false;
+ }
+ return _array.resize_inplace(n * sizeof(T));
+}
+
+template <typename T>
void Array<T>::resize(size_t n)
{
if (n > capacity()) {