diff --git a/.beman-tidy.yaml b/.beman-tidy.yaml index 7a0cc01..30b0ebf 100644 --- a/.beman-tidy.yaml +++ b/.beman-tidy.yaml @@ -7,3 +7,4 @@ disabled_rules: [] ignored_paths: - infra/ + - include/beman/optional/detail/stl_interfaces/ diff --git a/include/beman/inplace_vector/inplace_vector.hpp b/include/beman/inplace_vector/inplace_vector.hpp index 20ce557..e4b3560 100644 --- a/include/beman/inplace_vector/inplace_vector.hpp +++ b/include/beman/inplace_vector/inplace_vector.hpp @@ -4,6 +4,7 @@ #define BEMAN_INPLACE_VECTOR_INPLACE_VECTOR_HPP #include +#include #include // for rotate... #include @@ -327,18 +328,20 @@ struct inplace_vector_base : private storage::storage_for { return this->back(); } - template constexpr T *try_emplace_back(Args &&...args) { + template + constexpr beman::optional::optional try_emplace_back(Args &&...args) { if (size() == capacity()) [[unlikely]] - return nullptr; - return &unchecked_emplace_back(std::forward(args)...); + return beman::optional::nullopt; + return beman::optional::optional( + unchecked_emplace_back(std::forward(args)...)); } - constexpr T *try_push_back(const T &x) + constexpr beman::optional::optional try_push_back(const T &x) requires(std::constructible_from) { return try_emplace_back(x); } - constexpr T *try_push_back(T &&x) + constexpr beman::optional::optional try_push_back(T &&x) requires(std::constructible_from) { return try_emplace_back(std::forward(x)); diff --git a/include/beman/optional/CMakeLists.txt b/include/beman/optional/CMakeLists.txt new file mode 100644 index 0000000..a27526b --- /dev/null +++ b/include/beman/optional/CMakeLists.txt @@ -0,0 +1,15 @@ +# include/beman/optional/CMakeLists.txt -*-cmake-*- +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +target_sources( + beman.optional + PUBLIC + FILE_SET beman_optional_headers + TYPE HEADERS + FILES + optional.hpp + detail/iterator.hpp + detail/stl_interfaces/config.hpp + detail/stl_interfaces/fwd.hpp + detail/stl_interfaces/iterator_interface.hpp +) diff --git a/include/beman/optional/detail/iterator.hpp b/include/beman/optional/detail/iterator.hpp new file mode 100644 index 0000000..de11bc0 --- /dev/null +++ b/include/beman/optional/detail/iterator.hpp @@ -0,0 +1,71 @@ +// include/beman/optional/detail/iterator.hpp -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef BEMAN_OPTIONAL_DETAIL_ITERATOR_HPP +#define BEMAN_OPTIONAL_DETAIL_ITERATOR_HPP + +#include + +#include +#include + +namespace beman::optional::detail { + +// Forward declaration. +template struct contiguous_iterator; + +// Base class for contiguous iterator types with Boost stl_interfaces library. +// Current implementation based on P2727R4: std::iterator_interface. +template +using base_contiguous_iterator = stl_interfaces::iterator_interface< +#if !BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS + contiguous_iterator, // Required for P2727R4 to work with + // C++20/C++23. TODO: Do more + // experiments. +#endif + std::contiguous_iterator_tag, T>; + +// This is a minimal contiguous iterator. It uses stl_interfaces library from +// Boost (current implementation based on https://wg21.link/P2727R4). +// +// TODO: Change this to use the stl_interfaces library from Beman if/when +// available. +// +// @tparam T - The type of the elements the iterator points to. +// @tparam Container - The type of the container the iterator points to. This +// parameter exists solely so that different containers using this template can +// instantiate different types, even if the T parameter is the same. +template +struct contiguous_iterator : public base_contiguous_iterator { + // Alias for the base class. + using base_type = base_contiguous_iterator; + // Alias for types from the base class. + using typename base_type::difference_type; + using typename base_type::pointer; + using typename base_type::reference; + + // Default constructor. + constexpr contiguous_iterator() noexcept : m_current() {} + + // Pointer to iterator constructor. + constexpr contiguous_iterator(pointer it) noexcept : m_current(it) {} + + // As per P2727R4, for contiguous iterator we only need to provide operator*, + // operator+= and operator-. + constexpr reference operator*() const noexcept { return *m_current; } + constexpr auto &operator+=(difference_type pos) noexcept { + m_current += pos; + return *this; + } + constexpr difference_type + operator-(contiguous_iterator other) const noexcept { + return m_current - other.m_current; + } + +private: + T *m_current; +}; + +} // namespace beman::optional::detail + +#endif // BEMAN_OPTIONAL_DETAIL_ITERATOR_HPP diff --git a/include/beman/optional/detail/stl_interfaces/config.hpp b/include/beman/optional/detail/stl_interfaces/config.hpp new file mode 100644 index 0000000..8fa7633 --- /dev/null +++ b/include/beman/optional/detail/stl_interfaces/config.hpp @@ -0,0 +1,51 @@ +// include/beman/optional/detail/stl_interfaces/config.hpp -*-C++-*- + +// Copyright (C) 2020 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_CONFIG_HPP +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_CONFIG_HPP + +// Included for definition of __cpp_lib_concepts. +#include + +#if defined(__cpp_lib_concepts) && defined(__cpp_lib_ranges) && \ + !defined(BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_DISABLE_CONCEPTS) +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS 1 +#else +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS 0 +#endif + +#if defined(__cpp_explicit_this_parameter) && \ + BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS && \ + !defined(BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_DISABLE_DEDUCED_THIS) +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS 1 +#else +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS 0 +#endif + +// The inline namespaces v1, v2, and v3 represent C++14, C++20, and C++23 and +// later, respectively. v1 is inline for standards before C++20, and v2 is +// inline for C++20 and later. Note that this only applies to code for which +// multiple vI namespace alternatives exist. For example, some instances of +// the v1 namespace may still be inline, if there is no v2 version of its +// contents. +#if !BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS && \ + !BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V1 inline namespace v1 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3 +#elif BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS && \ + !BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_DEDUCED_THIS +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V2 inline namespace v2 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V3 namespace v3 +#else +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V1 namespace v1 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V2 namespace v2 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V3 inline namespace v3 +#endif + +#endif diff --git a/include/beman/optional/detail/stl_interfaces/fwd.hpp b/include/beman/optional/detail/stl_interfaces/fwd.hpp new file mode 100644 index 0000000..14a7647 --- /dev/null +++ b/include/beman/optional/detail/stl_interfaces/fwd.hpp @@ -0,0 +1,85 @@ +// include/beman/optional/detail/stl_interfaces/fwd.hpp -*-C++-*- + +// Copyright (C) 2019 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_FWD_HPP +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_FWD_HPP + +#include + +#if BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS +#include +#endif +#if defined(__cpp_lib_three_way_comparison) +#include +#endif + +#ifndef BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_DOXYGEN + +#if defined(_MSC_VER) || defined(__GNUC__) && __GNUC__ < 8 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NO_HIDDEN_FRIEND_CONSTEXPR +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR +#else +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR constexpr +#endif + +#if defined(__GNUC__) && __GNUC__ < 9 +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_CONCEPT concept bool +#else +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_CONCEPT concept +#endif + +#endif + +namespace beman::optional::detail { +namespace stl_interfaces { + +/** An enumeration used to indicate whether the underlying data have a + contiguous or discontiguous layout when instantiating `view_interface` + and `sequence_container_interface`. */ +enum class element_layout : bool { discontiguous = false, contiguous = true }; + +BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_NAMESPACE_V1 { + + namespace v1_dtl { + template using void_t = void; + + template + using iter_difference_t = + typename std::iterator_traits::difference_type; + + template struct iterator; + template + struct iterator().begin())>> { + using type = decltype(std::declval().begin()); + }; + template using iterator_t = typename iterator::type; + + template struct sentinel; + template + struct sentinel().end())>> { + using type = decltype(std::declval().end()); + }; + template using sentinel_t = typename sentinel::type; + + template + using range_difference_t = iter_difference_t>; + + template + using common_range = std::is_same, sentinel_t>; + + template + struct decrementable_sentinel : std::false_type {}; + template + struct decrementable_sentinel< + Range, void_t &>())>> + : std::true_type {}; + } // namespace v1_dtl +} +} // namespace stl_interfaces +} // namespace beman::optional::detail + +#endif diff --git a/include/beman/optional/detail/stl_interfaces/iterator_interface.hpp b/include/beman/optional/detail/stl_interfaces/iterator_interface.hpp new file mode 100644 index 0000000..deda3f6 --- /dev/null +++ b/include/beman/optional/detail/stl_interfaces/iterator_interface.hpp @@ -0,0 +1,1056 @@ +// include/beman/optional/detail/stl_interfaces/iterator_interface.hpp -*-C++-*- + +// Copyright (C) 2019 T. Zachary Laine +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_ITERATOR_INTERFACE_HPP +#define BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_ITERATOR_INTERFACE_HPP + +#include + +#include +#include +#if defined(__cpp_lib_three_way_comparison) +#include +#endif + +namespace beman::optional::detail { +namespace stl_interfaces { + +/** A type for granting access to the private members of an iterator + derived from `iterator_interface`. */ +struct access { +#ifndef BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_DOXYGEN + + template + static constexpr auto base(D &d) noexcept -> decltype(d.base_reference()) { + return d.base_reference(); + } + template + static constexpr auto base(const D &d) noexcept + -> decltype(d.base_reference()) { + return d.base_reference(); + } + +#endif +}; + +/** The return type of `operator->()` in a proxy iterator. + + This template is used as the default `Pointer` template parameter in + the `proxy_iterator_interface` template alias. Note that the use of + this template implies a copy or move of the underlying object of type + `T`. */ +template +#if defined(BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_DOXYGEN) || \ + BEMAN_OPTIONAL_DETAIL_STL_INTERFACES_USE_CONCEPTS +// clang-format off + requires std::is_object_v +#endif + struct proxy_arrow_result +// clang-format on +{ + constexpr proxy_arrow_result(const T &value) noexcept(noexcept(T(value))) + : value_(value) {} + constexpr proxy_arrow_result(T &&value) noexcept( + noexcept(T(std::move(value)))) + : value_(std::move(value)) {} + + constexpr const T *operator->() const noexcept { return &value_; } + constexpr T *operator->() noexcept { return &value_; } + +private: + T value_; +}; + +namespace detail { +template +auto make_pointer(T &&value, + std::enable_if_t::value && + std::is_reference::value, + int> = 0) + -> decltype(std::addressof(value)) { + return std::addressof(value); +} + +template +auto make_pointer(T &&value, + std::enable_if_t::value && + !std::is_same::value && + std::is_reference::value, + int> = 0) { + return Pointer(std::forward(value)); +} + +template struct pointer { + using type = Pointer; +}; +template struct pointer { + using type = void; +}; +template +using pointer_t = typename pointer::type; + +template +using interoperable = + std::integral_constant::value || + std::is_convertible::value)>; + +template +using common_t = std::conditional_t::value, U, T>; + +template +using use_base = decltype(access::base(std::declval())); + +template using void_t = void; + +template class Template, + typename... Args> +struct detector : std::false_type {}; + +template