diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ddcdf989..448c5219 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,6 +46,7 @@ add_mp_units_module( include/mp-units/ext/algorithm.h include/mp-units/ext/contracts.h include/mp-units/ext/fixed_string.h + include/mp-units/ext/inplace_vector.h include/mp-units/ext/prime.h include/mp-units/ext/type_name.h include/mp-units/ext/type_traits.h diff --git a/src/core/include/mp-units/ext/inplace_vector.h b/src/core/include/mp-units/ext/inplace_vector.h new file mode 100644 index 00000000..58970e5f --- /dev/null +++ b/src/core/include/mp-units/ext/inplace_vector.h @@ -0,0 +1,137 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Very simplified implementation of std::inplace_vector +// To be replaced with: +// P0843: std::inplace_vector + +#include // IWYU pragma: keep + +#ifndef MP_UNITS_IN_MODULE_INTERFACE +#include +#include +#include +#include +#endif + +// NOLINTBEGIN(*-avoid-c-arrays) +#pragma once + +namespace mp_units::detail { +template +class inplace_vector { +public: + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + constexpr inplace_vector() noexcept = default; + + // iterators + constexpr iterator begin() noexcept { return data(); } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr iterator end() noexcept { return begin() + size(); } + constexpr const_iterator end() const noexcept { return begin() + size(); } + constexpr reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + constexpr reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return cbegin() + size(); } + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); } + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); } + + [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }; + [[nodiscard]] constexpr size_type size() const noexcept { return size_; } + [[nodiscard]] static constexpr size_type max_size() noexcept { return N; } + [[nodiscard]] static constexpr size_type capacity() noexcept { return N; } + + // element access + constexpr reference operator[](size_type n) { return data_[n]; } + constexpr const_reference operator[](size_type n) const { return data_[n]; } + constexpr reference front() { return *data(); } + constexpr const_reference front() const { return *data(); } + constexpr reference back() { return *(data() + size() - 1); } + constexpr const_reference back() const { return *(data() + size() - 1); } + + // data access + constexpr T* data() noexcept { return data_; } + constexpr const T* data() const noexcept { return data_; } + + constexpr reference push_back(const T& v) + requires std::constructible_from + { + return emplace_back(v); + } + + constexpr reference push_back(T&& v) + requires std::constructible_from + { + return emplace_back(std::forward(v)); + } + + template + requires(std::constructible_from) + constexpr T& unchecked_emplace_back(Args&&... args) + { + std::construct_at(end(), std::forward(args)...); + ++size_; + return back(); + } + + template + requires(std::constructible_from) + constexpr T* try_emplace_back(Args&&... args) + { + if (size() == capacity()) return nullptr; + return &unchecked_emplace_back(std::forward(args)...); + } + + template + requires std::constructible_from + constexpr reference emplace_back(Args&&... args) + { + MP_UNITS_EXPECTS(size() < capacity()); + auto ptr = try_emplace_back(std::forward(args)...); +#if MP_UNITS_HOSTED + if (!ptr) throw std::runtime_error("not enough capacity"); +#endif + return *ptr; + } + +private: + T data_[N]; + size_type size_ = 0; +}; + +} // namespace mp_units::detail + +// NOLINTEND(*-avoid-c-arrays)