/
immovable_vector.h
160 lines (136 loc) · 4.47 KB
/
immovable_vector.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
* Copyright (c) 2021 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_DETAIL_IMMOVABLE_VECTOR_H_
#define CPPSORT_DETAIL_IMMOVABLE_VECTOR_H_
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cstddef>
#include <new>
#include <utility>
#include <cpp-sort/utility/iter_move.h>
#include "config.h"
#include "memory.h"
namespace cppsort
{
namespace detail
{
////////////////////////////////////////////////////////////
// Immovable vector
//
// Lightweight class similar to std::vector, but with a few
// key differences: it allocates a buffer sufficient to store
// a given number of elements during construction, and it can
// not be moved. While its original goal was to provide an
// std::vector-like class for immovable types, it is also
// through the library as a light contiguous collection when
// the number of elements to allocate is already known at
// construction time.
template<typename T>
class immovable_vector
{
public:
// Make the collection immovable
immovable_vector(const immovable_vector&) = delete;
immovable_vector(immovable_vector&&) = delete;
immovable_vector& operator=(const immovable_vector&) = delete;
immovable_vector& operator=(immovable_vector&&) = delete;
////////////////////////////////////////////////////////////
// Construction
explicit immovable_vector(std::ptrdiff_t n):
capacity_(n),
memory_(
static_cast<T*>(::operator new(n * sizeof(T)))
),
end_(memory_)
{}
////////////////////////////////////////////////////////////
// Destruction
~immovable_vector()
{
// Destroy the constructed elements
detail::destroy(memory_, end_);
// Free the allocated memory
#ifdef __cpp_sized_deallocation
::operator delete(memory_, capacity_ * sizeof(T));
#else
::operator delete(memory_);
#endif
}
////////////////////////////////////////////////////////////
// Element access
auto operator[](std::ptrdiff_t pos)
-> T&
{
CPPSORT_ASSERT(pos <= end_ - memory_);
return memory_[pos];
}
auto front()
-> T&
{
CPPSORT_ASSERT(memory_ != end_);
return *memory_;
}
auto back()
-> T&
{
CPPSORT_ASSERT(end_ - memory_ > 0);
return *(end_ - 1);
}
////////////////////////////////////////////////////////////
// Iterators
auto begin()
-> T*
{
return memory_;
}
auto end()
-> T*
{
return end_;
}
////////////////////////////////////////////////////////////
// Modifiers
auto clear() noexcept
-> void
{
// Destroy the constructed elements
detail::destroy(memory_, end_);
// Ensure the new size is zero
end_ = memory_;
}
template<typename... Args>
auto emplace_back(Args&&... args)
-> void
{
CPPSORT_ASSERT(end_ - memory_ < capacity_);
::new(end_) T(std::forward<Args>(args)...);
++end_;
}
template<typename Iterator>
auto insert_back(Iterator first, Iterator last)
-> void
{
auto writer = end_;
try {
for (; first != last; ++first) {
using utility::iter_move;
::new(writer) T(iter_move(first));
++writer;
}
} catch (...) {
// Cleanup
detail::destroy(end_, writer);
throw;
}
end_ = writer;
}
private:
std::ptrdiff_t capacity_;
T* memory_;
T* end_;
};
}}
#endif // CPPSORT_DETAIL_IMMOVABLE_VECTOR_H_