diff --git a/.clang-format b/.clang-format index b4bec3a..873b920 100644 --- a/.clang-format +++ b/.clang-format @@ -2,3 +2,6 @@ BasedOnStyle: Google AccessModifierOffset: -2 ColumnLimit: 160 IncludeBlocks: Preserve +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterRequiresInClause: true diff --git a/include/yk/stack.hpp b/include/yk/stack.hpp new file mode 100644 index 0000000..b209b68 --- /dev/null +++ b/include/yk/stack.hpp @@ -0,0 +1,158 @@ +#ifndef YK_STACK_HPP +#define YK_STACK_HPP + +#include "yk/allocator/concepts.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace yk { + +// stack with clear() +// also, defaults to std::vector instead of std::deque +template > +class stack : protected std::stack { + using base_stack = std::stack; + +public: + using typename base_stack::const_reference; + using typename base_stack::container_type; + using typename base_stack::reference; + using typename base_stack::size_type; + using typename base_stack::value_type; + + using base_stack::base_stack; + + using base_stack::empty; + using base_stack::push; + using base_stack::size; + using base_stack::top; + +#if __cpp_lib_containers_ranges >= 202202L + using base_stack::push_range; +#endif + + using base_stack::emplace; + using base_stack::pop; + + constexpr void swap(stack& other) noexcept(std::is_nothrow_swappable_v) { + using std::swap; + swap(c, other.c); + } + + // our addition + constexpr stack(std::initializer_list il) noexcept(noexcept(stack(il.begin(), il.end()))) : stack(il.begin(), il.end()) {} + + [[nodiscard]] constexpr size_type capacity() const noexcept + requires requires(Container c) { c.capacity(); } + { + return c.capacity(); + } + + constexpr void clear() noexcept(noexcept(c.clear())) + requires requires(Container c) { c.clear(); } + { + c.clear(); + } + + [[nodiscard]] constexpr size_type max_size() const noexcept { return c.max_size(); } + + constexpr void reserve(size_type n) + requires requires(Container c) { c.reserve(n); } + { + c.reserve(n); + } + + constexpr void shrink_to_fit() + requires requires(Container c) { c.shrink_to_fit(); } + { + c.shrink_to_fit(); + } + +protected: + using base_stack::c; + +public: + [[nodiscard]] friend constexpr bool operator==(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) == + static_cast(rhs))) { + return static_cast(lhs) == static_cast(rhs); + } + + [[nodiscard]] friend constexpr bool operator!=(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) != + static_cast(rhs))) { + return static_cast(lhs) != static_cast(rhs); + } + + [[nodiscard]] friend constexpr bool operator<(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) < + static_cast(rhs))) { + return static_cast(lhs) < static_cast(rhs); + } + + [[nodiscard]] friend constexpr bool operator<=(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) <= + static_cast(rhs))) { + return static_cast(lhs) <= static_cast(rhs); + } + + [[nodiscard]] friend constexpr bool operator>(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) > + static_cast(rhs))) { + return static_cast(lhs) > static_cast(rhs); + } + + [[nodiscard]] friend constexpr bool operator>=(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) >= + static_cast(rhs))) { + return static_cast(lhs) >= static_cast(rhs); + } + + [[nodiscard]] friend constexpr auto operator<=>(stack const& lhs, stack const& rhs) noexcept(noexcept(static_cast(lhs) <=> + static_cast(rhs))) + requires std::three_way_comparable + { + return static_cast(lhs) <=> static_cast(rhs); + } +}; + +template + requires (!xo::simple_allocator) +stack(Container) -> stack; + +template + requires (!xo::simple_allocator) && std::uses_allocator_v +stack(Container, Alloc) -> stack; + +#if __cpp_lib_adaptor_iterator_pair_constructor >= 202106L +// C++23 +template >> +stack(InputIt, InputIt, Alloc = Alloc()) -> stack, std::vector, Alloc>>; +#endif + +#if __cpp_lib_containers_ranges >= 202202L +// C++23 +template +stack(std::from_range_t, R&&) -> stack>; + +// C++23 +template +stack(std::from_range_t, R&&, Alloc) -> stack, std::vector, Alloc>>; +#endif + +template + requires std::is_swappable_v +void swap(stack& lhs, stack& rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} + +} // namespace yk + +namespace std { + +template +struct uses_allocator<::yk::stack, Alloc> : uses_allocator::type {}; + +} // namespace std + +#endif diff --git a/test/test.cpp b/test/test.cpp index 90fcdc8..f77188c 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,4 +1,5 @@ #include "yk/allocator/default_init_allocator.hpp" +#include "yk/stack.hpp" #include "yk/util/forward_like.hpp" #include "yk/util/pack_indexing.hpp" #include "yk/util/reverse.hpp" @@ -155,4 +156,18 @@ BOOST_AUTO_TEST_CASE(Allocator) { } } +BOOST_AUTO_TEST_CASE(Stack) { + yk::stack s{3, 1, 4, 1, 5}; + + s.shrink_to_fit(); + BOOST_TEST(s.capacity() == 5); + s.reserve(10); + BOOST_TEST(s.capacity() >= 10); + BOOST_TEST(s.capacity() <= s.max_size()); + + BOOST_TEST(!s.empty()); + s.clear(); + BOOST_TEST(s.empty()); +} + BOOST_AUTO_TEST_SUITE_END() // yk_util