aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/chunked-vector.hh68
-rw-r--r--src/libutil/types.hh59
2 files changed, 68 insertions, 59 deletions
diff --git a/src/libutil/chunked-vector.hh b/src/libutil/chunked-vector.hh
new file mode 100644
index 000000000..f15af9cd7
--- /dev/null
+++ b/src/libutil/chunked-vector.hh
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <bits/stdint-uintn.h>
+#include <cstdlib>
+#include <vector>
+#include <limits>
+
+namespace nix {
+
+/* Provides an indexable container like vector<> with memory overhead
+ guarantees like list<> by allocating storage in chunks of ChunkSize
+ elements instead of using a contiguous memory allocation like vector<>
+ does. Not using a single vector that is resized reduces memory overhead
+ on large data sets by on average (growth factor)/2, mostly
+ eliminates copies within the vector during resizing, and provides stable
+ references to its elements. */
+template<typename T, size_t ChunkSize>
+class ChunkedVector {
+private:
+ uint32_t size_ = 0;
+ std::vector<std::vector<T>> chunks;
+
+ /* keep this out of the ::add hot path */
+ [[gnu::noinline]]
+ auto & addChunk()
+ {
+ if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize)
+ abort();
+ chunks.emplace_back();
+ chunks.back().reserve(ChunkSize);
+ return chunks.back();
+ }
+
+public:
+ ChunkedVector(uint32_t reserve)
+ {
+ chunks.reserve(reserve);
+ addChunk();
+ }
+
+ uint32_t size() const { return size_; }
+
+ std::pair<T &, uint32_t> add(T value)
+ {
+ const auto idx = size_++;
+ auto & chunk = [&] () -> auto & {
+ if (auto & back = chunks.back(); back.size() < ChunkSize)
+ return back;
+ return addChunk();
+ }();
+ auto & result = chunk.emplace_back(std::move(value));
+ return {result, idx};
+ }
+
+ const T & operator[](uint32_t idx) const
+ {
+ return chunks[idx / ChunkSize][idx % ChunkSize];
+ }
+
+ template<typename Fn>
+ void forEach(Fn fn) const
+ {
+ for (const auto & c : chunks)
+ for (const auto & e : c)
+ fn(e);
+ }
+};
+}
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index bd1dd8bee..6bcbd7e1d 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -103,63 +103,4 @@ public:
Ptr operator->() const { return Ptr(**this); }
};
-/* Provides an indexable container like vector<> with memory overhead
- guarantees like list<> by allocating storage in chunks of ChunkSize
- elements instead of using a contiguous memory allocation like vector<>
- does. Not using a single vector that is resized reduces memory overhead
- on large data sets by on average (growth factor)/2, mostly
- eliminates copies within the vector during resizing, and provides stable
- references to its elements. */
-template<typename T, size_t ChunkSize>
-class ChunkedVector {
-private:
- uint32_t size_ = 0;
- std::vector<std::vector<T>> chunks;
-
- /* keep this out of the ::add hot path */
- [[gnu::noinline]]
- auto & addChunk()
- {
- if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize)
- abort();
- chunks.emplace_back();
- chunks.back().reserve(ChunkSize);
- return chunks.back();
- }
-
-public:
- ChunkedVector(uint32_t reserve)
- {
- chunks.reserve(reserve);
- addChunk();
- }
-
- uint32_t size() const { return size_; }
-
- std::pair<T &, uint32_t> add(T value)
- {
- const auto idx = size_++;
- auto & chunk = [&] () -> auto & {
- if (auto & back = chunks.back(); back.size() < ChunkSize)
- return back;
- return addChunk();
- }();
- auto & result = chunk.emplace_back(std::move(value));
- return {result, idx};
- }
-
- const T & operator[](uint32_t idx) const
- {
- return chunks[idx / ChunkSize][idx % ChunkSize];
- }
-
- template<typename Fn>
- void forEach(Fn fn) const
- {
- for (const auto & c : chunks)
- for (const auto & e : c)
- fn(e);
- }
-};
-
}