1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/vector.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/assert.hpp" |
12 | #include "duckdb/common/typedefs.hpp" |
13 | #include "duckdb/common/likely.hpp" |
14 | #include "duckdb/common/exception.hpp" |
15 | #include "duckdb/common/memory_safety.hpp" |
16 | #include <vector> |
17 | |
18 | namespace duckdb { |
19 | |
20 | template <class _Tp, bool SAFE = true> |
21 | class vector : public std::vector<_Tp, std::allocator<_Tp>> { |
22 | public: |
23 | using original = std::vector<_Tp, std::allocator<_Tp>>; |
24 | using original::original; |
25 | using size_type = typename original::size_type; |
26 | using const_reference = typename original::const_reference; |
27 | using reference = typename original::reference; |
28 | |
29 | private: |
30 | static inline void AssertIndexInBounds(idx_t index, idx_t size) { |
31 | #if defined(DUCKDB_DEBUG_NO_SAFETY) || defined(DUCKDB_CLANG_TIDY) |
32 | return; |
33 | #else |
34 | if (DUCKDB_UNLIKELY(index >= size)) { |
35 | throw InternalException("Attempted to access index %ld within vector of size %ld" , index, size); |
36 | } |
37 | #endif |
38 | } |
39 | |
40 | public: |
41 | #ifdef DUCKDB_CLANG_TIDY |
42 | // This is necessary to tell clang-tidy that it reinitializes the variable after a move |
43 | [[clang::reinitializes]] |
44 | #endif |
45 | inline void |
46 | clear() noexcept { |
47 | original::clear(); |
48 | } |
49 | |
50 | // Because we create the other constructor, the implicitly created constructor |
51 | // gets deleted, so we have to be explicit |
52 | vector() = default; |
53 | vector(original &&other) : original(std::move(other)) { |
54 | } |
55 | template <bool _SAFE> |
56 | vector(vector<_Tp, _SAFE> &&other) : original(std::move(other)) { |
57 | } |
58 | |
59 | template <bool _SAFE = false> |
60 | inline typename original::reference get(typename original::size_type __n) { |
61 | if (MemorySafety<_SAFE>::enabled) { |
62 | AssertIndexInBounds(index: __n, size: original::size()); |
63 | } |
64 | return original::operator[](__n); |
65 | } |
66 | |
67 | template <bool _SAFE = false> |
68 | inline typename original::const_reference get(typename original::size_type __n) const { |
69 | if (MemorySafety<_SAFE>::enabled) { |
70 | AssertIndexInBounds(index: __n, size: original::size()); |
71 | } |
72 | return original::operator[](__n); |
73 | } |
74 | |
75 | typename original::reference operator[](typename original::size_type __n) { |
76 | return get<SAFE>(__n); |
77 | } |
78 | typename original::const_reference operator[](typename original::size_type __n) const { |
79 | return get<SAFE>(__n); |
80 | } |
81 | |
82 | typename original::reference front() { |
83 | return get<SAFE>(0); |
84 | } |
85 | |
86 | typename original::const_reference front() const { |
87 | return get<SAFE>(0); |
88 | } |
89 | |
90 | typename original::reference back() { |
91 | if (original::empty()) { |
92 | throw InternalException("'back' called on an empty vector!" ); |
93 | } |
94 | return get<SAFE>(original::size() - 1); |
95 | } |
96 | |
97 | typename original::const_reference back() const { |
98 | if (original::empty()) { |
99 | throw InternalException("'back' called on an empty vector!" ); |
100 | } |
101 | return get<SAFE>(original::size() - 1); |
102 | } |
103 | }; |
104 | |
105 | template <typename T> |
106 | using unsafe_vector = vector<T, false>; |
107 | |
108 | } // namespace duckdb |
109 | |