numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
bidirectional_vector.h
Go to the documentation of this file.
1/*
2 * Copyright 2021 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <cstddef>
23#include <deque>
24#include <limits>
25
26#include <fmt/format.h> // IWYU pragma: keep
27
32
33namespace num_collect::util {
34
46template <typename Value, typename Container = std::deque<Value>>
48public:
50 using value_type = Value;
51
53 using container_type = Container;
54
59
68
74 [[nodiscard]] auto container() const noexcept -> const container_type& {
75 return container_;
76 }
77
83 [[nodiscard]] auto empty() const noexcept -> bool {
84 return container_.empty();
85 }
86
92 [[nodiscard]] auto min_index() const noexcept -> index_type {
93 return origin_index_;
94 }
95
101 [[nodiscard]] auto max_index() const noexcept -> index_type {
102 return origin_index_ + static_cast<index_type>(container_.size()) - 1;
103 }
104
113 [[nodiscard]] auto at(index_type index) const -> const value_type& {
114 return container_[container_index(index)];
115 }
116
125 [[nodiscard]] auto at(index_type index) -> value_type& {
126 return container_[container_index(index)];
127 }
128
137 [[nodiscard]] auto operator[](index_type index) const -> const value_type& {
138 return container_[unsafe_container_index(index)];
139 }
140
149 [[nodiscard]] auto operator[](index_type index) -> value_type& {
150 return container_[unsafe_container_index(index)];
151 }
152
159 [[nodiscard]] auto get_or_prepare(index_type index) -> value_type& {
160 prepare_for(index);
161 return container_[unsafe_container_index(index)];
162 }
163
172 const value_type& value = value_type()) {
173 const index_type current_min_index = this->min_index();
174 const index_type current_max_index = this->max_index();
175
176 if (max_index < current_min_index || current_max_index < min_index) {
178 const auto next_size =
179 static_cast<std::size_t>(max_index - min_index + 1);
180 container_.resize(next_size);
181 for (auto& elem : container_) {
182 elem = value;
183 }
184 return;
185 }
186
187 if (min_index < current_min_index) {
188 const auto num_added =
189 static_cast<std::size_t>(current_min_index - min_index);
190 container_.insert(container_.begin(), num_added, value);
191 } else if (min_index > current_min_index) {
192 const index_type num_erased = min_index - current_min_index;
193 container_.erase(
194 container_.begin(), container_.begin() + num_erased);
195 }
197
198 if (max_index > current_max_index) {
199 const auto num_added =
200 static_cast<std::size_t>(max_index - current_max_index);
201 container_.insert(container_.end(), num_added, value);
202 } else if (max_index < current_max_index) {
203 const index_type num_erased = current_max_index - max_index;
204 container_.erase(container_.end() - num_erased, container_.end());
205 }
206 }
207
213 void push_front(const value_type& value) {
215 origin_index_ > std::numeric_limits<index_type>::min());
216 container_.push_front(value);
218 }
219
225 void push_back(const value_type& value) { container_.push_back(value); }
226
234 origin_index_ += offset;
235 }
236
237private:
240
243
250 [[nodiscard]] auto container_index(index_type index) const -> std::size_t {
251 if (index < origin_index_) {
252 throw_out_of_range(index);
253 }
254 const auto result = static_cast<std::size_t>(index - origin_index_);
255 if (result >= container_.size()) {
256 throw_out_of_range(index);
257 }
258 return result;
259 }
260
267 [[nodiscard]] auto unsafe_container_index(index_type index) const noexcept
268 -> std::size_t {
269 return static_cast<std::size_t>(index - origin_index_);
270 }
271
277 [[noreturn]] void throw_out_of_range(index_type index) const {
279 fmt::format("Index out of range (index: {}, range: [{}, {}])",
280 index, min_index(), max_index()));
281 }
282
289 if (container_.empty()) {
290 origin_index_ = index;
291 container_.push_back(value_type());
292 return;
293 }
294
295 index_type next_min = min_index();
296 index_type next_max = max_index();
297 bool should_resize = false;
298 if (next_min > index) {
299 next_min = index;
300 should_resize = true;
301 }
302 if (next_max < index) {
303 next_max = index;
304 should_resize = true;
305 }
306 if (should_resize) {
307 resize(next_min, next_max);
308 }
309 }
310
317 [[nodiscard]] auto is_safe_offset(index_type offset) const noexcept
318 -> bool {
319 if (offset < 0) {
320 return origin_index_ >=
321 std::numeric_limits<index_type>::min() - offset;
322 }
323 return max_index() <= std::numeric_limits<index_type>::max() - offset;
324 }
325};
326
327} // namespace num_collect::util
Definition of assertion macros.
#define NUM_COLLECT_ASSERT(CONDITION)
Macro to check whether a condition is satisfied.
Definition assert.h:66
Class of exception on invalid arguments.
Definition exception.h:85
Class to save data in a sequence which can be extended even toward negative direction.
void throw_out_of_range(index_type index) const
Throw exception for indices out of range.
auto is_safe_offset(index_type offset) const noexcept -> bool
Check whether the given offset is safe to move.
auto at(index_type index) -> value_type &
Access a value with checks.
auto operator[](index_type index) -> value_type &
Access a value without checks.
bidirectional_vector()=default
Constructor.
auto operator[](index_type index) const -> const value_type &
Access a value without checks.
void resize(index_type min_index, index_type max_index, const value_type &value=value_type())
Change the position of this object.
container_type container_
Internal container.
auto max_index() const noexcept -> index_type
Get the maximum index.
auto container() const noexcept -> const container_type &
Get the internal container.
bidirectional_vector(container_type container, index_type origin_index)
Constructor.
auto min_index() const noexcept -> index_type
Get the minimum index. (Equal to the index of the origin.)
auto get_or_prepare(index_type index) -> value_type &
Access a value preparing it if needed.
void prepare_for(index_type index)
Prepare space for an index.
auto at(index_type index) const -> const value_type &
Access a value with checks.
Container container_type
Type of the internal container.
auto empty() const noexcept -> bool
Check whether this object is empty.
void push_front(const value_type &value)
Add a value to the beginning.
auto unsafe_container_index(index_type index) const noexcept -> std::size_t
Calculate the index in the container without checks.
auto container_index(index_type index) const -> std::size_t
Calculate the index in the container with checks.
void push_back(const value_type &value)
Add a value to the end.
void move_position(index_type offset)
Move the position of this object.
Definition of exceptions.
Definition of index_type type.
Definition of macros for logging.
#define NUM_COLLECT_LOG_AND_THROW(EXCEPTION_TYPE,...)
Write an error log and throw an exception for an error.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
Namespace of utilities.
Definition assert.h:30
STL namespace.