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
18namespace duckdb {
19
20template <class _Tp, bool SAFE = true>
21class vector : public std::vector<_Tp, std::allocator<_Tp>> {
22public:
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
29private:
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
40public:
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
105template <typename T>
106using unsafe_vector = vector<T, false>;
107
108} // namespace duckdb
109