diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/boost/libs/stl_interfaces | |
parent | Initial commit. (diff) | |
download | ceph-upstream/18.2.2.tar.xz ceph-upstream/18.2.2.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/stl_interfaces')
34 files changed, 7042 insertions, 0 deletions
diff --git a/src/boost/libs/stl_interfaces/CMakeLists.txt b/src/boost/libs/stl_interfaces/CMakeLists.txt new file mode 100644 index 000000000..f8a156671 --- /dev/null +++ b/src/boost/libs/stl_interfaces/CMakeLists.txt @@ -0,0 +1,107 @@ +if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + +# Generated by `boostdep --cmake stl_interfaces` +# Copyright 2020, 2021 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(boost_stl_interfaces VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +add_library(boost_stl_interfaces INTERFACE) +add_library(Boost::stl_interfaces ALIAS boost_stl_interfaces) + +target_include_directories(boost_stl_interfaces INTERFACE include) + +target_link_libraries(boost_stl_interfaces + INTERFACE + Boost::assert + Boost::config +) + +target_compile_features(boost_stl_interfaces INTERFACE cxx_std_14) + +else() + +# 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) +cmake_minimum_required(VERSION 3.5) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +project(stl_interfaces) + +################################################## +# C++ standard version selection +################################################## +set(CXX_STD 14 CACHE STRING "Set to X to enable C++X builds.") +message("-- Using -std=c++${CXX_STD}") + + +################################################## +# Sanitizers +################################################## +set(USE_ASAN false CACHE BOOL "Set to true to enable -fsanitize=address when building tests.") +set(USE_UBSAN false CACHE BOOL "Set to true to enable -fsanitize=undefined when building tests.") +if (USE_ASAN AND USE_UBSAN) + message(FATAL_ERROR "USE_ASAN and USE_UBSAN must not be enabled at the same time") +elseif (USE_ASAN) + set(compile_flags -fsanitize=address) + set(link_flags -fsanitize=address) + message("-- Using -fsanitize=address") +elseif (USE_UBSAN) + set(compile_flags -fsanitize=undefined) + set(link_flags -fsanitize=undefined) + message("-- Using -fsanitize=undefined") +endif() + + +################################################## +# Code coverage +################################################## +if (UNIX) + set(BUILD_COVERAGE false CACHE BOOL "Set to true to enable code coverage when building tests. Only Linux and Mac are supported.") + if (BUILD_COVERAGE) + message("-- Building for code coverage; disabling any sanitizers") + if (APPLE) + set(compile_flags -fprofile-arcs -ftest-coverage) + set(CMAKE_BUILD_TYPE Debug) + set(link_flags --coverage) + else () + set(compile_flags --coverage) + set(CMAKE_BUILD_TYPE Debug) + set(link_flags --coverage) + endif () + endif () +endif () + + +################################################## +# Dependencies +################################################## +set(boost_components) +include(dependencies) + +################################################## +# stl_interfaces library +################################################## +add_library(stl_interfaces INTERFACE) + +target_include_directories(stl_interfaces INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(stl_interfaces INTERFACE boost) +if (link_flags) + target_link_libraries(stl_interfaces INTERFACE ${link_flags}) + target_compile_options(stl_interfaces INTERFACE ${compile_flags}) +endif () +if (NOT MSVC) + target_compile_options(stl_interfaces INTERFACE -Wall) +endif () + + +add_subdirectory(test) +add_subdirectory(example) + +endif() diff --git a/src/boost/libs/stl_interfaces/LICENSE_1_0.txt b/src/boost/libs/stl_interfaces/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/src/boost/libs/stl_interfaces/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/boost/libs/stl_interfaces/README.md b/src/boost/libs/stl_interfaces/README.md new file mode 100644 index 000000000..340ea5923 --- /dev/null +++ b/src/boost/libs/stl_interfaces/README.md @@ -0,0 +1,199 @@ +# stl_interfaces + +An updated C++20-friendly version of the `iterator_facade` and +`iterator_adaptor` parts of Boost.Iterator (now called `iterator_interface`); +a pre-C++20 version of C++20's `view_interface`; and a new template called +`container_interface`, meant to aid the creation of new containers; all +targeting standardization. This library requires at least C++14. + +For the iterator portion -- if you need to write an iterator, `iterator_interface` turns this: + +```c++ + struct repeated_chars_iterator + { + using value_type = char; + using difference_type = std::ptrdiff_t; + using pointer = char const *; + using reference = char const; + using iterator_category = std::random_access_iterator_tag; + + constexpr repeated_chars_iterator() noexcept : + first_(nullptr), + size_(0), + n_(0) + {} + constexpr repeated_chars_iterator( + char const * first, + difference_type size, + difference_type n) noexcept : + first_(first), + size_(size), + n_(n) + {} + + constexpr reference operator*() const noexcept + { + return first_[n_ % size_]; + } + + constexpr value_type operator[](difference_type n) const noexcept + { + return first_[(n_ + n) % size_]; + } + + constexpr repeated_chars_iterator & operator++() noexcept + { + ++n_; + return *this; + } + constexpr repeated_chars_iterator operator++(int)noexcept + { + repeated_chars_iterator retval = *this; + ++*this; + return retval; + } + constexpr repeated_chars_iterator & operator+=(difference_type n) noexcept + { + n_ += n; + return *this; + } + + constexpr repeated_chars_iterator & operator--() noexcept + { + --n_; + return *this; + } + constexpr repeated_chars_iterator operator--(int)noexcept + { + repeated_chars_iterator retval = *this; + --*this; + return retval; + } + constexpr repeated_chars_iterator & operator-=(difference_type n) noexcept + { + n_ -= n; + return *this; + } + + friend constexpr bool operator==( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return lhs.first_ == rhs.first_ && lhs.n_ == rhs.n_; + } + friend constexpr bool operator!=( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return !(lhs == rhs); + } + friend constexpr bool operator<( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return lhs.first_ == rhs.first_ && lhs.n_ < rhs.n_; + } + friend constexpr bool operator<=( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return lhs == rhs || lhs < rhs; + } + friend constexpr bool operator>( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return rhs < lhs; + } + friend constexpr bool operator>=( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return rhs <= lhs; + } + + friend constexpr repeated_chars_iterator + operator+(repeated_chars_iterator lhs, difference_type rhs) noexcept + { + return lhs += rhs; + } + friend constexpr repeated_chars_iterator + operator+(difference_type lhs, repeated_chars_iterator rhs) noexcept + { + return rhs += lhs; + } + friend constexpr repeated_chars_iterator + operator-(repeated_chars_iterator lhs, difference_type rhs) noexcept + { + return lhs -= rhs; + } + friend constexpr difference_type operator-( + repeated_chars_iterator lhs, repeated_chars_iterator rhs) noexcept + { + return lhs.n_ - rhs.n_; + } + + private: + char const * first_; + difference_type size_; + difference_type n_; + }; +``` + +into this: + +```c++ +struct repeated_chars_iterator : boost::stl_interfaces::iterator_interface< + repeated_chars_iterator, + std::random_access_iterator_tag, + char, + char> +{ + constexpr repeated_chars_iterator() noexcept : + first_(nullptr), + size_(0), + n_(0) + {} + constexpr repeated_chars_iterator( + char const * first, difference_type size, difference_type n) noexcept : + first_(first), + size_(size), + n_(n) + {} + + constexpr char operator*() const noexcept { return first_[n_ % size_]; } + constexpr repeated_chars_iterator & operator+=(std::ptrdiff_t i) noexcept + { + n_ += i; + return *this; + } + constexpr auto operator-(repeated_chars_iterator other) const noexcept + { + return n_ - other.n_; + } + +private: + char const * first_; + difference_type size_; + difference_type n_; +}; +``` + +The code size savings are even more dramatic for `view_interface` and +`container_interface`! If you don't ever write iterators, range views, or +containers, this is not for you. + +Online docs: https://boostorg.github.io/stl_interfaces. + +This library includes a temporary implementation for those who wish to experiment with +a concept-constrained version before C++20 is widely implemented. Casey Carter's cmcstl2 +is an implementation of the `std::ranges` portion of the C++20 standard library. To use it: + +- check out the cmcstl2 branch of this library; then + +- put its headers in your include path, so that they can be included with + `#include <stl2/foo.hpp>`; and + +- build with GCC 8 or 9, including the `-fconcepts` and `-std=c++2a` flags. + +GCC 8 and 9 are the only compilers with an adequate concepts implementation at +the time of this writing. + + +[![Build Status](https://travis-ci.org/boostorg/stl_interfaces.svg?branch=develop)](https://travis-ci.org/boostorg/stl_interfaces) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/tzlaine/stl-interfaces?branch=develop&svg=true)](https://ci.appveyor.com/project/tzlaine/stl-interfaces) +[![License](https://img.shields.io/badge/license-boost-brightgreen.svg)](LICENSE_1_0.txt) diff --git a/src/boost/libs/stl_interfaces/cmake/dependencies.cmake b/src/boost/libs/stl_interfaces/cmake/dependencies.cmake new file mode 100644 index 000000000..139f24ead --- /dev/null +++ b/src/boost/libs/stl_interfaces/cmake/dependencies.cmake @@ -0,0 +1,40 @@ +# Copyright Louis Dionne 2016 +# Copyright Zach Laine 2016-2017 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +############################################################################### +# Boost +############################################################################### +set(Boost_USE_STATIC_LIBS ON) +if (NOT BOOST_BRANCH) + set(BOOST_BRANCH master) +endif() +if (NOT EXISTS ${CMAKE_BINARY_DIR}/boost_root) + add_custom_target( + boost_root_clone + git clone --depth 100 -b ${BOOST_BRANCH} + https://github.com/boostorg/boost.git boost_root + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + if (MSVC) + set(bootstrap_cmd ./bootstrap.bat) + else() + set(bootstrap_cmd ./bootstrap.sh) + endif() + add_custom_target( + boost_clone + COMMAND git submodule init libs/assert + COMMAND git submodule init libs/config + COMMAND git submodule init libs/core + COMMAND git submodule init tools/build + COMMAND git submodule init libs/headers + COMMAND git submodule init tools/boost_install + COMMAND git submodule update --jobs 3 + COMMAND ${bootstrap_cmd} + COMMAND ./b2 headers + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/boost_root + DEPENDS boost_root_clone) +endif () +add_library(boost INTERFACE) +add_dependencies(boost boost_clone) +target_include_directories(boost INTERFACE ${CMAKE_BINARY_DIR}/boost_root) diff --git a/src/boost/libs/stl_interfaces/example/CMakeLists.txt b/src/boost/libs/stl_interfaces/example/CMakeLists.txt new file mode 100644 index 000000000..f24b8d431 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/CMakeLists.txt @@ -0,0 +1,35 @@ +# 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) +include_directories(${CMAKE_HOME_DIRECTORY}) + +include(CTest) + +enable_testing() + +add_custom_target(run_examples COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) + +macro(add_sample name) + add_executable(${name} ${name}.cpp) + target_link_libraries(${name} stl_interfaces) + set_property(TARGET ${name} PROPERTY CXX_STANDARD ${CXX_STD}) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (clang_on_linux) + target_link_libraries(${name} c++) + endif () +endmacro() + +add_sample(repeated_chars_iterator) +add_sample(filtered_int_iterator) +add_sample(node_iterator) +add_sample(random_access_iterator) +add_sample(interoperability) +add_sample(zip_proxy_iterator) +add_sample(back_insert_iterator) +add_sample(reverse_iterator) + +add_sample(drop_while_view) + +add_sample(static_vector) diff --git a/src/boost/libs/stl_interfaces/example/back_insert_iterator.cpp b/src/boost/libs/stl_interfaces/example/back_insert_iterator.cpp new file mode 100644 index 000000000..9bef646b2 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/back_insert_iterator.cpp @@ -0,0 +1,79 @@ +// 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) +//[ back_insert_iterator +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <vector> + +#include <cassert> + + +// This is an output iterator that holds a reference to a container, and calls +// push_back() on that container when it is written to, just like +// std::back_insert_iterator. This is not a lot less code to write than the +// implementation of std::back_insert_iterator, but it demonstrates that +// iterator_interface is flexible enough to handle this odd kind of iterator. +template<typename Container> +struct back_insert_iterator : boost::stl_interfaces::iterator_interface< + back_insert_iterator<Container>, + std::output_iterator_tag, + typename Container::value_type, + back_insert_iterator<Container> &> +{ + // For concept requirements. + back_insert_iterator() : c_(nullptr) {} + + // Construct from a container. + explicit back_insert_iterator(Container & c) : c_(std::addressof(c)) {} + + // When writing to *this, copy v into the container via push_back(). + back_insert_iterator & operator=(typename Container::value_type const & v) + { + c_->push_back(v); + return *this; + } + // When writing to *this, move v into the container via push_back(). + back_insert_iterator & operator=(typename Container::value_type && v) + { + c_->push_back(std::move(v)); + return *this; + } + + // Dereferencing *this just returns a reference to *this, so that the + // expression *it = value uses the operator=() overloads above. + back_insert_iterator & operator*() { return *this; } + // There is no underlying sequence over which we are iterating, so there's + // nowhere to go in next(). Do nothing. + back_insert_iterator & operator++() { return *this; } + + using base_type = boost::stl_interfaces::iterator_interface< + back_insert_iterator<Container>, + std::output_iterator_tag, + typename Container::value_type, + back_insert_iterator<Container> &>; + using base_type::operator++; + +private: + Container * c_; +}; + +// A convenience function that creates a back_insert_iterator<Container>. +template<typename Container> +back_insert_iterator<Container> back_inserter(Container & c) +{ + return back_insert_iterator<Container>(c); +} + + +int main() +{ + std::vector<int> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + std::vector<int> ints_copy; + std::copy(ints.begin(), ints.end(), ::back_inserter(ints_copy)); + assert(ints_copy == ints); +} +//] diff --git a/src/boost/libs/stl_interfaces/example/drop_while_view.cpp b/src/boost/libs/stl_interfaces/example/drop_while_view.cpp new file mode 100644 index 000000000..28578d2a2 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/drop_while_view.cpp @@ -0,0 +1,137 @@ +// 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) +#include <boost/stl_interfaces/view_interface.hpp> + +#include <algorithm> +#include <vector> + +#include <cassert> + + +//[ all_view +// A subrange is simply an iterator-sentinel pair. This one is a bit simpler +// than the one in std::ranges; its missing a bunch of constructors, prev(), +// next(), and advance(). +template<typename Iterator, typename Sentinel> +struct subrange + : boost::stl_interfaces::view_interface<subrange<Iterator, Sentinel>> +{ + subrange() = default; + constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {} + + constexpr auto begin() const { return first_; } + constexpr auto end() const { return last_; } + +private: + Iterator first_; + Sentinel last_; +}; + +// std::view::all() returns one of several types, depending on what you pass +// it. Here, we're keeping it simple; all() always returns a subrange. +template<typename Range> +auto all(Range && range) +{ + return subrange<decltype(range.begin()), decltype(range.end())>( + range.begin(), range.end()); +} + +// A template alias that denotes the type of all(r) for some Range r. +template<typename Range> +using all_view = decltype(all(std::declval<Range>())); +//] + +//[ drop_while_view_template + +// Perhaps its clear now why we defined subrange, all(), etc. above. +// drop_while_view contains a view data member. If we just took any old range +// that was passed to drop_while_view's constructor, we'd copy the range +// itself, which may be a std::vector. So, we want to make a view out of +// whatever Range we're given so that this copy of an owning range does not +// happen. +template<typename Range, typename Pred> +struct drop_while_view + : boost::stl_interfaces::view_interface<drop_while_view<Range, Pred>> +{ + using base_type = all_view<Range>; + + drop_while_view() = default; + + constexpr drop_while_view(Range & base, Pred pred) : + base_(all(base)), + pred_(std::move(pred)) + {} + + constexpr base_type base() const { return base_; } + constexpr Pred const & pred() const noexcept { return pred_; } + + // A more robust implementation should probably cache the value computed + // by this function, so that subsequent calls can just return the cached + // iterator. + constexpr auto begin() + { + // We're forced to write this out as a raw loop, since no + // std::-namespace algorithms accept a sentinel. + auto first = base_.begin(); + auto const last = base_.end(); + for (; first != last; ++first) { + if (!pred_(*first)) + break; + } + return first; + } + + constexpr auto end() { return base_.end(); } + +private: + base_type base_; + Pred pred_; +}; + +// Since this is a C++14 and later library, we're not using CTAD; we therefore +// need a make-function. +template<typename Range, typename Pred> +auto make_drop_while_view(Range & base, Pred pred) +{ + return drop_while_view<Range, Pred>(base, std::move(pred)); +} +//] + + +int main() +{ + //[ drop_while_view_usage + std::vector<int> const ints = {2, 4, 3, 4, 5, 6}; + + // all() returns a subrange, which is a view type containing ints.begin() + // and ints.end(). + auto all_ints = all(ints); + + // This works using just the used-defined members of subrange: begin() and + // end(). + assert( + std::equal(all_ints.begin(), all_ints.end(), ints.begin(), ints.end())); + + // These are available because subrange is derived from view_interface. + assert(all_ints[2] == 3); + assert(all_ints.size() == 6u); + + auto even = [](int x) { return x % 2 == 0; }; + auto ints_after_even_prefix = make_drop_while_view(ints, even); + + // Available via begin()/end()... + assert(std::equal( + ints_after_even_prefix.begin(), + ints_after_even_prefix.end(), + ints.begin() + 2, + ints.end())); + + // ... and via view_interface. + assert(!ints_after_even_prefix.empty()); + assert(ints_after_even_prefix[2] == 5); + assert(ints_after_even_prefix.back() == 6); + //] +} diff --git a/src/boost/libs/stl_interfaces/example/filtered_int_iterator.cpp b/src/boost/libs/stl_interfaces/example/filtered_int_iterator.cpp new file mode 100644 index 000000000..a788cc577 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/filtered_int_iterator.cpp @@ -0,0 +1,92 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <array> +#include <vector> + +#include <cassert> + + +//[ filtered_int_iterator_defn +template<typename Pred> +struct filtered_int_iterator : boost::stl_interfaces::iterator_interface< + filtered_int_iterator<Pred>, + std::bidirectional_iterator_tag, + int> +{ + filtered_int_iterator() : it_(nullptr) {} + filtered_int_iterator(int * it, int * last, Pred pred) : + it_(it), + last_(last), + pred_(std::move(pred)) + { + // We need to do this in the constructor so that operator== works + // properly on two filtered_int_iterators, when they bound a sequence + // in which none of the ints meets the predicate. + it_ = std::find_if(it_, last_, pred_); + } + + // A bidirectional iterator based on iterator_interface usually required + // four user-defined operations. since we are adapting an existing + // iterator (an int *), we only need to define this one. The others are + // implemented by iterator_interface, using the underlying int *. + filtered_int_iterator & operator++() + { + it_ = std::find_if(std::next(it_), last_, pred_); + return *this; + } + + // It is really common for iterator adaptors to have a base() member + // function that returns the adapted iterator. + int * base() const { return it_; } + +private: + // Provide access to these private members. + friend boost::stl_interfaces::access; + + // These functions are picked up by iterator_interface, and used to + // implement any operations that you don't define above. They're not + // called base() so that they do not collide with the base() member above. + // + // Note that the const overload does not strictly speaking need to be a + // reference, as demonstrated here. + constexpr int *& base_reference() noexcept { return it_; } + constexpr int * base_reference() const noexcept { return it_; } + + int * it_; + int * last_; + Pred pred_; +}; + +// A make-function makes it easier to deal with the Pred parameter. +template<typename Pred> +auto make_filtered_int_iterator(int * it, int * last, Pred pred) +{ + return filtered_int_iterator<Pred>(it, last, std::move(pred)); +} +//] + + +int main() +{ + //[ filtered_int_iterator_usage + std::array<int, 8> ints = {{0, 1, 2, 3, 4, 5, 6, 7}}; + int * const ints_first = ints.data(); + int * const ints_last = ints.data() + ints.size(); + + auto even = [](int x) { return (x % 2) == 0; }; + auto first = make_filtered_int_iterator(ints_first, ints_last, even); + auto last = make_filtered_int_iterator(ints_last, ints_last, even); + + // This is an example only. Obviously, we could have called + // std::copy_if() here. + std::vector<int> ints_copy; + std::copy(first, last, std::back_inserter(ints_copy)); + assert(ints_copy == (std::vector<int>{0, 2, 4, 6})); + //] +} diff --git a/src/boost/libs/stl_interfaces/example/interoperability.cpp b/src/boost/libs/stl_interfaces/example/interoperability.cpp new file mode 100644 index 000000000..7c69b0e68 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/interoperability.cpp @@ -0,0 +1,87 @@ +// 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) +//[ interoperability +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <array> +#include <numeric> + +#include <cassert> + + +// This is a random access iterator templated on a value type. The ValueType +// template parameter allows us easily to define const and non-const iterators +// from the same template. +template<typename ValueType> +struct random_access_iterator : boost::stl_interfaces::iterator_interface< + random_access_iterator<ValueType>, + std::random_access_iterator_tag, + ValueType> +{ + static_assert(std::is_object<ValueType>::value, ""); + + // Default constructor. + constexpr random_access_iterator() noexcept {} + + // Construction from an underlying pointer. + constexpr random_access_iterator(ValueType * it) noexcept : it_(it) {} + + // Implicit conversion from an existing random_access_iterator with a + // possibly different value type. The enable_if logic here just enforces + // that this constructor only participates in overload resolution when the + // expression it_ = other.it_ is well-formed. + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + constexpr random_access_iterator( + random_access_iterator<ValueType2> other) noexcept : + it_(other.it_) + {} + + constexpr ValueType & operator*() const noexcept { return *it_; } + constexpr random_access_iterator & operator+=(std::ptrdiff_t i) noexcept + { + it_ += i; + return *this; + } + constexpr auto operator-(random_access_iterator other) const noexcept + { + return it_ - other.it_; + } + +private: + ValueType * it_; + + // This friendship is necessary to enable the implicit conversion + // constructor above to work. + template<typename ValueType2> + friend struct random_access_iterator; +}; + +using iterator = random_access_iterator<int>; +using const_iterator = random_access_iterator<int const>; + +int main() +{ + std::array<int, 10> ints = {{0, 2, 1, 3, 4, 5, 7, 6, 8, 9}}; + + // Create and use two mutable iterators. + iterator first(ints.data()); + iterator last(ints.data() + ints.size()); + std::sort(first, last); + assert(ints == (std::array<int, 10>{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}})); + + // Create and use two constant iterators, one from an existing mutable + // iterator. + std::array<int, 10> int_sums; + const_iterator cfirst(ints.data()); + const_iterator clast = last; + std::partial_sum(cfirst, clast, int_sums.begin()); + assert(int_sums == (std::array<int, 10>{{0, 1, 3, 6, 10, 15, 21, 28, 36, 45}})); +} +//] diff --git a/src/boost/libs/stl_interfaces/example/node_iterator.cpp b/src/boost/libs/stl_interfaces/example/node_iterator.cpp new file mode 100644 index 000000000..752638d50 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/node_iterator.cpp @@ -0,0 +1,90 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <array> +#include <iostream> + +#include <cassert> + + +//[ node_defn +template<typename T> +struct node +{ + T value_; + node * next_; // == nullptr in the tail node +}; +//] + +//[ node_iterator_class_head +template<typename T> +struct node_iterator + : boost::stl_interfaces:: + iterator_interface<node_iterator<T>, std::forward_iterator_tag, T> +//] +{ + //[ node_iterator_ctors + constexpr node_iterator() noexcept : it_(nullptr) {} + constexpr node_iterator(node<T> * it) noexcept : it_(it) {} + //] + + //[ node_iterator_user_ops + constexpr T & operator*() const noexcept { return it_->value_; } + constexpr node_iterator & operator++() noexcept + { + it_ = it_->next_; + return *this; + } + friend constexpr bool + operator==(node_iterator lhs, node_iterator rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + //] + + //[ node_iterator_using_declaration + using base_type = boost::stl_interfaces:: + iterator_interface<node_iterator<T>, std::forward_iterator_tag, T>; + using base_type::operator++; + //] + +private: + node<T> * it_; +}; + +//[ node_iterator_concept_check Equivalent to +// static_assert(std::forward_iterator<node_iterator>, ""), or nothing in +// C++17 and earlier. +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + node_iterator<int>, std::forward_iterator) +//] + + +int main() +{ + std::array<node<int>, 5> nodes; + std::generate(nodes.begin(), nodes.end(), [] { + static int i = 0; + return node<int>{i++}; + }); + std::adjacent_find( + nodes.begin(), nodes.end(), [](node<int> & a, node<int> & b) { + a.next_ = &b; + return false; + }); + nodes.back().next_ = nullptr; + + //[ node_iterator_usage + node_iterator<int> const first(&nodes[0]); + node_iterator<int> const last; + for (auto it = first; it != last; it++) { + std::cout << *it << " "; // Prints 0 1 2 3 4 + } + std::cout << "\n"; + //] +} diff --git a/src/boost/libs/stl_interfaces/example/random_access_iterator.cpp b/src/boost/libs/stl_interfaces/example/random_access_iterator.cpp new file mode 100644 index 000000000..1d5071f72 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/random_access_iterator.cpp @@ -0,0 +1,55 @@ +// 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) +//[ random_access_iterator +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <array> + +#include <cassert> + + +// This is a minimal random access iterator. It uses default template +// parameters for most stl_interfaces template parameters. +struct simple_random_access_iterator + : boost::stl_interfaces::iterator_interface< + simple_random_access_iterator, + std::random_access_iterator_tag, + int> +{ + // This default constructor does not initialize it_, since that's how int * + // works as well. This allows optimum performance in code paths where + // initializing a single pointer may be measurable. It is also a + // reasonable choice to initialize with nullptr. + simple_random_access_iterator() noexcept {} + simple_random_access_iterator(int * it) noexcept : it_(it) {} + + int & operator*() const noexcept { return *it_; } + simple_random_access_iterator & operator+=(std::ptrdiff_t i) noexcept + { + it_ += i; + return *this; + } + auto operator-(simple_random_access_iterator other) const noexcept + { + return it_ - other.it_; + } + +private: + int * it_; +}; + + +int main() +{ + std::array<int, 10> ints = {{0, 2, 1, 3, 4, 5, 7, 6, 8, 9}}; + + simple_random_access_iterator first(ints.data()); + simple_random_access_iterator last(ints.data() + ints.size()); + std::sort(first, last); + assert(ints == (std::array<int, 10>{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}})); +} +//] diff --git a/src/boost/libs/stl_interfaces/example/repeated_chars_iterator.cpp b/src/boost/libs/stl_interfaces/example/repeated_chars_iterator.cpp new file mode 100644 index 000000000..83a158b96 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/repeated_chars_iterator.cpp @@ -0,0 +1,60 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <string> + +#include <cassert> + + +//[ repeated_chars_iterator +struct repeated_chars_iterator : boost::stl_interfaces::iterator_interface< + repeated_chars_iterator, + std::random_access_iterator_tag, + char, + char> +{ + constexpr repeated_chars_iterator() noexcept : + first_(nullptr), + size_(0), + n_(0) + {} + constexpr repeated_chars_iterator( + char const * first, difference_type size, difference_type n) noexcept : + first_(first), + size_(size), + n_(n) + {} + + constexpr char operator*() const noexcept { return first_[n_ % size_]; } + constexpr repeated_chars_iterator & operator+=(std::ptrdiff_t i) noexcept + { + n_ += i; + return *this; + } + constexpr auto operator-(repeated_chars_iterator other) const noexcept + { + return n_ - other.n_; + } + +private: + char const * first_; + difference_type size_; + difference_type n_; +}; +//] + + +int main() +{ + //[ repeated_chars_iterator_usage + repeated_chars_iterator first("foo", 3, 0); // 3 is the length of "foo", 0 is this iterator's position. + repeated_chars_iterator last("foo", 3, 7); // Same as above, but now the iterator's position is 7. + std::string result; + std::copy(first, last, std::back_inserter(result)); + assert(result == "foofoof"); + //] +} diff --git a/src/boost/libs/stl_interfaces/example/reverse_iterator.cpp b/src/boost/libs/stl_interfaces/example/reverse_iterator.cpp new file mode 100644 index 000000000..217fca787 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/reverse_iterator.cpp @@ -0,0 +1,124 @@ +// 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) +//[ reverse_iterator +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <list> +#include <vector> + +#include <cassert> + + +// In all the previous examples, we only had to implement a subset of the six +// possible user-defined basis operations that was needed for one particular +// iterator concept. For reverse_iterator, we want to support bidirectional, +// random access, and contiguous iterators. We therefore need to provide all +// the basis operations that might be needed. +template<typename BidiIter> +struct reverse_iterator + : boost::stl_interfaces::iterator_interface< + reverse_iterator<BidiIter>, +#if 201703L < __cplusplus && defined(__cpp_lib_ranges) + boost::stl_interfaces::v2::v2_dtl::iter_concept_t<BidiIter>, +#else + typename std::iterator_traits<BidiIter>::iterator_category, +#endif + typename std::iterator_traits<BidiIter>::value_type> +{ + reverse_iterator() : it_() {} + reverse_iterator(BidiIter it) : it_(it) {} + + using ref_t = typename std::iterator_traits<BidiIter>::reference; + using diff_t = typename std::iterator_traits<BidiIter>::difference_type; + + ref_t operator*() const { return *std::prev(it_); } + + // These three are used only when BidiIter::iterator_category is + // std::bidirectional_iterator_tag. + bool operator==(reverse_iterator other) const { return it_ == other.it_; } + + // Even though iterator_interface-derived bidirectional iterators are + // usually given operator++() and operator--() members, it turns out that + // operator+=() below amounts to the same thing. That's good, since + // having operator++() and operator+=() in this class would have lead to + // ambiguities in iterator_interface. + + // These two are only used when BidiIter::iterator_category is + // std::random_access_iterator_tag or std::contiguous_iterator_tag. Even + // so, they need to compile even when BidiIter::iterator_category is + // std::bidirectional_iterator_tag. That means we have to use + // std::distance() and std::advance() instead of operator-() and + // operator+=(). + // + // Don't worry, the O(n) bidirectional implementations of std::distance() + // and std::advance() are dead code, because compare() and advance() are + // never even called when BidiIter::iterator_category is + // std::bidirectional_iterator_tag. + diff_t operator-(reverse_iterator other) const + { + return -std::distance(other.it_, it_); + } + reverse_iterator & operator+=(diff_t n) + { + std::advance(it_, -n); + return *this; + } + + // No need for a using declaration to make + // iterator_interface::operator++(int) visible, because we're not defining + // operator++() in this template. + +private: + BidiIter it_; +}; + +using rev_bidi_iter = reverse_iterator<std::list<int>::iterator>; +using rev_ra_iter = reverse_iterator<std::vector<int>::iterator>; + + +int main() +{ + { + std::list<int> ints = {4, 3, 2}; + std::list<int> ints_copy; + std::copy( + rev_bidi_iter(ints.end()), + rev_bidi_iter(ints.begin()), + std::back_inserter(ints_copy)); + std::reverse(ints.begin(), ints.end()); + assert(ints_copy == ints); + } + + { + std::vector<int> ints = {4, 3, 2}; + std::vector<int> ints_copy(ints.size()); + std::copy( + rev_ra_iter(ints.end()), + rev_ra_iter(ints.begin()), + ints_copy.begin()); + std::reverse(ints.begin(), ints.end()); + assert(ints_copy == ints); + } + + { + using rev_ptr_iter = reverse_iterator<int *>; + + int ints[3] = {4, 3, 2}; + int ints_copy[3]; + std::copy( + rev_ptr_iter(std::end(ints)), + rev_ptr_iter(std::begin(ints)), + std::begin(ints_copy)); + std::reverse(std::begin(ints), std::end(ints)); + assert(std::equal( + std::begin(ints_copy), + std::end(ints_copy), + std::begin(ints), + std::end(ints))); + } +} +//] diff --git a/src/boost/libs/stl_interfaces/example/static_vector.cpp b/src/boost/libs/stl_interfaces/example/static_vector.cpp new file mode 100644 index 000000000..ffb5fadb3 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/static_vector.cpp @@ -0,0 +1,23 @@ +// 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) +#include "static_vector.hpp" + + +int main() +{ + //[ static_vector_usage + static_vector<int, 128> vec; + vec.push_back(42); + vec.push_back(13); + assert(vec[0] == 42); + assert(vec[1] == 13); + assert(vec.size() == 2u); + + vec.erase(vec.end() - 1); + static_vector<int, 128> tmp({42}); + assert(vec == (static_vector<int, 128>({42}))); + //] +} diff --git a/src/boost/libs/stl_interfaces/example/static_vector.hpp b/src/boost/libs/stl_interfaces/example/static_vector.hpp new file mode 100644 index 000000000..0290fdfea --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/static_vector.hpp @@ -0,0 +1,282 @@ +// 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) +#include <boost/stl_interfaces/sequence_container_interface.hpp> + +#include <algorithm> +#include <iterator> +#include <memory> +#include <tuple> + +#include <cassert> + + +// There's a test that uses this example header; this controls whether the +// C++14 version (v1::) of sequence_container_interface gets used, or the +// C++20 version (v2::). +#if defined(USE_V2) +template<typename Derived, boost::stl_interfaces::element_layout Contiguity> +using sequence_container_interface = + boost::stl_interfaces::v2::sequence_container_interface<Derived>; +#else +template<typename Derived, boost::stl_interfaces::element_layout Contiguity> +using sequence_container_interface = + boost::stl_interfaces::v1::sequence_container_interface<Derived, Contiguity>; +#endif + + +//[ static_vector_defn +// The sections of member functions below are commented as they are in the +// standard for std::vector. Each section has two numbers: the number of +// member functions in that section, and the number that are missing, because +// they are provided by sequence_container_interface. The purely +// allocator-specific members are neither present nor part of the counts. +// +// We're passing boost::stl_interfaces::contiguous here, so that +// sequence_container_interface knows that it should provide data(). +template<typename T, std::size_t N> +struct static_vector : sequence_container_interface< + static_vector<T, N>, + boost::stl_interfaces::element_layout::contiguous> +{ + // These are the types required for reversible containers. These must be + // user-defined. + using value_type = T; + using pointer = T *; + using const_pointer = T const *; + using reference = value_type &; + using const_reference = value_type const &; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using iterator = T *; + using const_iterator = T const *; + using reverse_iterator = boost::stl_interfaces::reverse_iterator<iterator>; + using const_reverse_iterator = + boost::stl_interfaces::reverse_iterator<const_iterator>; + + // construct/copy/destroy (9 members, skipped 2) + // + // Constructors and special member functions all must be user-provided. + // Were they provided by sequence_container_interface, everything would + // break, due to the language rules related to them. However, assignment + // from std::initializer_list can come from sequence_container_interface. + static_vector() noexcept : size_(0) {} + explicit static_vector(size_type n) : size_(0) { resize(n); } + explicit static_vector(size_type n, T const & x) : size_(0) + { + // Note that you must write "this->" before all the member functions + // provided by sequence_container_interface, which is slightly annoying. + this->assign(n, x); + } + template< + typename InputIterator, + typename Enable = std::enable_if_t<std::is_convertible< + typename std::iterator_traits<InputIterator>::iterator_category, + std::input_iterator_tag>::value>> + static_vector(InputIterator first, InputIterator last) : size_(0) + { + this->assign(first, last); + } + static_vector(std::initializer_list<T> il) : + static_vector(il.begin(), il.end()) + {} + static_vector(static_vector const & other) : size_(0) + { + this->assign(other.begin(), other.end()); + } + static_vector(static_vector && other) noexcept( + noexcept(std::declval<static_vector>().emplace_back( + std::move(*other.begin())))) : + size_(0) + { + for (auto & element : other) { + emplace_back(std::move(element)); + } + other.clear(); + } + static_vector & operator=(static_vector const & other) + { + this->clear(); + this->assign(other.begin(), other.end()); + return *this; + } + static_vector & operator=(static_vector && other) noexcept(noexcept( + std::declval<static_vector>().emplace_back(std::move(*other.begin())))) + { + this->clear(); + for (auto & element : other) { + emplace_back(std::move(element)); + } + other.clear(); + return *this; + } + ~static_vector() { this->clear(); } + + // iterators (2 members, skipped 10) + // + // This section is the first big win. Instead of having to write 12 + // overloads line begin, cbegin, rbegin, crbegin, etc., we can just write + // 2. + iterator begin() noexcept { return reinterpret_cast<T *>(buf_); } + iterator end() noexcept + { + return reinterpret_cast<T *>(buf_ + size_ * sizeof(T)); + } + + // capacity (6 members, skipped 2) + // + // Most of these are not even part of the general requirements, because + // some are specific to std::vector and related types. However, we do get + // empty and size from sequence_container_interface. + size_type max_size() const noexcept { return N; } + size_type capacity() const noexcept { return N; } + void resize(size_type sz) noexcept + { + resize_impl(sz, [] { return T(); }); + } + void resize(size_type sz, T const & x) noexcept + { + resize_impl(sz, [&]() -> T const & { return x; }); + } + void reserve(size_type n) noexcept { assert(n < capacity()); } + void shrink_to_fit() noexcept {} + + // element access (skipped 8) + // data access (skipped 2) + // + // Another big win. sequence_container_interface provides all of the + // overloads of operator[], at, front, back, and data. + + // modifiers (5 members, skipped 9) + // + // In this section we again get most of the API from + // sequence_container_interface. + + // emplace_back does not look very necessary -- just look at its trivial + // implementation -- but we can't provide it from + // sequence_container_interface, because it is an optional sequence + // container interface. We would not want emplace_front to suddenly + // appear on our std::vector-like type, and there may be some other type + // for which emplace_back is a bad idea. + // + // However, by providing emplace_back here, we signal to the + // sequence_container_interface template that our container is + // back-mutation-friendly, and this allows it to provide all the overloads + // of push_back and pop_back. + template<typename... Args> + reference emplace_back(Args &&... args) + { + return *emplace(end(), std::forward<Args>(args)...); + } + template<typename... Args> + iterator emplace(const_iterator pos, Args &&... args) + { + auto position = const_cast<T *>(pos); + bool const insert_before_end = position < end(); + if (insert_before_end) { + auto last = end(); + emplace_back(std::move(this->back())); + std::move_backward(position, last - 1, last); + } + new (position) T(std::forward<Args>(args)...); + if (!insert_before_end) + ++size_; + return position; + } + // Note: The iterator category here was upgraded to ForwardIterator + // (instead of vector's InputIterator), to ensure linear time complexity. + template< + typename ForwardIterator, + typename Enable = std::enable_if_t<std::is_convertible< + typename std::iterator_traits<ForwardIterator>::iterator_category, + std::forward_iterator_tag>::value>> + iterator + insert(const_iterator pos, ForwardIterator first, ForwardIterator last) + { + auto position = const_cast<T *>(pos); + auto const insertions = std::distance(first, last); + assert(this->size() + insertions < capacity()); + uninitialized_generate(end(), end() + insertions, [] { return T(); }); + std::move_backward(position, end(), end() + insertions); + std::copy(first, last, position); + size_ += insertions; + return position; + } + iterator erase(const_iterator f, const_iterator l) + { + auto first = const_cast<T *>(f); + auto last = const_cast<T *>(l); + auto end_ = this->end(); + auto it = std::move(last, end_, first); + for (; it != end_; ++it) { + it->~T(); + } + size_ -= last - first; + return first; + } + void swap(static_vector & other) + { + size_type short_size, long_size; + std::tie(short_size, long_size) = + std::minmax(this->size(), other.size()); + for (auto i = size_type(0); i < short_size; ++i) { + using std::swap; + swap((*this)[i], other[i]); + } + + static_vector * longer = this; + static_vector * shorter = this; + if (this->size() < other.size()) + longer = &other; + else + shorter = &other; + + for (auto it = longer->begin() + short_size, last = longer->end(); + it != last; + ++it) { + shorter->emplace_back(std::move(*it)); + } + + longer->resize(short_size); + shorter->size_ = long_size; + } + + // Since we're getting so many overloads from + // sequence_container_interface, and since many of those overloads are + // implemented in terms of a user-defined function of the same name, we + // need to add quite a few using declarations here. + using base_type = sequence_container_interface< + static_vector<T, N>, + boost::stl_interfaces::element_layout::contiguous>; + using base_type::begin; + using base_type::end; + using base_type::insert; + using base_type::erase; + + // comparisons (skipped 6) + +private: + template<typename F> + static void uninitialized_generate(iterator f, iterator l, F func) + { + for (; f != l; ++f) { + new (static_cast<void *>(std::addressof(*f))) T(func()); + } + } + template<typename F> + void resize_impl(size_type sz, F func) noexcept + { + assert(sz < capacity()); + if (sz < this->size()) + erase(begin() + sz, end()); + if (this->size() < sz) + uninitialized_generate(end(), begin() + sz, func); + size_ = sz; + } + + alignas(T) unsigned char buf_[N * sizeof(T)]; + size_type size_; +}; +//] diff --git a/src/boost/libs/stl_interfaces/example/zip_proxy_iterator.cpp b/src/boost/libs/stl_interfaces/example/zip_proxy_iterator.cpp new file mode 100644 index 000000000..4a73e0791 --- /dev/null +++ b/src/boost/libs/stl_interfaces/example/zip_proxy_iterator.cpp @@ -0,0 +1,119 @@ +// 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) +//[ zip_proxy_iterator +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <algorithm> +#include <array> +#include <tuple> + +#include <cassert> + + +// This is a zip iterator, meaning that it iterates over a notional sequence +// of pairs that is formed from two actual sequences of scalars. To make this +// iterator writable, it needs to have a reference type that is not actually a +// reference -- the reference type is a pair of references, std::tuple<int &, +// int &>. +struct zip_iterator : boost::stl_interfaces::proxy_iterator_interface< + zip_iterator, + std::random_access_iterator_tag, + std::tuple<int, int>, + std::tuple<int &, int &>> +{ + constexpr zip_iterator() noexcept : it1_(), it2_() {} + constexpr zip_iterator(int * it1, int * it2) noexcept : it1_(it1), it2_(it2) + {} + + constexpr std::tuple<int &, int &> operator*() const noexcept + { + return std::tuple<int &, int &>{*it1_, *it2_}; + } + constexpr zip_iterator & operator += (std::ptrdiff_t i) noexcept + { + it1_ += i; + it2_ += i; + return *this; + } + constexpr auto operator-(zip_iterator other) const noexcept + { + return it1_ - other.it1_; + } + +private: + int * it1_; + int * it2_; +}; + + +namespace std { + // Required for std::sort to work with zip_iterator. Without this + // overload, std::sort eventually tries to call std::swap(*it1, *it2), + // *it1 and *it2 are rvalues, and std::swap() takes mutable lvalue + // references. That makes std::swap(*it1, *it2) ill-formed. + // + // Note that this overload does not conflict with any other swap() + // overloads, since this one takes rvalue reference parameters. + // + // Also note that this overload has to be in namespace std only because + // ADL cannot find it anywhere else. If + // zip_iterator::reference/std::tuple's template parameters were not + // builtins, this overload could be in whatever namespace those template + // parameters were declared in. + void swap(zip_iterator::reference && lhs, zip_iterator::reference && rhs) + { + using std::swap; + swap(std::get<0>(lhs), std::get<0>(rhs)); + swap(std::get<1>(lhs), std::get<1>(rhs)); + } +} + + +int main() +{ + std::array<int, 10> ints = {{2, 0, 1, 5, 3, 6, 8, 4, 9, 7}}; + std::array<int, 10> ones = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; + + { + std::array<std::tuple<int, int>, 10> const result = {{ + {2, 1}, + {0, 1}, + {1, 1}, + {5, 1}, + {3, 1}, + {6, 1}, + {8, 1}, + {4, 1}, + {9, 1}, + {7, 1}, + }}; + + zip_iterator first(ints.data(), ones.data()); + zip_iterator last(ints.data() + ints.size(), ones.data() + ones.size()); + assert(std::equal(first, last, result.begin(), result.end())); + } + + { + std::array<std::tuple<int, int>, 10> const result = {{ + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {6, 1}, + {7, 1}, + {8, 1}, + {9, 1}, + }}; + zip_iterator first(ints.data(), ones.data()); + zip_iterator last(ints.data() + ints.size(), ones.data() + ones.size()); + assert(!std::equal(first, last, result.begin(), result.end())); + std::sort(first, last); + assert(std::equal(first, last, result.begin(), result.end())); + } +} +//] diff --git a/src/boost/libs/stl_interfaces/index.html b/src/boost/libs/stl_interfaces/index.html new file mode 100644 index 000000000..289c1da12 --- /dev/null +++ b/src/boost/libs/stl_interfaces/index.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/stl_interfaces.html"> + </head> + + <body> + Automatic redirection failed, click this <a href="../../doc/html/stl_interfaces.html">link</a> + <hr> + <p>Copyright T. Zachary Laine 2019</p> + <p> + Distributed under the Boost Software License, Version 1.0. + (See accompanying file <a href="LICENSE.md">LICENSE.md</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>) + </p> + </body> +</html> diff --git a/src/boost/libs/stl_interfaces/meta/libraries.json b/src/boost/libs/stl_interfaces/meta/libraries.json new file mode 100644 index 000000000..d95e99a93 --- /dev/null +++ b/src/boost/libs/stl_interfaces/meta/libraries.json @@ -0,0 +1,9 @@ +{ + "key": "stl_interfaces", + "name": "stl_interfaces", + "authors": [ "T. Zachary Laine" ], + "maintainers": [ "Zach Laine <whatwasthataddress -at- gmail.com>" ], + "description": "C++14 and later CRTP templates for defining iterators, views, and containers.", + "category": [ "Generic" ], + "cxxstd": "14" +} diff --git a/src/boost/libs/stl_interfaces/test/CMakeLists.txt b/src/boost/libs/stl_interfaces/test/CMakeLists.txt new file mode 100755 index 000000000..5e2185c44 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/CMakeLists.txt @@ -0,0 +1,55 @@ +# 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) +include_directories(${CMAKE_HOME_DIRECTORY}) + +include(CTest) + +enable_testing() + +add_custom_target(stl_interfaces_check COMMAND ${CMAKE_CTEST_COMMAND} -j4 -C ${CMAKE_CFG_INTDIR}) +if (NOT TARGET check) + add_custom_target(check DEPENDS stl_interfaces_check) +else() + add_dependencies(check stl_interfaces_check) +endif() + +set(warnings_flag) +if (NOT MSVC) + set(warnings_flag -Wall) +endif () + +macro(add_test_executable name) + add_executable(${name} ${name}.cpp) + target_compile_options(${name} PRIVATE ${warnings_flag}) + target_link_libraries(${name} stl_interfaces) + target_compile_definitions(${name} PRIVATE BOOST_NO_AUTO_PTR) + set_property(TARGET ${name} PROPERTY CXX_STANDARD ${CXX_STD}) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (clang_on_linux) + target_link_libraries(${name} c++) + endif () +endmacro() + +add_test_executable(input) +add_test_executable(output) +add_test_executable(forward) +add_test_executable(bidirectional) +add_test_executable(random_access) +add_test_executable(reverse_iter) +add_test_executable(detail) +add_test_executable(static_vec) +add_test_executable(static_vec_noncopyable) +add_test_executable(array) + +add_executable( + compile_tests + compile_tests_main.cpp + compile_seq_cont_rvalue_constrained_pop_back.cpp +) +target_link_libraries(compile_tests stl_interfaces) +if (clang_on_linux) + target_link_libraries(compile_tests c++) +endif () diff --git a/src/boost/libs/stl_interfaces/test/Jamfile.v2 b/src/boost/libs/stl_interfaces/test/Jamfile.v2 new file mode 100644 index 000000000..4a4efacae --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/Jamfile.v2 @@ -0,0 +1,28 @@ +# Boost.STLInterfaces Library Tests Jamfile + +# Copyright Oliver Kowalke 2013. +# Copyright Modified Work Barrett Adair 2020 +# 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) + +import testing ; +import ../../config/checks/config : requires ; + +project : + requirements + [ requires cxx14_constexpr ] +; + +run forward.cpp ; +run detail.cpp ; +run array.cpp ; +run output.cpp ; +run input.cpp ; +run reverse_iter.cpp ; +run static_vec_noncopyable.cpp ; +run bidirectional.cpp ; +run random_access.cpp ; +run static_vec.cpp ; + +compile compile_seq_cont_rvalue_constrained_pop_back.cpp ; diff --git a/src/boost/libs/stl_interfaces/test/array.cpp b/src/boost/libs/stl_interfaces/test/array.cpp new file mode 100644 index 000000000..bd334e98e --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/array.cpp @@ -0,0 +1,586 @@ +// 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) +#include <boost/stl_interfaces/sequence_container_interface.hpp> + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <array> +#include <deque> +#include <vector> + + +// Just like std::array, except for the 0-size specialization, and the fact +// that the base class makes brace-initialization wonky. +template<typename T, std::size_t N> +struct array : boost::stl_interfaces::sequence_container_interface< + array<T, N>, + boost::stl_interfaces::element_layout::contiguous> +{ + using value_type = T; + using pointer = T *; + using const_pointer = T const *; + using reference = value_type &; + using const_reference = value_type const &; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using iterator = T *; + using const_iterator = T const *; + using reverse_iterator = boost::stl_interfaces::reverse_iterator<iterator>; + using const_reverse_iterator = + boost::stl_interfaces::reverse_iterator<const_iterator>; + + void fill(T const & x) { std::fill(begin(), end(), x); } + + iterator begin() noexcept { return elements_; } + iterator end() noexcept { return elements_ + N; } + + size_type max_size() const noexcept { return N; } + + void swap(array & other) + { + using std::swap; + T * element = elements_; + for (auto & x : other) { + swap(*element++, x); + } + } + + using base_type = boost::stl_interfaces::sequence_container_interface< + array<T, N>, + boost::stl_interfaces::element_layout::contiguous>; + using base_type::begin; + using base_type::end; + + T elements_[N]; +}; + +using arr_type = array<int, 5>; + + +void test_comparisons() +{ + arr_type sm; + sm[0] = 1; + sm[1] = 2; + sm[2] = 3; + sm[3] = 0; + sm[4] = 0; + arr_type md; + md[0] = 1; + md[1] = 2; + md[2] = 3; + md[3] = 4; + md[4] = 0; + arr_type lg; + lg[0] = 1; + lg[1] = 2; + lg[2] = 3; + lg[3] = 4; + lg[4] = 5; + + BOOST_TEST(sm == sm); + BOOST_TEST(!(sm == md)); + BOOST_TEST(!(sm == lg)); + + BOOST_TEST(!(sm != sm)); + BOOST_TEST(sm != md); + BOOST_TEST(sm != lg); + + BOOST_TEST(!(sm < sm)); + BOOST_TEST(sm < md); + BOOST_TEST(sm < lg); + + BOOST_TEST(sm <= sm); + BOOST_TEST(sm <= md); + BOOST_TEST(sm <= lg); + + BOOST_TEST(!(sm > sm)); + BOOST_TEST(!(sm > md)); + BOOST_TEST(!(sm > lg)); + + BOOST_TEST(sm >= sm); + BOOST_TEST(!(sm >= md)); + BOOST_TEST(!(sm >= lg)); + + + BOOST_TEST(!(md == sm)); + BOOST_TEST(md == md); + BOOST_TEST(!(md == lg)); + + BOOST_TEST(!(md < sm)); + BOOST_TEST(!(md < md)); + BOOST_TEST(md < lg); + + BOOST_TEST(!(md <= sm)); + BOOST_TEST(md <= md); + BOOST_TEST(md <= lg); + + BOOST_TEST(md > sm); + BOOST_TEST(!(md > md)); + BOOST_TEST(!(md > lg)); + + BOOST_TEST(md >= sm); + BOOST_TEST(md >= md); + BOOST_TEST(!(md >= lg)); + + + BOOST_TEST(!(lg == sm)); + BOOST_TEST(!(lg == md)); + BOOST_TEST(lg == lg); + + BOOST_TEST(!(lg < sm)); + BOOST_TEST(!(lg < md)); + BOOST_TEST(!(lg < lg)); + + BOOST_TEST(!(lg <= sm)); + BOOST_TEST(!(lg <= md)); + BOOST_TEST(lg <= lg); + + BOOST_TEST(lg > sm); + BOOST_TEST(lg > md); + BOOST_TEST(!(lg > lg)); + + BOOST_TEST(lg >= sm); + BOOST_TEST(lg >= md); + BOOST_TEST(lg >= lg); +} + + +void test_swap() +{ + { + arr_type v1; + v1[0] = 3; + v1[1] = 4; + v1[2] = 0; + v1[3] = 0; + v1[4] = 0; + arr_type v2; + v2[0] = 4; + v2[1] = 3; + v2[2] = 0; + v2[3] = 0; + v2[4] = 0; + + arr_type const v1_copy = v1; + arr_type const v2_copy = v2; + + static_assert(std::is_same<decltype(v1.swap(v2)), void>::value, ""); + static_assert(std::is_same<decltype(swap(v1, v2)), void>::value, ""); + + v1.swap(v2); + + BOOST_TEST(v1 == v2_copy); + BOOST_TEST(v2 == v1_copy); + } + + { + arr_type v1; + v1[0] = 3; + v1[1] = 4; + v1[2] = 0; + v1[3] = 0; + v1[4] = 0; + arr_type v2; + v2[0] = 4; + v2[1] = 3; + v2[2] = 0; + v2[3] = 0; + v2[4] = 0; + + arr_type const v1_copy = v1; + arr_type const v2_copy = v2; + + swap(v1, v2); + + BOOST_TEST(v1 == v2_copy); + BOOST_TEST(v2 == v1_copy); + } +} + +template<typename Iter> +using writable_iter_t = decltype( + *std::declval<Iter>() = + std::declval<typename std::iterator_traits<Iter>::value_type>()); + +static_assert( + !ill_formed<writable_iter_t, decltype(std::declval<arr_type &>().begin())>:: + value, + ""); +static_assert( + !ill_formed<writable_iter_t, decltype(std::declval<arr_type &>().end())>:: + value, + ""); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<arr_type const &>().begin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<arr_type const &>().end())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<arr_type &>().cbegin())>:: + value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<arr_type &>().cend())>:: + value, + ""); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<arr_type const &>().rbegin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<arr_type const &>().rend())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<arr_type &>().crbegin())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<arr_type &>().crend())>:: + value, + ""); + +void test_iterators() +{ + arr_type v0; + v0[0] = 3; + v0[1] = 2; + v0[2] = 1; + v0[3] = 0; + v0[4] = 0; + + { + arr_type v = v0; + + static_assert( + std::is_same<decltype(v.begin()), arr_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.end()), arr_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.cbegin()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), arr_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), arr_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + arr_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + arr_type::const_reverse_iterator>::value, + ""); + + std::array<int, 5> const a = {{3, 2, 1, 0, 0}}; + std::array<int, 5> const ra = {{0, 0, 1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + + arr_type v2; + v2[0] = 8; + v2[1] = 2; + v2[2] = 1; + v2[3] = 0; + v2[4] = 9; + + *v.begin() = 8; + *v.rbegin() = 9; + BOOST_TEST(v == v2); + } + + { + arr_type const v = v0; + + static_assert( + std::is_same<decltype(v.begin()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.end()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cbegin()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), arr_type::const_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + arr_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + arr_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + arr_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + arr_type::const_reverse_iterator>::value, + ""); + + std::array<int, 5> const a = {{3, 2, 1, 0, 0}}; + std::array<int, 5> const ra = {{0, 0, 1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + } +} + + +template< + typename Container, + typename ValueType = typename Container::value_type> +using lvalue_push_front_t = decltype( + std::declval<Container &>().push_front(std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using rvalue_push_front_t = decltype(std::declval<Container &>().push_front(0)); +template<typename Container> +using pop_front_t = decltype(std::declval<Container &>().pop_front()); + +static_assert(ill_formed<lvalue_push_front_t, arr_type>::value, ""); +static_assert(ill_formed<rvalue_push_front_t, arr_type>::value, ""); +static_assert(ill_formed<pop_front_t, arr_type>::value, ""); + +using std_deq_int = std::deque<int>; + +static_assert(!ill_formed<lvalue_push_front_t, std_deq_int>::value, ""); +static_assert(!ill_formed<rvalue_push_front_t, std_deq_int>::value, ""); +static_assert(!ill_formed<pop_front_t, std_deq_int>::value, ""); + + +template< + typename Container, + typename ValueType = typename Container::value_type> +using lvalue_push_back_t = decltype( + std::declval<Container &>().push_back(std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using rvalue_push_back_t = decltype(std::declval<Container &>().push_back(0)); +template<typename Container> +using pop_back_t = decltype(std::declval<Container &>().pop_back()); + +static_assert(ill_formed<lvalue_push_back_t, arr_type>::value, ""); +static_assert(ill_formed<rvalue_push_back_t, arr_type>::value, ""); +static_assert(ill_formed<pop_back_t, arr_type>::value, ""); + +using std_vec_int = std::vector<int>; + +static_assert(!ill_formed<lvalue_push_back_t, std_vec_int>::value, ""); +static_assert(!ill_formed<rvalue_push_back_t, std_vec_int>::value, ""); +static_assert(!ill_formed<pop_back_t, std_vec_int>::value, ""); + + +void test_front_back() +{ + { + arr_type v; + v[0] = 0; + v[1] = 0; + v[2] = 0; + v[3] = 0; + v[4] = 0; + + static_assert(std::is_same<decltype(v.front()), int &>::value, ""); + static_assert(std::is_same<decltype(v.back()), int &>::value, ""); + + v.front() = 9; + v.back() = 8; + BOOST_TEST(v[0] == v.front()); + BOOST_TEST(v[4] == v.back()); + } + + { + arr_type v0; + v0[0] = 3; + v0[1] = 0; + v0[2] = 2; + v0[3] = 0; + v0[4] = 1; + + arr_type const v = v0; + BOOST_TEST(v.front() == 3); + BOOST_TEST(v.back() == 1); + + static_assert( + std::is_same<decltype(v.front()), int const &>::value, ""); + static_assert(std::is_same<decltype(v.back()), int const &>::value, ""); + } +} + + +void test_cindex_at() +{ + arr_type v0; + v0[0] = 3; + v0[1] = 2; + v0[2] = 1; + v0[3] = 0; + v0[4] = 0; + + { + arr_type v = v0; + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(5), std::out_of_range); + + static_assert(std::is_same<decltype(v[0]), int &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), int &>::value, ""); + + v[0] = 8; + v.at(1) = 9; + BOOST_TEST(v[0] == 8); + BOOST_TEST(v[1] == 9); + } + + { + arr_type const v = v0; + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(5), std::out_of_range); + + static_assert(std::is_same<decltype(v[0]), int const &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), int const &>::value, ""); + } +} + + +template<typename Container> +using resize_t = decltype(std::declval<Container &>().resize(0)); + +static_assert(ill_formed<resize_t, arr_type>::value, ""); + +static_assert(!ill_formed<resize_t, std_vec_int>::value, ""); + +template< + typename Container, + typename ValueType = typename Container::value_type> +using lvalue_insert_t = decltype(std::declval<Container &>().insert( + std::declval<Container &>().begin(), std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using rvalue_insert_t = decltype(std::declval<Container &>().insert( + std::declval<Container &>().begin(), std::declval<ValueType &&>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using insert_n_t = decltype(std::declval<Container &>().insert( + std::declval<Container &>().begin(), 2, std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using insert_il_t = decltype(std::declval<Container &>().insert( + std::declval<Container &>().begin(), std::initializer_list<int>{})); + +static_assert(ill_formed<lvalue_insert_t, arr_type>::value, ""); +static_assert(ill_formed<rvalue_insert_t, arr_type>::value, ""); + +#if defined(__cpp_lib_concepts) +static_assert(ill_formed<insert_n_t, arr_type>::value, ""); +#endif + +static_assert(ill_formed<insert_il_t, arr_type>::value, ""); + +static_assert(!ill_formed<lvalue_insert_t, std_vec_int>::value, ""); +static_assert(!ill_formed<rvalue_insert_t, std_vec_int>::value, ""); +static_assert(!ill_formed<insert_n_t, std_vec_int>::value, ""); +static_assert(!ill_formed<insert_il_t, std_vec_int>::value, ""); + + +template<typename Container> +using erase_t = decltype( + std::declval<Container &>().erase(std::declval<Container &>().begin())); + +static_assert(ill_formed<erase_t, arr_type>::value, ""); + +static_assert(!ill_formed<erase_t, std_vec_int>::value, ""); + + +template<typename Container> +using assign_t = decltype(std::declval<Container &>().assign( + std::declval<int *>(), std::declval<int *>())); +template<typename Container> +using assign_n_t = decltype(std::declval<Container &>().assign(5, 5)); +template<typename Container> +using assign_il_t = + decltype(std::declval<Container &>().assign(std::initializer_list<int>{})); +template<typename Container> +using assignment_operator_il_t = + decltype(std::declval<Container &>() = std::initializer_list<int>{}); + +static_assert(ill_formed<assign_t, arr_type>::value, ""); +static_assert(ill_formed<assign_n_t, arr_type>::value, ""); +static_assert(ill_formed<assign_il_t, arr_type>::value, ""); +static_assert(ill_formed<assignment_operator_il_t, arr_type>::value, ""); + +static_assert(!ill_formed<assign_t, std_vec_int>::value, ""); +static_assert(!ill_formed<assign_n_t, std_vec_int>::value, ""); +static_assert(!ill_formed<assign_il_t, std_vec_int>::value, ""); +static_assert(!ill_formed<assignment_operator_il_t, std_vec_int>::value, ""); + +template<typename Container> +using clear_t = decltype(std::declval<Container &>().clear()); + +static_assert(ill_formed<clear_t, arr_type>::value, ""); + +static_assert(!ill_formed<clear_t, std_vec_int>::value, ""); + +int main() +{ + test_comparisons(); + test_swap(); + test_iterators(); + test_front_back(); + test_cindex_at(); + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/bidirectional.cpp b/src/boost/libs/stl_interfaces/test/bidirectional.cpp new file mode 100644 index 000000000..1b51578d6 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/bidirectional.cpp @@ -0,0 +1,669 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <algorithm> +#include <array> +#include <functional> +#include <numeric> +#include <list> +#include <type_traits> + + +struct basic_bidirectional_iter : boost::stl_interfaces::iterator_interface< + basic_bidirectional_iter, + std::bidirectional_iterator_tag, + int> +{ + basic_bidirectional_iter() : it_(nullptr) {} + basic_bidirectional_iter(int * it) : it_(it) {} + + int & operator*() const { return *it_; } + basic_bidirectional_iter & operator++() + { + ++it_; + return *this; + } + basic_bidirectional_iter & operator--() + { + --it_; + return *this; + } + friend bool operator==( + basic_bidirectional_iter lhs, basic_bidirectional_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces::iterator_interface< + basic_bidirectional_iter, + std::bidirectional_iterator_tag, + int>; + using base_type::operator++; + using base_type::operator--; + +private: + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_bidirectional_iter, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_bidirectional_iter, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +static_assert( + !boost::stl_interfaces::v1::v1_dtl:: + plus_eq<basic_bidirectional_iter, std::ptrdiff_t>::value, + ""); + +struct basic_adapted_bidirectional_ptr_iter + : boost::stl_interfaces::iterator_interface< + basic_adapted_bidirectional_ptr_iter, + std::bidirectional_iterator_tag, + int> +{ + basic_adapted_bidirectional_ptr_iter() : it_(nullptr) {} + basic_adapted_bidirectional_ptr_iter(int * it) : it_(it) {} + +private: + friend boost::stl_interfaces::access; + int *& base_reference() noexcept { return it_; } + int * base_reference() const noexcept { return it_; } + + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_adapted_bidirectional_ptr_iter, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_adapted_bidirectional_ptr_iter, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +struct basic_adapted_bidirectional_list_iter + : boost::stl_interfaces::iterator_interface< + basic_adapted_bidirectional_list_iter, + std::bidirectional_iterator_tag, + int> +{ + basic_adapted_bidirectional_list_iter() : it_() {} + basic_adapted_bidirectional_list_iter(std::list<int>::iterator it) : it_(it) + {} + +private: + friend boost::stl_interfaces::access; + std::list<int>::iterator & base_reference() noexcept { return it_; } + std::list<int>::iterator base_reference() const noexcept { return it_; } + + std::list<int>::iterator it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_adapted_bidirectional_list_iter, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_adapted_bidirectional_list_iter, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +template<typename ValueType> +struct adapted_bidirectional_ptr_iter + : boost::stl_interfaces::iterator_interface< + adapted_bidirectional_ptr_iter<ValueType>, + std::bidirectional_iterator_tag, + ValueType> +{ + adapted_bidirectional_ptr_iter() : it_(nullptr) {} + adapted_bidirectional_ptr_iter(ValueType * it) : it_(it) {} + + template<typename ValueType2> + adapted_bidirectional_ptr_iter( + adapted_bidirectional_ptr_iter<ValueType2> other) : + it_(other.it_) + {} + + template<typename ValueType2> + friend struct adapted_bidirectional_ptr_iter; + +private: + friend boost::stl_interfaces::access; + ValueType *& base_reference() noexcept { return it_; } + ValueType * base_reference() const noexcept { return it_; } + + ValueType * it_; +}; + +static_assert( + !boost::stl_interfaces::v1::v1_dtl::ra_iter< + adapted_bidirectional_ptr_iter<int>>::value, + ""); +static_assert( + !boost::stl_interfaces::v1::v1_dtl::ra_iter< + adapted_bidirectional_ptr_iter<int const>>::value, + ""); + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + adapted_bidirectional_ptr_iter<int>, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + adapted_bidirectional_ptr_iter<int>, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + adapted_bidirectional_ptr_iter<int const>, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + adapted_bidirectional_ptr_iter<int const>, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int const &, + int const *, + std::ptrdiff_t) + +template<typename ValueType> +struct bidirectional_iter : boost::stl_interfaces::iterator_interface< + bidirectional_iter<ValueType>, + std::bidirectional_iterator_tag, + ValueType> +{ + bidirectional_iter() : it_(nullptr) {} + bidirectional_iter(ValueType * it) : it_(it) {} + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + bidirectional_iter(bidirectional_iter<ValueType2> it) : it_(it.it_) + {} + + ValueType & operator*() const { return *it_; } + bidirectional_iter & operator++() + { + ++it_; + return *this; + } + bidirectional_iter & operator--() + { + --it_; + return *this; + } + friend bool + operator==(bidirectional_iter lhs, bidirectional_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces::iterator_interface< + bidirectional_iter<ValueType>, + std::bidirectional_iterator_tag, + ValueType>; + using base_type::operator++; + using base_type::operator--; + +private: + ValueType * it_; + + template<typename ValueType2> + friend struct bidirectional_iter; +}; + +using bidirectional = bidirectional_iter<int>; +using const_bidirectional = bidirectional_iter<int const>; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + bidirectional, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + bidirectional, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + const_bidirectional, std::bidirectional_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + const_bidirectional, + std::bidirectional_iterator_tag, + std::bidirectional_iterator_tag, + int, + int const &, + int const *, + std::ptrdiff_t) + + +std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + + +//////////////////// +// view_interface // +//////////////////// +#include "view_tests.hpp" + +template<typename T> +using data_t = decltype(std::declval<T>().data()); + +static_assert( + ill_formed< + data_t, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + data_t, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using size_t_ = decltype(std::declval<T>().size()); + +static_assert( + ill_formed< + size_t_, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + size_t_, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using index_operator_t = decltype(std::declval<T>()[0]); + +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_bidirectional_iter, + basic_bidirectional_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + + +int main() +{ + +{ + basic_bidirectional_iter first(ints.data()); + basic_bidirectional_iter last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + basic_bidirectional_iter first(iota_ints.data()); + basic_bidirectional_iter last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_bidirectional_iter first(iota_ints.data()); + basic_bidirectional_iter last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + basic_adapted_bidirectional_ptr_iter first(ints.data()); + basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + basic_adapted_bidirectional_ptr_iter first(iota_ints.data()); + basic_adapted_bidirectional_ptr_iter last( + iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_adapted_bidirectional_ptr_iter first(iota_ints.data()); + basic_adapted_bidirectional_ptr_iter last( + iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + basic_adapted_bidirectional_list_iter first(ints.begin()); + basic_adapted_bidirectional_list_iter last(ints.end()); + + { + std::list<int> ints_copy; + std::copy(first, last, std::back_inserter(ints_copy)); + BOOST_TEST(ints_copy == ints); + } + + { + std::list<int> ints_copy; + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + std::back_inserter(ints_copy)); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } +} + + +{ + { + bidirectional first(ints.data()); + bidirectional last(ints.data() + ints.size()); + const_bidirectional first_copy(first); + const_bidirectional last_copy(last); + std::equal(first, last, first_copy, last_copy); + } + + { + adapted_bidirectional_ptr_iter<int> first(ints.data()); + adapted_bidirectional_ptr_iter<int> last(ints.data() + ints.size()); + adapted_bidirectional_ptr_iter<int const> first_copy( + (int const *)ints.data()); + adapted_bidirectional_ptr_iter<int const> last_copy( + (int const *)ints.data() + ints.size()); + std::equal(first, last, first_copy, last_copy); + } +} + + +{ + { + bidirectional first(ints.data()); + bidirectional last(ints.data() + ints.size()); + const_bidirectional first_const(first); + const_bidirectional last_const(last); + + BOOST_TEST(first == first_const); + BOOST_TEST(first_const == first); + BOOST_TEST(first != last_const); + BOOST_TEST(last_const != first); + } + + { + adapted_bidirectional_ptr_iter<int> first(ints.data()); + adapted_bidirectional_ptr_iter<int> last(ints.data() + ints.size()); + adapted_bidirectional_ptr_iter<int const> first_const( + (int const *)ints.data()); + adapted_bidirectional_ptr_iter<int const> last_const( + (int const *)ints.data() + ints.size()); + + static_assert( + !boost::stl_interfaces::v1::v1_dtl::ra_iter< + adapted_bidirectional_ptr_iter<int>>::value, + ""); + + BOOST_TEST(first == first_const); + BOOST_TEST(first_const == first); + BOOST_TEST(first != last_const); + BOOST_TEST(last_const != first); + } +} + + +{ + { + bidirectional first(ints.data()); + bidirectional last(ints.data() + ints.size()); + while (first != last && !(first == last)) + first++; + } + + { + bidirectional first(ints.data()); + bidirectional last(ints.data() + ints.size()); + while (first != last && !(first == last)) + last--; + } + + { + basic_bidirectional_iter first(ints.data()); + basic_bidirectional_iter last(ints.data() + ints.size()); + while (first != last && !(first == last)) + first++; + } + + { + basic_bidirectional_iter first(ints.data()); + basic_bidirectional_iter last(ints.data() + ints.size()); + while (first != last && !(first == last)) + last--; + } + + { + basic_adapted_bidirectional_ptr_iter first(ints.data()); + basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size()); + while (first != last && !(first == last)) + first++; + } + + { + basic_adapted_bidirectional_ptr_iter first(ints.data()); + basic_adapted_bidirectional_ptr_iter last(ints.data() + ints.size()); + while (first != last && !(first == last)) + last--; + } + + { + std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + basic_adapted_bidirectional_list_iter first(ints.begin()); + basic_adapted_bidirectional_list_iter last(ints.end()); + while (first != last && !(first == last)) + first++; + } + + { + std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + basic_adapted_bidirectional_list_iter first(ints.begin()); + basic_adapted_bidirectional_list_iter last(ints.end()); + while (first != last && !(first == last)) + last--; + } +} + + +{ + bidirectional first(ints.data()); + bidirectional last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + bidirectional first(iota_ints.data()); + bidirectional last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + bidirectional first(iota_ints.data()); + bidirectional last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + const_bidirectional first(ints.data()); + const_bidirectional last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + BOOST_TEST(std::binary_search(first, last, 3)); + BOOST_TEST(std::binary_search( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 3, + std::greater<>{})); + } +} + +{ + basic_bidirectional_iter first(ints.data()); + basic_bidirectional_iter last(ints.data() + ints.size()); + + auto r = range<boost::stl_interfaces::element_layout::discontiguous>( + first, last); + auto empty = + range<boost::stl_interfaces::element_layout::discontiguous>( + first, first); + + // range begin/end + { + std::array<int, 10> ints_copy; + std::copy(r.begin(), r.end(), ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + + BOOST_TEST(empty.begin() == empty.end()); + } + + // empty/op bool + { + BOOST_TEST(!r.empty()); + BOOST_TEST(r); + + BOOST_TEST(empty.empty()); + BOOST_TEST(!empty); + + auto const cr = r; + BOOST_TEST(!cr.empty()); + BOOST_TEST(cr); + + auto const cempty = empty; + BOOST_TEST(cempty.empty()); + BOOST_TEST(!cempty); + } + + // front/back + { + BOOST_TEST(r.front() == 0); + BOOST_TEST(r.back() == 9); + + auto const cr = r; + BOOST_TEST(cr.front() == 0); + BOOST_TEST(cr.back() == 9); + } +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/compile_seq_cont_rvalue_constrained_pop_back.cpp b/src/boost/libs/stl_interfaces/test/compile_seq_cont_rvalue_constrained_pop_back.cpp new file mode 100644 index 000000000..63b656d82 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/compile_seq_cont_rvalue_constrained_pop_back.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2021 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 BOOST_STL_INTERFACES_USE_CONCEPTS + +void compile_seq_cont_constrained_pop_back() {} + +#else + +#include <initializer_list> +#include <memory> +#include <type_traits> +#include <utility> +#include <vector> + +#include <boost/stl_interfaces/sequence_container_interface.hpp> + +template<class T> +struct container : boost::stl_interfaces::sequence_container_interface< + container<T>, + boost::stl_interfaces::element_layout::contiguous> +{ +public: + using super = boost::stl_interfaces::sequence_container_interface< + container<T>, + boost::stl_interfaces::element_layout::contiguous>; + using container_type = std::vector<T>; + + using value_type = typename container_type::value_type; + using reference = typename container_type::reference; + using const_reference = typename container_type::const_reference; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using difference_type = typename container_type::difference_type; + using size_type = typename container_type::size_type; + + container() = default; + container(const container &) = default; + container(container &&) = default; + ~container() = default; + container & operator=(const container &) = default; + container & operator=(container &&) = default; + + container(size_type count, const_reference value) : c(count, value) {} + container(std::initializer_list<value_type> init) : c(init) {} + + template<class InputIt> + container(InputIt first, InputIt last) : c(first, last) + {} + + iterator begin() noexcept { return c.begin(); } + iterator end() noexcept { return c.end(); } + + size_type max_size() const noexcept { return c.max_size(); } + + template<class InputIt> + iterator insert(const_iterator pos, InputIt first, InputIt last) + { + return c.insert(pos, first, last); + } + + template<class... Args> + iterator emplace(const_iterator pos, Args &&... args) + { + return c.emplace(pos, std::forward<Args>(args)...); + } + + iterator erase(const_iterator first, const_iterator last) + { + return c.erase(first, last); + } + + template<class... Args> + requires(std::constructible_from<value_type, Args &&...>) reference + emplace_back(Args &&... args) + { + return c.emplace_back(std::forward<Args>(args)...); + } + + void swap(container & other) { c.swap(other.c); } + + using super::begin; + using super::end; + using super::insert; + using super::erase; + +private: + container_type c; +}; + +void compile_seq_cont_constrained_pop_back() +{ + { + std::vector<int> v; + v.emplace_back(0); + v.pop_back(); + + container<int> c; + c.emplace_back(0); + c.pop_back(); + } + + { + std::vector<std::unique_ptr<int>> v; + v.emplace_back(new int); + v.pop_back(); + + container<std::unique_ptr<int>> c; + c.emplace_back(new int); + c.pop_back(); + } +} + +#endif diff --git a/src/boost/libs/stl_interfaces/test/compile_tests_main.cpp b/src/boost/libs/stl_interfaces/test/compile_tests_main.cpp new file mode 100644 index 000000000..9da47592e --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/compile_tests_main.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2021 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) +void compile_seq_cont_constrained_pop_back(); + +int main() +{ + compile_seq_cont_constrained_pop_back(); +} diff --git a/src/boost/libs/stl_interfaces/test/detail.cpp b/src/boost/libs/stl_interfaces/test/detail.cpp new file mode 100644 index 000000000..59bfaac96 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/detail.cpp @@ -0,0 +1,103 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> +#include <boost/stl_interfaces/view_interface.hpp> +#include <boost/stl_interfaces/sequence_container_interface.hpp> + +#include <boost/core/lightweight_test.hpp> + +#include <array> +#include <list> +#include <vector> + + +namespace detail = boost::stl_interfaces::detail; +namespace v1_dtl = boost::stl_interfaces::v1::v1_dtl; + + +// iter_difference_t +static_assert( + std::is_same<v1_dtl::iter_difference_t<int *>, std::ptrdiff_t>::value, ""); +static_assert(std::is_same< + v1_dtl::iter_difference_t<std::vector<double>::iterator>, + std::vector<double>::difference_type>::value, ""); +static_assert(std::is_same< + v1_dtl::iter_difference_t<std::list<double>::iterator>, + std::list<double>::difference_type>::value, ""); + +struct ridiculous_range +{ + int * begin() { return nullptr; } + double end() { return 1.3; } +}; + +// iterator_t +static_assert(std::is_same< + v1_dtl::iterator_t<std::vector<double>>, + std::vector<double>::iterator>::value, ""); +static_assert(std::is_same< + v1_dtl::iterator_t<std::list<double>>, + std::list<double>::iterator>::value, ""); +static_assert(std::is_same<v1_dtl::iterator_t<ridiculous_range>, int *>::value, ""); + +// sentinel_t +static_assert(std::is_same< + v1_dtl::sentinel_t<std::vector<double>>, + std::vector<double>::iterator>::value, ""); +static_assert(std::is_same< + v1_dtl::sentinel_t<std::list<double>>, + std::list<double>::iterator>::value, ""); +static_assert(std::is_same<v1_dtl::sentinel_t<ridiculous_range>, double>::value, ""); + +// range_difference_t +static_assert( + std::is_same< + v1_dtl::range_difference_t<std::vector<double>>, + std::iterator_traits<std::vector<double>::iterator>::difference_type>::value, ""); +static_assert( + std::is_same< + v1_dtl::range_difference_t<std::list<double>>, + std::iterator_traits<std::list<double>::iterator>::difference_type>::value, ""); +static_assert(std::is_same< + v1_dtl::range_difference_t<ridiculous_range>, + std::ptrdiff_t>::value, ""); + +// common_range +static_assert(v1_dtl::common_range<std::vector<double>>::value, ""); +static_assert(v1_dtl::common_range<std::list<double>>::value, ""); +static_assert(!v1_dtl::common_range<ridiculous_range>::value, ""); + + +struct no_clear +{}; + +int main() +{ + +{ + { + no_clear nc; + v1_dtl::clear_impl<no_clear>::call(nc); + } + { + std::vector<int> vec(10); + v1_dtl::clear_impl<std::vector<int>>::call(vec); + BOOST_TEST(vec.empty()); + } +} + + +{ + std::array<int, 5> ints = {{0, 1, 2, 3, 4}}; + int const new_value = 6; + detail::n_iter<int, int> first = detail::make_n_iter(new_value, 3); + detail::n_iter<int, int> last = detail::make_n_iter_end(new_value, 3); + std::copy(first, last, &ints[1]); + BOOST_TEST(ints == (std::array<int, 5>{{0, 6, 6, 6, 4}})); +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/forward.cpp b/src/boost/libs/stl_interfaces/test/forward.cpp new file mode 100644 index 000000000..51e9ed942 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/forward.cpp @@ -0,0 +1,342 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <algorithm> +#include <array> +#include <numeric> +#include <type_traits> + + +template<typename T> +using decrementable_t = decltype(--std::declval<T &>()); + +struct basic_forward_iter + : boost::stl_interfaces:: + iterator_interface<basic_forward_iter, std::forward_iterator_tag, int> +{ + basic_forward_iter() : it_(nullptr) {} + basic_forward_iter(int * it) : it_(it) {} + + int & operator*() const { return *it_; } + basic_forward_iter & operator++() + { + ++it_; + return *this; + } + friend bool + operator==(basic_forward_iter lhs, basic_forward_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces:: + iterator_interface<basic_forward_iter, std::forward_iterator_tag, int>; + using base_type::operator++; + +private: + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_forward_iter, std::forward_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_forward_iter, + std::forward_iterator_tag, + std::forward_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +static_assert(ill_formed<decrementable_t, basic_forward_iter>::value, ""); + +template<typename ValueType> +struct forward_iter : boost::stl_interfaces::iterator_interface< + forward_iter<ValueType>, + std::forward_iterator_tag, + ValueType> +{ + forward_iter() : it_(nullptr) {} + forward_iter(ValueType * it) : it_(it) {} + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + forward_iter(forward_iter<ValueType2> it) : it_(it.it_) + {} + + ValueType & operator*() const { return *it_; } + forward_iter & operator++() + { + ++it_; + return *this; + } + friend bool operator==(forward_iter lhs, forward_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces::iterator_interface< + forward_iter<ValueType>, + std::forward_iterator_tag, + ValueType>; + using base_type::operator++; + +private: + ValueType * it_; + + template<typename ValueType2> + friend struct forward_iter; +}; + +using forward = forward_iter<int>; +using const_forward = forward_iter<int const>; + +static_assert(ill_formed<decrementable_t, forward>::value, ""); +static_assert(ill_formed<decrementable_t, const_forward>::value, ""); + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(forward, std::forward_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + forward, + std::forward_iterator_tag, + std::forward_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(const_forward, std::forward_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + const_forward, + std::forward_iterator_tag, + std::forward_iterator_tag, + int, + int const &, + int const *, + std::ptrdiff_t) + + +std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + + + +//////////////////// +// view_interface // +//////////////////// +#include "view_tests.hpp" + +template<typename T> +using data_t = decltype(std::declval<T>().data()); + +static_assert( + ill_formed< + data_t, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + data_t, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using size_t_ = decltype(std::declval<T>().size()); + +static_assert( + ill_formed< + size_t_, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + size_t_, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using back_t_ = decltype(std::declval<T>().back()); + +static_assert( + ill_formed< + back_t_, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + back_t_, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using index_operator_t = decltype(std::declval<T>()[0]); + +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_forward_iter, + basic_forward_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + + +int main() +{ + +{ + basic_forward_iter first(ints.data()); + basic_forward_iter last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + basic_forward_iter first(iota_ints.data()); + basic_forward_iter last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + forward first(ints.data()); + forward last(ints.data() + ints.size()); + const_forward first_copy(first); + const_forward last_copy(last); + std::equal(first, last, first_copy, last_copy); +} + + +{ + forward first(ints.data()); + forward last(ints.data() + ints.size()); + while (first != last) + first++; +} + + +{ + forward first(ints.data()); + forward last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + forward first(iota_ints.data()); + forward last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + const_forward first(ints.data()); + const_forward last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + BOOST_TEST(std::binary_search(first, last, 3)); + } +} + +{ + basic_forward_iter first(ints.data()); + basic_forward_iter last(ints.data() + ints.size()); + + auto r = range<boost::stl_interfaces::element_layout::discontiguous>( + first, last); + auto empty = + range<boost::stl_interfaces::element_layout::discontiguous>( + first, first); + + // range begin/end + { + std::array<int, 10> ints_copy; + std::copy(r.begin(), r.end(), ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + + BOOST_TEST(empty.begin() == empty.end()); + } + + // empty/op bool + { + BOOST_TEST(!r.empty()); + BOOST_TEST(r); + + BOOST_TEST(empty.empty()); + BOOST_TEST(!empty); + + auto const cr = r; + BOOST_TEST(!cr.empty()); + BOOST_TEST(cr); + + auto const cempty = empty; + BOOST_TEST(cempty.empty()); + BOOST_TEST(!cempty); + } + + // front/back + { + BOOST_TEST(r.front() == 0); + + auto const cr = r; + BOOST_TEST(cr.front() == 0); + } +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/ill_formed.hpp b/src/boost/libs/stl_interfaces/test/ill_formed.hpp new file mode 100644 index 000000000..00b5a1eb9 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/ill_formed.hpp @@ -0,0 +1,17 @@ +// 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 BOOST_STL_INTERFACES_ILL_FORMED_HPP +#define BOOST_STL_INTERFACES_ILL_FORMED_HPP + +#include <boost/stl_interfaces/iterator_interface.hpp> + + +template<template<class...> class Template, typename... Args> +using ill_formed = std::integral_constant< + bool, + !boost::stl_interfaces::detail::detector<void, Template, Args...>::value>; + +#endif diff --git a/src/boost/libs/stl_interfaces/test/input.cpp b/src/boost/libs/stl_interfaces/test/input.cpp new file mode 100644 index 000000000..8000bc319 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/input.cpp @@ -0,0 +1,395 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <array> +#include <numeric> +#include <type_traits> + + +struct basic_input_iter + : boost::stl_interfaces:: + iterator_interface<basic_input_iter, std::input_iterator_tag, int> +{ + basic_input_iter() : it_(nullptr) {} + basic_input_iter(int * it) : it_(it) {} + + int & operator*() const noexcept { return *it_; } + basic_input_iter & operator++() noexcept + { + ++it_; + return *this; + } + friend bool operator==(basic_input_iter lhs, basic_input_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces:: + iterator_interface<basic_input_iter, std::input_iterator_tag, int>; + using base_type::operator++; + +private: + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_input_iter, std::input_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_input_iter, + std::input_iterator_tag, + std::input_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +template<typename ValueType> +struct input_iter : boost::stl_interfaces::iterator_interface< + input_iter<ValueType>, + std::input_iterator_tag, + ValueType> +{ + input_iter() : it_(nullptr) {} + input_iter(ValueType * it) : it_(it) {} + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + input_iter(input_iter<ValueType2> it) : it_(it.it_) + {} + + ValueType & operator*() const noexcept { return *it_; } + input_iter & operator++() noexcept + { + ++it_; + return *this; + } + friend bool operator==(input_iter lhs, input_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces::iterator_interface< + input_iter<ValueType>, + std::input_iterator_tag, + ValueType>; + using base_type::operator++; + +private: + ValueType * it_; + + template<typename ValueType2> + friend struct input_iter; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(input_iter<int>, std::input_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + input_iter<int>, + std::input_iterator_tag, + std::input_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +using int_input = input_iter<int>; +using const_int_input = input_iter<int const>; +using pair_input = input_iter<std::pair<int, int>>; +using const_pair_input = input_iter<std::pair<int, int> const>; + +template<typename ValueType> +struct proxy_input_iter : boost::stl_interfaces::proxy_iterator_interface< + proxy_input_iter<ValueType>, + std::input_iterator_tag, + ValueType> +{ + proxy_input_iter() : it_(nullptr) {} + proxy_input_iter(ValueType * it) : it_(it) {} + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + proxy_input_iter(proxy_input_iter<ValueType2> it) : it_(it.it_) + {} + + ValueType operator*() const noexcept { return *it_; } + proxy_input_iter & operator++() noexcept + { + ++it_; + return *this; + } + friend bool operator==(proxy_input_iter lhs, proxy_input_iter rhs) noexcept + { + return lhs.it_ == rhs.it_; + } + + using base_type = boost::stl_interfaces::proxy_iterator_interface< + proxy_input_iter<ValueType>, + std::input_iterator_tag, + ValueType>; + using base_type::operator++; + +private: + ValueType * it_; + + template<typename ValueType2> + friend struct proxy_input_iter; +}; + +using int_pair = std::pair<int, int>; +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + proxy_input_iter<int_pair>, std::input_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + proxy_input_iter<int_pair>, + std::input_iterator_tag, + std::input_iterator_tag, + int_pair, + int_pair, + boost::stl_interfaces::proxy_arrow_result<int_pair>, + std::ptrdiff_t) + +std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; +std::array<std::pair<int, int>, 10> pairs = {{ + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {6, 1}, + {7, 1}, + {8, 1}, + {9, 1}, +}}; + + +//////////////////// +// view_interface // +//////////////////// +#include "view_tests.hpp" + +template<typename T> +using data_t = decltype(std::declval<T>().data()); + +static_assert( + ill_formed< + data_t, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + data_t, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using size_t_ = decltype(std::declval<T>().size()); + +static_assert( + ill_formed< + size_t_, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + size_t_, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using back_t_ = decltype(std::declval<T>().back()); + +static_assert( + ill_formed< + back_t_, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + back_t_, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using index_operator_t = decltype(std::declval<T>()[0]); + +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + index_operator_t, + subrange< + basic_input_iter, + basic_input_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + + +int main() +{ + +{ + basic_input_iter first(ints.data()); + basic_input_iter last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } +} + + +{ + int_input first(ints.data()); + int_input last(ints.data() + ints.size()); + const_int_input first_copy(first); + const_int_input last_copy(last); + std::equal(first, last, first_copy, last_copy); +} + + +{ + int_input first(ints.data()); + int_input last(ints.data() + ints.size()); + while (first != last) + first++; +} + + +{ + { + std::array<int, 10> ints_copy; + int_input first(ints.data()); + int_input last(ints.data() + ints.size()); + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<std::pair<int, int>, 10> pairs_copy; + pair_input first(pairs.data()); + pair_input last(pairs.data() + pairs.size()); + std::copy(first, last, pairs_copy.begin()); + BOOST_TEST(pairs_copy == pairs); + } + + { + std::array<int, 10> firsts_copy; + pair_input first(pairs.data()); + pair_input last(pairs.data() + pairs.size()); + for (auto out = firsts_copy.begin(); first != last; ++first) { + *out++ = first->first; + } + BOOST_TEST(firsts_copy == ints); + } + + { + std::array<int, 10> firsts_copy; + proxy_input_iter<std::pair<int, int>> first(pairs.data()); + proxy_input_iter<std::pair<int, int>> last(pairs.data() + pairs.size()); + for (auto out = firsts_copy.begin(); first != last; ++first) { + *out++ = first->first; + } + BOOST_TEST(firsts_copy == ints); + } +} + + +{ + { + std::array<int, 10> ints_copy; + const_int_input first(ints.data()); + const_int_input last(ints.data() + ints.size()); + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<std::pair<int, int>, 10> pairs_copy; + const_pair_input first(pairs.data()); + const_pair_input last(pairs.data() + pairs.size()); + std::copy(first, last, pairs_copy.begin()); + BOOST_TEST(pairs_copy == pairs); + } + + { + std::array<int, 10> firsts_copy; + const_pair_input first(pairs.data()); + const_pair_input last(pairs.data() + pairs.size()); + for (auto out = firsts_copy.begin(); first != last; ++first) { + *out++ = first->first; + } + BOOST_TEST(firsts_copy == ints); + } + + { + std::array<int, 10> firsts_copy; + proxy_input_iter<std::pair<int, int> const> first(pairs.data()); + proxy_input_iter<std::pair<int, int> const> last( + pairs.data() + pairs.size()); + for (auto out = firsts_copy.begin(); first != last; ++first) { + *out++ = first->first; + } + BOOST_TEST(firsts_copy == ints); + } +} + +{ + basic_input_iter first(ints.data()); + basic_input_iter last(ints.data() + ints.size()); + + auto r = range<boost::stl_interfaces::element_layout::discontiguous>( + first, last); + auto empty = + range<boost::stl_interfaces::element_layout::discontiguous>( + first, first); + + // range begin/end + { + std::array<int, 10> ints_copy; + std::copy(r.begin(), r.end(), ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + + BOOST_TEST(empty.begin() == empty.end()); + } +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/output.cpp b/src/boost/libs/stl_interfaces/test/output.cpp new file mode 100644 index 000000000..2144be574 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/output.cpp @@ -0,0 +1,130 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include <boost/core/lightweight_test.hpp> + +#include <array> +#include <numeric> +#include <vector> +#include <type_traits> + + +struct basic_output_iter + : boost::stl_interfaces:: + iterator_interface<basic_output_iter, std::output_iterator_tag, int> +{ + basic_output_iter() : it_(nullptr) {} + basic_output_iter(int * it) : it_(it) {} + + int & operator*() noexcept { return *it_; } + basic_output_iter & operator++() noexcept + { + ++it_; + return *this; + } + + using base_type = boost::stl_interfaces:: + iterator_interface<basic_output_iter, std::output_iterator_tag, int>; + using base_type::operator++; + +private: + int * it_; +}; + +using output = basic_output_iter; + +#if 201703L < __cplusplus && defined(__cpp_lib_concepts) +static_assert(std::output_iterator<output, int>, ""); +#endif +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + output, + std::output_iterator_tag, + std::output_iterator_tag, + int, + int &, + void, + std::ptrdiff_t) + +template<typename Container> +struct back_insert_iter : boost::stl_interfaces::iterator_interface< + back_insert_iter<Container>, + std::output_iterator_tag, + typename Container::value_type, + back_insert_iter<Container> &> +{ + back_insert_iter() : c_(nullptr) {} + back_insert_iter(Container & c) : c_(std::addressof(c)) {} + + back_insert_iter & operator*() noexcept { return *this; } + back_insert_iter & operator++() noexcept { return *this; } + + back_insert_iter & operator=(typename Container::value_type const & v) + { + c_->push_back(v); + return *this; + } + back_insert_iter & operator=(typename Container::value_type && v) + { + c_->push_back(std::move(v)); + return *this; + } + + using base_type = boost::stl_interfaces::iterator_interface< + back_insert_iter<Container>, + std::output_iterator_tag, + typename Container::value_type, + back_insert_iter<Container> &>; + using base_type::operator++; + +private: + Container * c_; +}; + +using back_insert = back_insert_iter<std::vector<int>>; + +#if 201703L < __cplusplus && defined(__cpp_lib_concepts) +static_assert(std::output_iterator<back_insert, int>, ""); +#endif +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + back_insert, + std::output_iterator_tag, + std::output_iterator_tag, + int, + back_insert &, + void, + std::ptrdiff_t) + + +std::vector<int> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + + +int main() +{ + +{ + std::vector<int> ints_copy(ints.size()); + std::copy(ints.begin(), ints.end(), output(&ints_copy[0])); + BOOST_TEST(ints_copy == ints); +} + + +{ + std::vector<int> ints_copy; + std::copy(ints.begin(), ints.end(), back_insert(ints_copy)); + BOOST_TEST(ints_copy == ints); +} + + +{ + std::vector<int> ints_copy; + back_insert out(ints_copy); + for (int i = 0; i < 10; ++i) + out++; +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/random_access.cpp b/src/boost/libs/stl_interfaces/test/random_access.cpp new file mode 100644 index 000000000..5e7416230 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/random_access.cpp @@ -0,0 +1,1035 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <algorithm> +#include <array> +#include <functional> +#include <numeric> +#include <tuple> +#include <type_traits> + + +struct basic_random_access_iter : boost::stl_interfaces::iterator_interface< + basic_random_access_iter, + std::random_access_iterator_tag, + int> +{ + basic_random_access_iter() {} + basic_random_access_iter(int * it) : it_(it) {} + + int & operator*() const { return *it_; } + basic_random_access_iter & operator+=(std::ptrdiff_t i) + { + it_ += i; + return *this; + } + friend std::ptrdiff_t operator-( + basic_random_access_iter lhs, basic_random_access_iter rhs) noexcept + { + return lhs.it_ - rhs.it_; + } + +private: + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_random_access_iter, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_random_access_iter, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +static_assert( + boost::stl_interfaces::v1::v1_dtl:: + plus_eq<basic_random_access_iter, std::ptrdiff_t>::value, + ""); + +struct basic_adapted_random_access_iter + : boost::stl_interfaces::iterator_interface< + basic_adapted_random_access_iter, + std::random_access_iterator_tag, + int> +{ + basic_adapted_random_access_iter() {} + basic_adapted_random_access_iter(int * it) : it_(it) {} + +private: + friend boost::stl_interfaces::access; + int *& base_reference() noexcept { return it_; } + int * base_reference() const noexcept { return it_; } + + int * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + basic_adapted_random_access_iter, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + basic_adapted_random_access_iter, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +template<typename ValueType> +struct adapted_random_access_iter : boost::stl_interfaces::iterator_interface< + adapted_random_access_iter<ValueType>, + std::random_access_iterator_tag, + ValueType> +{ + adapted_random_access_iter() {} + adapted_random_access_iter(ValueType * it) : it_(it) {} + + template< + typename ValueType2, + typename Enable = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + adapted_random_access_iter(adapted_random_access_iter<ValueType2> other) : + it_(other.it_) + {} + + template<typename ValueType2> + friend struct adapted_random_access_iter; + +private: + friend boost::stl_interfaces::access; + ValueType *& base_reference() noexcept { return it_; } + ValueType * base_reference() const noexcept { return it_; } + + ValueType * it_; +}; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + adapted_random_access_iter<int>, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + adapted_random_access_iter<int>, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + adapted_random_access_iter<int const>, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + adapted_random_access_iter<int const>, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int const &, + int const *, + std::ptrdiff_t) + +template<typename ValueType> +struct random_access_iter : boost::stl_interfaces::iterator_interface< + random_access_iter<ValueType>, + std::random_access_iterator_tag, + ValueType> +{ + random_access_iter() {} + random_access_iter(ValueType * it) : it_(it) {} + template< + typename ValueType2, + typename E = std::enable_if_t< + std::is_convertible<ValueType2 *, ValueType *>::value>> + random_access_iter(random_access_iter<ValueType2> it) : it_(it.it_) + {} + + ValueType & operator*() const { return *it_; } + random_access_iter & operator+=(std::ptrdiff_t i) + { + it_ += i; + return *this; + } + friend std::ptrdiff_t + operator-(random_access_iter lhs, random_access_iter rhs) noexcept + { + return lhs.it_ - rhs.it_; + } + +private: + ValueType * it_; + + template<typename ValueType2> + friend struct random_access_iter; +}; + +using random_access = random_access_iter<int>; +using const_random_access = random_access_iter<int const>; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + random_access, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + random_access, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int &, + int *, + std::ptrdiff_t) + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + const_random_access, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + const_random_access, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int, + int const &, + int const *, + std::ptrdiff_t) + +struct zip_iter : boost::stl_interfaces::proxy_iterator_interface< + zip_iter, + std::random_access_iterator_tag, + std::tuple<int, int>, + std::tuple<int &, int &>> +{ + zip_iter() : it1_(nullptr), it2_(nullptr) {} + zip_iter(int * it1, int * it2) : it1_(it1), it2_(it2) {} + + std::tuple<int &, int &> operator*() const + { + return std::tuple<int &, int &>{*it1_, *it2_}; + } + zip_iter & operator+=(std::ptrdiff_t i) + { + it1_ += i; + it2_ += i; + return *this; + } + friend std::ptrdiff_t operator-(zip_iter lhs, zip_iter rhs) noexcept + { + return lhs.it1_ - rhs.it1_; + } + +private: + int * it1_; + int * it2_; +}; + +using int_pair = std::tuple<int, int>; +using int_refs_pair = std::tuple<int &, int &>; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + zip_iter, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + zip_iter, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int_pair, + int_refs_pair, + boost::stl_interfaces::proxy_arrow_result<int_refs_pair>, + std::ptrdiff_t) + +struct int_t +{ + int value_; + + bool operator==(int_t other) const { return value_ == other.value_; } + bool operator!=(int_t other) const { return value_ != other.value_; } + bool operator<(int_t other) const { return value_ < other.value_; } + + bool operator==(int other) const { return value_ == other; } + bool operator!=(int other) const { return value_ != other; } + bool operator<(int other) const { return value_ < other; } + + friend bool operator==(int lhs, int_t rhs) { return lhs == rhs.value_; } + friend bool operator!=(int lhs, int_t rhs) { return lhs != rhs.value_; } + friend bool operator<(int lhs, int_t rhs) { return lhs < rhs.value_; } +}; + +struct udt_zip_iter : boost::stl_interfaces::proxy_iterator_interface< + udt_zip_iter, + std::random_access_iterator_tag, + std::tuple<int_t, int>, + std::tuple<int_t &, int &>> +{ + udt_zip_iter() : it1_(nullptr), it2_(nullptr) {} + udt_zip_iter(int_t * it1, int * it2) : it1_(it1), it2_(it2) {} + + std::tuple<int_t &, int &> operator*() const + { + return std::tuple<int_t &, int &>{*it1_, *it2_}; + } + udt_zip_iter & operator+=(std::ptrdiff_t i) + { + it1_ += i; + it2_ += i; + return *this; + } + friend std::ptrdiff_t operator-(udt_zip_iter lhs, udt_zip_iter rhs) noexcept + { + return lhs.it1_ - rhs.it1_; + } + +private: + int_t * it1_; + int * it2_; +}; + +using int_t_int_pair = std::tuple<int_t, int>; +using int_t_int_refs_pair = std::tuple<int_t &, int &>; + +BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT( + udt_zip_iter, std::random_access_iterator) +BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS( + udt_zip_iter, + std::random_access_iterator_tag, + std::random_access_iterator_tag, + int_t_int_pair, + int_t_int_refs_pair, + boost::stl_interfaces::proxy_arrow_result<int_t_int_refs_pair>, + std::ptrdiff_t) + +namespace std { + // Required for std::sort to work with zip_iter. If zip_iter::reference + // were not a std::tuple with builtin types as its template parameters, we + // could have put this in another namespace. + void swap(zip_iter::reference && lhs, zip_iter::reference && rhs) + { + using std::swap; + swap(std::get<0>(lhs), std::get<0>(rhs)); + swap(std::get<1>(lhs), std::get<1>(rhs)); + } +} + +void swap(udt_zip_iter::reference && lhs, udt_zip_iter::reference && rhs) +{ + using std::swap; + swap(std::get<0>(lhs), std::get<0>(rhs)); + swap(std::get<1>(lhs), std::get<1>(rhs)); +} + +std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; +std::array<int, 10> ones = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; +std::array<std::tuple<int, int>, 10> tuples = {{ + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {6, 1}, + {7, 1}, + {8, 1}, + {9, 1}, +}}; + +std::array<int_t, 10> udts = { + {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}}; +std::array<std::tuple<int_t, int>, 10> udt_tuples = {{ + std::tuple<int_t, int>{{0}, 1}, + std::tuple<int_t, int>{{1}, 1}, + std::tuple<int_t, int>{{2}, 1}, + std::tuple<int_t, int>{{3}, 1}, + std::tuple<int_t, int>{{4}, 1}, + std::tuple<int_t, int>{{5}, 1}, + std::tuple<int_t, int>{{6}, 1}, + std::tuple<int_t, int>{{7}, 1}, + std::tuple<int_t, int>{{8}, 1}, + std::tuple<int_t, int>{{9}, 1}, +}}; + + +//////////////////// +// view_interface // +//////////////////// +#include "view_tests.hpp" + +#if !defined(__cpp_lib_concepts) + +template<typename T> +using data_t = decltype(std::declval<T>().data()); + +static_assert( + ill_formed< + data_t, + subrange< + basic_random_access_iter, + basic_random_access_iter, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + data_t, + subrange< + basic_random_access_iter, + basic_random_access_iter, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +template<typename T> +using back_t = decltype(std::declval<T>().back()); + +static_assert( + ill_formed< + back_t, + subrange< + int *, + int const *, + boost::stl_interfaces::element_layout::discontiguous>>::value, + ""); +static_assert( + ill_formed< + back_t, + subrange< + int *, + int const *, + boost::stl_interfaces::element_layout::discontiguous> const>:: + value, + ""); + +#endif + + +int main() +{ + +{ + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + + BOOST_TEST(*first == 0); + BOOST_TEST(*(first + 1) == 1); + BOOST_TEST(*(first + 2) == 2); + BOOST_TEST(*(1 + first) == 1); + BOOST_TEST(*(2 + first) == 2); + + BOOST_TEST(first[0] == 0); + BOOST_TEST(first[1] == 1); + BOOST_TEST(first[2] == 2); + + BOOST_TEST(*(last - 1) == 9); + BOOST_TEST(*(last - 2) == 8); + BOOST_TEST(*(last - 3) == 7); + + BOOST_TEST(last[-1] == 9); + BOOST_TEST(last[-2] == 8); + BOOST_TEST(last[-3] == 7); + + BOOST_TEST(last - first == 10); + BOOST_TEST(first == first); + BOOST_TEST(first != last); + BOOST_TEST(first < last); + BOOST_TEST(first <= last); + BOOST_TEST(first <= first); + BOOST_TEST(last > first); + BOOST_TEST(last >= first); + BOOST_TEST(last >= last); + + { + auto first_copy = first; + first_copy += 10; + BOOST_TEST(first_copy == last); + } + + { + auto last_copy = last; + last_copy -= 10; + BOOST_TEST(last_copy == first); + } +} + + +{ + { + std::array<int, 10> ints_copy; + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + basic_random_access_iter first(iota_ints.data()); + basic_random_access_iter last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_random_access_iter first(iota_ints.data()); + basic_random_access_iter last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_random_access_iter first(iota_ints.data()); + basic_random_access_iter last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::sort(first, last); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + basic_adapted_random_access_iter first(ints.data()); + basic_adapted_random_access_iter last(ints.data() + ints.size()); + + BOOST_TEST(*first == 0); + BOOST_TEST(*(first + 1) == 1); + BOOST_TEST(*(first + 2) == 2); + BOOST_TEST(*(1 + first) == 1); + BOOST_TEST(*(2 + first) == 2); + + BOOST_TEST(first[0] == 0); + BOOST_TEST(first[1] == 1); + BOOST_TEST(first[2] == 2); + + BOOST_TEST(*(last - 1) == 9); + BOOST_TEST(*(last - 2) == 8); + BOOST_TEST(*(last - 3) == 7); + + BOOST_TEST(last[-1] == 9); + BOOST_TEST(last[-2] == 8); + BOOST_TEST(last[-3] == 7); + + BOOST_TEST(last - first == 10); + BOOST_TEST(first == first); + BOOST_TEST(first != last); + BOOST_TEST(first < last); + BOOST_TEST(first <= last); + BOOST_TEST(first <= first); + BOOST_TEST(last > first); + BOOST_TEST(last >= first); + BOOST_TEST(last >= last); + + { + auto first_copy = first; + first_copy += 10; + BOOST_TEST(first_copy == last); + } + + { + auto last_copy = last; + last_copy -= 10; + BOOST_TEST(last_copy == first); + } +} + + +{ + { + std::array<int, 10> ints_copy; + basic_adapted_random_access_iter first(ints.data()); + basic_adapted_random_access_iter last(ints.data() + ints.size()); + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + basic_adapted_random_access_iter first(ints.data()); + basic_adapted_random_access_iter last(ints.data() + ints.size()); + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + basic_adapted_random_access_iter first(iota_ints.data()); + basic_adapted_random_access_iter last( + iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_adapted_random_access_iter first(iota_ints.data()); + basic_adapted_random_access_iter last( + iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + basic_adapted_random_access_iter first(iota_ints.data()); + basic_adapted_random_access_iter last( + iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::sort(first, last); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + { + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + const_random_access first_copy(first); + const_random_access last_copy(last); + std::equal(first, last, first_copy, last_copy); + } + + { + adapted_random_access_iter<int> first(ints.data()); + adapted_random_access_iter<int> last(ints.data() + ints.size()); + adapted_random_access_iter<int const> first_copy( + (int const *)ints.data()); + adapted_random_access_iter<int const> last_copy( + (int const *)ints.data() + ints.size()); + std::equal(first, last, first_copy, last_copy); + } +} + + +{ + { + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + const_random_access first_const(first); + const_random_access last_const(last); + + BOOST_TEST(first == first_const); + BOOST_TEST(first_const == first); + BOOST_TEST(first != last_const); + BOOST_TEST(last_const != first); + BOOST_TEST(first <= first_const); + BOOST_TEST(first_const <= first); + BOOST_TEST(first >= first_const); + BOOST_TEST(first_const >= first); + BOOST_TEST(last_const > first); + BOOST_TEST(last > first_const); + BOOST_TEST(first_const < last); + BOOST_TEST(first < last_const); + } + + { + adapted_random_access_iter<int> first(ints.data()); + adapted_random_access_iter<int> last(ints.data() + ints.size()); + adapted_random_access_iter<int const> first_const(first); + adapted_random_access_iter<int const> last_const(last); + + BOOST_TEST(first == first_const); + BOOST_TEST(first_const == first); + BOOST_TEST(first != last_const); + BOOST_TEST(last_const != first); + BOOST_TEST(first <= first_const); + BOOST_TEST(first_const <= first); + BOOST_TEST(first >= first_const); + BOOST_TEST(first_const >= first); + BOOST_TEST(last_const > first); + BOOST_TEST(last > first_const); + BOOST_TEST(first_const < last); + BOOST_TEST(first < last_const); + } +} + + +{ + { + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + while (first != last) + first++; + } + + { + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + while (first != last) + last--; + } + + { + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + while (first != last) + first++; + } + + { + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + while (first != last) + last--; + } + + { + basic_adapted_random_access_iter first(ints.data()); + basic_adapted_random_access_iter last(ints.data() + ints.size()); + while (first != last) + first++; + } + + { + basic_adapted_random_access_iter first(ints.data()); + basic_adapted_random_access_iter last(ints.data() + ints.size()); + while (first != last) + last--; + } +} + + +{ + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + + BOOST_TEST(*first == 0); + BOOST_TEST(*(first + 1) == 1); + BOOST_TEST(*(first + 2) == 2); + BOOST_TEST(*(1 + first) == 1); + BOOST_TEST(*(2 + first) == 2); + + BOOST_TEST(first[0] == 0); + BOOST_TEST(first[1] == 1); + BOOST_TEST(first[2] == 2); + + BOOST_TEST(*(last - 1) == 9); + BOOST_TEST(*(last - 2) == 8); + BOOST_TEST(*(last - 3) == 7); + + BOOST_TEST(last[-1] == 9); + BOOST_TEST(last[-2] == 8); + BOOST_TEST(last[-3] == 7); + + BOOST_TEST(last - first == 10); + BOOST_TEST(first == first); + BOOST_TEST(first != last); + BOOST_TEST(first < last); + BOOST_TEST(first <= last); + BOOST_TEST(first <= first); + BOOST_TEST(last > first); + BOOST_TEST(last >= first); + BOOST_TEST(last >= last); + + { + auto first_copy = first; + first_copy += 10; + BOOST_TEST(first_copy == last); + } + + { + auto last_copy = last; + last_copy -= 10; + BOOST_TEST(last_copy == first); + } +} + + +{ + random_access first(ints.data()); + random_access last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> ints_copy; + std::copy( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + ints_copy.begin()); + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(ints_copy == ints); + } + + { + std::array<int, 10> iota_ints; + random_access first(iota_ints.data()); + random_access last(iota_ints.data() + iota_ints.size()); + std::iota(first, last, 0); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + random_access first(iota_ints.data()); + random_access last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::reverse(iota_ints.begin(), iota_ints.end()); + BOOST_TEST(iota_ints == ints); + } + + { + std::array<int, 10> iota_ints; + random_access first(iota_ints.data()); + random_access last(iota_ints.data() + iota_ints.size()); + std::iota( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 0); + std::sort(first, last); + BOOST_TEST(iota_ints == ints); + } +} + + +{ + const_random_access first(ints.data()); + const_random_access last(ints.data() + ints.size()); + + { + std::array<int, 10> ints_copy; + std::copy(first, last, ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + } + + { + BOOST_TEST(std::binary_search(first, last, 3)); + BOOST_TEST(std::binary_search( + std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + 3, + std::greater<>{})); + } +} + + +{ + { + zip_iter first(ints.data(), ones.data()); + zip_iter last(ints.data() + ints.size(), ones.data() + ones.size()); + BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end())); + } + + { + auto ints_copy = ints; + std::reverse(ints_copy.begin(), ints_copy.end()); + auto ones_copy = ones; + zip_iter first(ints_copy.data(), ones_copy.data()); + zip_iter last( + ints_copy.data() + ints_copy.size(), + ones_copy.data() + ones_copy.size()); + BOOST_TEST(!std::equal(first, last, tuples.begin(), tuples.end())); + std::sort(first, last); + BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end())); + } + + { + udt_zip_iter first(udts.data(), ones.data()); + udt_zip_iter last(udts.data() + udts.size(), ones.data() + ones.size()); + BOOST_TEST( + std::equal(first, last, udt_tuples.begin(), udt_tuples.end())); + } + + { + auto udts_copy = udts; + std::reverse(udts_copy.begin(), udts_copy.end()); + auto ones_copy = ones; + udt_zip_iter first(udts_copy.data(), ones_copy.data()); + udt_zip_iter last( + udts_copy.data() + udts_copy.size(), + ones_copy.data() + ones_copy.size()); + BOOST_TEST( + !std::equal(first, last, udt_tuples.begin(), udt_tuples.end())); + std::sort(first, last); + BOOST_TEST( + std::equal(first, last, udt_tuples.begin(), udt_tuples.end())); + } +} + +{ + basic_random_access_iter first(ints.data()); + basic_random_access_iter last(ints.data() + ints.size()); + + auto r = range<boost::stl_interfaces::element_layout::contiguous>( + first, last); + auto empty = range<boost::stl_interfaces::element_layout::contiguous>( + first, first); + + // range begin/end + { + std::array<int, 10> ints_copy; + std::copy(r.begin(), r.end(), ints_copy.begin()); + BOOST_TEST(ints_copy == ints); + + BOOST_TEST(empty.begin() == empty.end()); + } + + // empty/op bool + { + BOOST_TEST(!r.empty()); + BOOST_TEST(r); + + BOOST_TEST(empty.empty()); + BOOST_TEST(!empty); + + auto const cr = r; + BOOST_TEST(!cr.empty()); + BOOST_TEST(cr); + + auto const cempty = empty; + BOOST_TEST(cempty.empty()); + BOOST_TEST(!cempty); + } + + // TODO: Disabled for now, because std::to_address() appears to be broken + // in GCC10, which breaks the contiguous_iterator concept. + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96416 +#if !defined(__cpp_lib_concepts) + // data + { + BOOST_TEST(r.data() != nullptr); + BOOST_TEST(r.data()[2] == 2); + + BOOST_TEST(empty.data() != nullptr); + + auto const cr = r; + BOOST_TEST(cr.data() != nullptr); + BOOST_TEST(cr.data()[2] == 2); + + auto const cempty = empty; + BOOST_TEST(cempty.data() != nullptr); + } +#endif + + // size + { + BOOST_TEST(r.size() == 10u); + + BOOST_TEST(empty.size() == 0u); + + auto const cr = r; + BOOST_TEST(cr.size() == 10u); + + auto const cempty = empty; + BOOST_TEST(cempty.size() == 0u); + } + + // front/back + { + BOOST_TEST(r.front() == 0); + BOOST_TEST(r.back() == 9); + + auto const cr = r; + BOOST_TEST(cr.front() == 0); + BOOST_TEST(cr.back() == 9); + } + + // op[] + { + BOOST_TEST(r[2] == 2); + + auto const cr = r; + BOOST_TEST(cr[2] == 2); + } +} + + +{ + zip_iter first(ints.data(), ones.data()); + zip_iter last(ints.data() + ints.size(), ones.data() + ones.size()); + + auto r = range<boost::stl_interfaces::element_layout::discontiguous>( + first, last); + auto empty = + range<boost::stl_interfaces::element_layout::discontiguous>( + first, first); + + // range begin/end + { + BOOST_TEST(std::equal(first, last, tuples.begin(), tuples.end())); + } + + // empty/op bool + { + BOOST_TEST(!r.empty()); + BOOST_TEST(r); + + BOOST_TEST(empty.empty()); + BOOST_TEST(!empty); + + auto const cr = r; + BOOST_TEST(!cr.empty()); + BOOST_TEST(cr); + + auto const cempty = empty; + BOOST_TEST(cempty.empty()); + BOOST_TEST(!cempty); + } + + // size + { + BOOST_TEST(r.size() == 10u); + + BOOST_TEST(empty.size() == 0u); + + auto const cr = r; + BOOST_TEST(cr.size() == 10u); + + auto const cempty = empty; + BOOST_TEST(cempty.size() == 0u); + } + + // front/back + { + BOOST_TEST(r.front() == (std::tuple<int, int>(0, 1))); + BOOST_TEST(r.back() == (std::tuple<int, int>(9, 1))); + + auto const cr = r; + BOOST_TEST(cr.front() == (std::tuple<int, int>(0, 1))); + BOOST_TEST(cr.back() == (std::tuple<int, int>(9, 1))); + } + + // op[] + { + BOOST_TEST(r[2] == (std::tuple<int, int>(2, 1))); + + auto const cr = r; + BOOST_TEST(cr[2] == (std::tuple<int, int>(2, 1))); + } +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/reverse_iter.cpp b/src/boost/libs/stl_interfaces/test/reverse_iter.cpp new file mode 100644 index 000000000..661426c02 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/reverse_iter.cpp @@ -0,0 +1,243 @@ +// 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) +#include <boost/stl_interfaces/iterator_interface.hpp> +#include <boost/stl_interfaces/reverse_iterator.hpp> + +#include <boost/core/lightweight_test.hpp> + +#include <algorithm> +#include <array> +#include <list> +#include <tuple> +#include <vector> + + +struct zip_iter : boost::stl_interfaces::proxy_iterator_interface< + zip_iter, + std::random_access_iterator_tag, + std::tuple<int, int>, + std::tuple<int &, int &>> +{ + zip_iter() : it1_(nullptr), it2_(nullptr) {} + zip_iter(int * it1, int * it2) : it1_(it1), it2_(it2) {} + + std::tuple<int &, int &> operator*() const + { + return std::tuple<int &, int &>{*it1_, *it2_}; + } + zip_iter & operator+=(std::ptrdiff_t i) + { + it1_ += i; + it2_ += i; + return *this; + } + friend std::ptrdiff_t operator-(zip_iter lhs, zip_iter rhs) noexcept + { + return lhs.it1_ - rhs.it1_; + } + +private: + int * it1_; + int * it2_; +}; + + +int main() +{ + +{ + std::list<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + auto first = boost::stl_interfaces::make_reverse_iterator(ints.end()); + auto last = boost::stl_interfaces::make_reverse_iterator(ints.begin()); + + { + auto cfirst = boost::stl_interfaces::reverse_iterator< + std::list<int>::const_iterator>(first); + auto clast = boost::stl_interfaces::reverse_iterator< + std::list<int>::const_iterator>(last); + BOOST_TEST(std::equal(first, last, cfirst, clast)); + } + + { + auto ints_copy = ints; + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST( + std::equal(first, last, ints_copy.begin(), ints_copy.end())); + } + + { + std::list<int> ints_copy; + std::reverse_copy(first, last, std::back_inserter(ints_copy)); + BOOST_TEST(ints_copy == ints); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; ++it) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; it++) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; --it) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; it--) { + ++count; + } + BOOST_TEST(count == ints.size()); + } +} + + +{ + std::vector<int> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + auto first = boost::stl_interfaces::make_reverse_iterator(ints.end()); + auto last = boost::stl_interfaces::make_reverse_iterator(ints.begin()); + + { + auto cfirst = boost::stl_interfaces::reverse_iterator< + std::vector<int>::const_iterator>(first); + auto clast = boost::stl_interfaces::reverse_iterator< + std::vector<int>::const_iterator>(last); + BOOST_TEST(std::equal(first, last, cfirst, clast)); + } + + { + auto ints_copy = ints; + std::reverse(ints_copy.begin(), ints_copy.end()); + BOOST_TEST(first - last == ints_copy.begin() - ints_copy.end()); + BOOST_TEST( + std::equal(first, last, ints_copy.begin(), ints_copy.end())); + } + + { + std::vector<int> ints_copy; + std::reverse_copy(first, last, std::back_inserter(ints_copy)); + BOOST_TEST(ints_copy == ints); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; ++it) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; it++) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; --it) { + ++count; + } + BOOST_TEST(count == ints.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; it--) { + ++count; + } + BOOST_TEST(count == ints.size()); + } +} + + +{ + std::array<int, 10> ints = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; + std::array<int, 10> ones = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; + std::array<std::tuple<int, int>, 10> tuples = {{ + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {6, 1}, + {7, 1}, + {8, 1}, + {9, 1}, + }}; + + auto first = boost::stl_interfaces::make_reverse_iterator( + zip_iter(ints.data() + ints.size(), ones.data() + ones.size())); + auto last = boost::stl_interfaces::make_reverse_iterator( + zip_iter(ints.data(), ones.data())); + + { + auto tuples_copy = tuples; + std::reverse(tuples_copy.begin(), tuples_copy.end()); + BOOST_TEST(first - last == tuples_copy.begin() - tuples_copy.end()); + BOOST_TEST( + std::equal(first, last, tuples_copy.begin(), tuples_copy.end())); + } + + { + std::array<std::tuple<int, int>, 10> tuples_copy; + std::reverse_copy(first, last, tuples_copy.begin()); + BOOST_TEST(tuples_copy == tuples); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; ++it) { + ++count; + } + BOOST_TEST(count == tuples.size()); + } + + { + std::size_t count = 0; + for (auto it = first; it != last; it++) { + ++count; + } + BOOST_TEST(count == tuples.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; --it) { + ++count; + } + BOOST_TEST(count == tuples.size()); + } + + { + std::size_t count = 0; + for (auto it = last; it != first; it--) { + ++count; + } + BOOST_TEST(count == tuples.size()); + } +} + + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/static_vec.cpp b/src/boost/libs/stl_interfaces/test/static_vec.cpp new file mode 100644 index 000000000..755ed9f42 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/static_vec.cpp @@ -0,0 +1,773 @@ +// 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) +#include "../example/static_vector.hpp" + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <array> + +// Instantiate all the members we can. +template struct static_vector<int, 1024>; + +using vec_type = static_vector<int, 10>; + + +void test_default_ctor() +{ + vec_type v; + BOOST_TEST(v.empty()); + BOOST_TEST(v.size() == 0u); + + BOOST_TEST(v.max_size() == 10u); + BOOST_TEST(v.capacity() == 10u); + + BOOST_TEST(v == v); + BOOST_TEST(v <= v); + BOOST_TEST(v >= v); + + BOOST_TEST_THROWS(v.at(0), std::out_of_range); + + vec_type const & cv = v; + BOOST_TEST(cv.empty()); + BOOST_TEST(cv.size() == 0u); + + BOOST_TEST(cv.max_size() == 10u); + BOOST_TEST(cv.capacity() == 10u); + + BOOST_TEST(cv == cv); + BOOST_TEST(cv <= cv); + BOOST_TEST(cv >= cv); + + BOOST_TEST_THROWS(cv.at(0), std::out_of_range); +} + + +void test_other_ctors_assign_ctor() +{ + { + vec_type v(3); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + vec_type v2(std::initializer_list<int>{0, 0, 0}); + BOOST_TEST(v == v2); + } + + { + std::initializer_list<int> il{3, 2, 1}; + vec_type v(il); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v = il), vec_type &>::value, ""); + + vec_type v2; + v2 = il; + BOOST_TEST(v == v2); + } + + { + std::initializer_list<int> il{3, 2, 1}; + vec_type v; + v.assign(il); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v.assign(il)), void>::value, ""); + + vec_type v2; + v2 = il; + BOOST_TEST(v == v2); + } + + { + vec_type v(3, 4); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + vec_type v2 = {4, 4, 4}; + BOOST_TEST(v == v2); + } + + { + vec_type v; + v.assign(3, 4); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v.assign(3, 4)), void>::value, ""); + + vec_type v2 = {4, 4, 4}; + BOOST_TEST(v == v2); + } + + { + std::array<int, 3> a = {{1, 2, 3}}; + + vec_type v(a.begin(), a.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + vec_type v2 = {1, 2, 3}; + BOOST_TEST(v == v2); + } + + { + std::array<int, 3> a = {{1, 2, 3}}; + + vec_type v; + v.assign(a.begin(), a.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert( + std::is_same<decltype(v.assign(a.begin(), a.end())), void>::value, + ""); + + vec_type v2 = {1, 2, 3}; + BOOST_TEST(v == v2); + } +} + + +void test_resize() +{ + { + vec_type v; + + static_assert(std::is_same<decltype(v.resize(1)), void>::value, ""); + + v.resize(3); + BOOST_TEST(v == vec_type(3)); + + v.resize(6); + BOOST_TEST(v == vec_type(6)); + } + + { + vec_type v(6); + + v.resize(3); + BOOST_TEST(v == vec_type(3)); + + v.resize(0); + BOOST_TEST(v == vec_type{}); + } +} + + +void test_assignment_copy_move_equality() +{ + { + vec_type v2 = {4, 4, 4}; + + vec_type v(v2); + BOOST_TEST(v == v2); + } + + { + vec_type v; + vec_type v2 = {4, 4, 4}; + + static_assert(std::is_same<decltype(v = v2), vec_type &>::value, ""); + static_assert( + std::is_same<decltype(v = std::move(v2)), vec_type &>::value, ""); + + v = v2; + BOOST_TEST(v == v2); + } + + { + vec_type v2 = {4, 4, 4}; + + vec_type v(std::move(v2)); + BOOST_TEST(v == (vec_type(3, 4))); + BOOST_TEST(v2.empty()); + } + + { + vec_type v; + vec_type v2 = {4, 4, 4}; + + v = std::move(v2); + BOOST_TEST(v == (vec_type(3, 4))); + BOOST_TEST(v2.empty()); + } +} + + +void test_comparisons() +{ + vec_type sm = {1, 2, 3}; + vec_type md = {1, 2, 3, 4}; + vec_type lg = {1, 2, 3, 4, 5}; + + BOOST_TEST(sm == sm); + BOOST_TEST(!(sm == md)); + BOOST_TEST(!(sm == lg)); + + BOOST_TEST(!(sm != sm)); + BOOST_TEST(sm != md); + BOOST_TEST(sm != lg); + + BOOST_TEST(!(sm < sm)); + BOOST_TEST(sm < md); + BOOST_TEST(sm < lg); + + BOOST_TEST(sm <= sm); + BOOST_TEST(sm <= md); + BOOST_TEST(sm <= lg); + + BOOST_TEST(!(sm > sm)); + BOOST_TEST(!(sm > md)); + BOOST_TEST(!(sm > lg)); + + BOOST_TEST(sm >= sm); + BOOST_TEST(!(sm >= md)); + BOOST_TEST(!(sm >= lg)); + + + BOOST_TEST(!(md == sm)); + BOOST_TEST(md == md); + BOOST_TEST(!(md == lg)); + + BOOST_TEST(!(md < sm)); + BOOST_TEST(!(md < md)); + BOOST_TEST(md < lg); + + BOOST_TEST(!(md <= sm)); + BOOST_TEST(md <= md); + BOOST_TEST(md <= lg); + + BOOST_TEST(md > sm); + BOOST_TEST(!(md > md)); + BOOST_TEST(!(md > lg)); + + BOOST_TEST(md >= sm); + BOOST_TEST(md >= md); + BOOST_TEST(!(md >= lg)); + + + BOOST_TEST(!(lg == sm)); + BOOST_TEST(!(lg == md)); + BOOST_TEST(lg == lg); + + BOOST_TEST(!(lg < sm)); + BOOST_TEST(!(lg < md)); + BOOST_TEST(!(lg < lg)); + + BOOST_TEST(!(lg <= sm)); + BOOST_TEST(!(lg <= md)); + BOOST_TEST(lg <= lg); + + BOOST_TEST(lg > sm); + BOOST_TEST(lg > md); + BOOST_TEST(!(lg > lg)); + + BOOST_TEST(lg >= sm); + BOOST_TEST(lg >= md); + BOOST_TEST(lg >= lg); +} + + +void test_swap() +{ + { + vec_type v1(3, 4); + vec_type v2(4, 3); + + static_assert(std::is_same<decltype(v1.swap(v2)), void>::value, ""); + static_assert(std::is_same<decltype(swap(v1, v2)), void>::value, ""); + + v1.swap(v2); + + BOOST_TEST(v1.size() == 4u); + BOOST_TEST(v2.size() == 3u); + + BOOST_TEST(v1 == vec_type(4, 3)); + BOOST_TEST(v2 == vec_type(3, 4)); + } + + { + vec_type v1(3, 4); + vec_type v2(4, 3); + + swap(v1, v2); + + BOOST_TEST(v1.size() == 4u); + BOOST_TEST(v2.size() == 3u); + + BOOST_TEST(v1 == vec_type(4, 3)); + BOOST_TEST(v2 == vec_type(3, 4)); + } +} + +template<typename Iter> +using writable_iter_t = decltype( + *std::declval<Iter>() = + std::declval<typename std::iterator_traits<Iter>::value_type>()); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().begin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().end())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().cbegin())>:: + value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().cend())>:: + value, + ""); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().rbegin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().rend())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type &>().crbegin())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().crend())>:: + value, + ""); + +void test_iterators() +{ + { + vec_type v = {3, 2, 1}; + + static_assert( + std::is_same<decltype(v.begin()), vec_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.end()), vec_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.cbegin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), vec_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), vec_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + + std::array<int, 3> const a = {{3, 2, 1}}; + std::array<int, 3> const ra = {{1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + + *v.begin() = 8; + *v.rbegin() = 9; + BOOST_TEST(v == vec_type({8, 2, 9})); + } + + { + vec_type const v = {3, 2, 1}; + + static_assert( + std::is_same<decltype(v.begin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.end()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cbegin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + + std::array<int, 3> const a = {{3, 2, 1}}; + std::array<int, 3> const ra = {{1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + } +} + + +void test_emplace_insert() +{ + { + vec_type v; + + int const i = 0; + static_assert( + std::is_same<decltype(v.emplace_back(0)), vec_type::reference>:: + value, + ""); + static_assert( + std::is_same<decltype(v.emplace_back(i)), vec_type::reference>:: + value, + ""); + + v.emplace_back(i); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == i); + + v.emplace_back(1); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 1); + + v.emplace_back(2); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 2); + + BOOST_TEST(v == vec_type({0, 1, 2})); + } + + { + vec_type v = {1, 2}; + + int const i = 0; + static_assert( + std::is_same< + decltype(v.emplace(v.begin(), 0)), + vec_type::iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.emplace(v.begin(), i)), + vec_type::iterator>::value, + ""); + + v.emplace(v.begin(), i); + BOOST_TEST(v == vec_type({0, 1, 2})); + + v.emplace(v.end(), 3); + BOOST_TEST(v == vec_type({0, 1, 2, 3})); + + v.emplace(v.begin() + 2, 9); + BOOST_TEST(v == vec_type({0, 1, 9, 2, 3})); + } + + { + vec_type v = {1, 2}; + + std::array<int, 2> a1 = {{0, 0}}; + std::array<int, 1> a2 = {{3}}; + std::array<int, 3> a3 = {{9, 9, 9}}; + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), a1.begin(), a1.end())), + vec_type::iterator>::value, + ""); + + auto const it0 = v.insert(v.begin(), a1.begin(), a1.end()); + BOOST_TEST(v == vec_type({0, 0, 1, 2})); + BOOST_TEST(it0 == v.begin()); + + auto const it1 = v.insert(v.end(), a2.begin(), a2.end()); + BOOST_TEST(v == vec_type({0, 0, 1, 2, 3})); + BOOST_TEST(it1 == v.begin() + 4); + + auto const it2 = v.insert(v.begin() + 2, a3.begin(), a3.end()); + BOOST_TEST(v == vec_type({0, 0, 9, 9, 9, 1, 2, 3})); + BOOST_TEST(it2 == v.begin() + 2); + } + + { + vec_type v = {1, 2}; + + int const i = 0; + static_assert( + std::is_same<decltype(v.insert(v.begin(), 0)), vec_type::iterator>:: + value, + ""); + static_assert( + std::is_same<decltype(v.insert(v.begin(), i)), vec_type::iterator>:: + value, + ""); + + v.insert(v.begin(), i); + BOOST_TEST(v == vec_type({0, 1, 2})); + + v.insert(v.end(), 3); + BOOST_TEST(v == vec_type({0, 1, 2, 3})); + + v.insert(v.begin() + 2, 9); + BOOST_TEST(v == vec_type({0, 1, 9, 2, 3})); + } + + { + vec_type v = {1, 2}; + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), 3, 0)), + vec_type::iterator>::value, + ""); + + v.insert(v.begin(), 2, 0); + BOOST_TEST(v == vec_type({0, 0, 1, 2})); + + v.insert(v.end(), 1, 3); + BOOST_TEST(v == vec_type({0, 0, 1, 2, 3})); + + v.insert(v.begin() + 2, 3, 9); + BOOST_TEST(v == vec_type({0, 0, 9, 9, 9, 1, 2, 3})); + } + + { + vec_type v = {1, 2}; + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), std::initializer_list<int>{0, 0})), + vec_type::iterator>::value, + ""); + + v.insert(v.begin(), std::initializer_list<int>{0, 0}); + BOOST_TEST(v == vec_type({0, 0, 1, 2})); + + v.insert(v.end(), std::initializer_list<int>{3}); + BOOST_TEST(v == vec_type({0, 0, 1, 2, 3})); + + v.insert(v.begin() + 2, std::initializer_list<int>{9, 9, 9}); + BOOST_TEST(v == vec_type({0, 0, 9, 9, 9, 1, 2, 3})); + } +} + + +void test_erase() +{ + { + vec_type v = {3, 2, 1}; + + static_assert( + std::is_same< + decltype(v.erase(v.begin(), v.end())), + vec_type::iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.erase(v.begin())), vec_type::iterator>:: + value, + ""); + + v.erase(v.begin(), v.end()); + BOOST_TEST(v.empty()); + BOOST_TEST(v.size() == 0u); + } + + { + vec_type v = {3, 2, 1}; + v.erase(v.begin() + 1, v.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 1u); + BOOST_TEST(v == vec_type(1, 3)); + } + + { + vec_type v = {3, 2, 1}; + v.erase(v.begin(), v.end() - 1); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 1u); + BOOST_TEST(v == vec_type(1, 1)); + } + + { + vec_type v = {3, 2, 1}; + v.erase(v.begin()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v == vec_type({2, 1})); + } + + { + vec_type v = {3, 2, 1}; + v.erase(v.begin() + 1); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v == vec_type({3, 1})); + } + + { + vec_type v = {3, 2, 1}; + v.erase(v.begin() + 2); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v == vec_type({3, 2})); + } +} + +template< + typename Container, + typename ValueType = typename Container::value_type> +using lvalue_push_front_t = decltype( + std::declval<Container &>().push_front(std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using rvalue_push_front_t = decltype(std::declval<Container &>().push_front(0)); +template<typename Container> +using pop_front_t = decltype(std::declval<Container &>().pop_front()); + +static_assert(ill_formed<lvalue_push_front_t, vec_type>::value, ""); +static_assert(ill_formed<rvalue_push_front_t, vec_type>::value, ""); +static_assert(ill_formed<pop_front_t, vec_type>::value, ""); + +void test_front_back() +{ + { + vec_type v; + + int const i = 0; + static_assert(std::is_same<decltype(v.push_back(0)), void>::value, ""); + static_assert(std::is_same<decltype(v.push_back(i)), void>::value, ""); + static_assert(std::is_same<decltype(v.pop_back()), void>::value, ""); + + v.push_back(i); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == i); + + v.push_back(1); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 1); + + v.push_back(2); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 2); + + static_assert(std::is_same<decltype(v.front()), int &>::value, ""); + static_assert(std::is_same<decltype(v.back()), int &>::value, ""); + + v.front() = 9; + v.back() = 8; + BOOST_TEST(v == vec_type({9, 1, 8})); + + v.pop_back(); + BOOST_TEST(v == vec_type({9, 1})); + } + + { + vec_type const v = {3, 2, 1}; + BOOST_TEST(v.front() == 3); + BOOST_TEST(v.back() == 1); + + static_assert( + std::is_same<decltype(v.front()), int const &>::value, ""); + static_assert(std::is_same<decltype(v.back()), int const &>::value, ""); + } +} + + +void test_data_index_at() +{ + { + vec_type v = {3, 2, 1}; + BOOST_TEST(v.data()[0] == 3); + BOOST_TEST(v.data()[1] == 2); + BOOST_TEST(v.data()[2] == 1); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(3), std::out_of_range); + + static_assert(std::is_same<decltype(v.data()), int *>::value, ""); + static_assert(std::is_same<decltype(v[0]), int &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), int &>::value, ""); + + v[0] = 8; + v.at(1) = 9; + BOOST_TEST(v == vec_type({8, 9, 1})); + } + + { + vec_type const v = {3, 2, 1}; + BOOST_TEST(v.data()[0] == 3); + BOOST_TEST(v.data()[1] == 2); + BOOST_TEST(v.data()[2] == 1); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(3), std::out_of_range); + + static_assert(std::is_same<decltype(v.data()), int const *>::value, ""); + static_assert(std::is_same<decltype(v[0]), int const &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), int const &>::value, ""); + } +} + +int main() +{ + test_default_ctor(); + test_other_ctors_assign_ctor(); + test_resize(); + test_assignment_copy_move_equality(); + test_comparisons(); + test_swap(); + test_iterators(); + test_emplace_insert(); + test_erase(); + test_front_back(); + test_data_index_at(); + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/static_vec_noncopyable.cpp b/src/boost/libs/stl_interfaces/test/static_vec_noncopyable.cpp new file mode 100644 index 000000000..2ea477f5b --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/static_vec_noncopyable.cpp @@ -0,0 +1,921 @@ +// 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) +#include "../example/static_vector.hpp" + +#include "ill_formed.hpp" + +#include <boost/core/lightweight_test.hpp> + +#include <array> + + +struct noncopyable_int +{ + noncopyable_int() : value_(0) {} + + noncopyable_int(noncopyable_int const &) = delete; + noncopyable_int(noncopyable_int && other) : value_(other.value_) {} + noncopyable_int & operator=(noncopyable_int const &) = delete; + noncopyable_int & operator=(noncopyable_int && rhs) + { + value_ = rhs.value_; + return *this; + } + + noncopyable_int(int i) : value_(i) {} + noncopyable_int & operator=(int i) + { + value_ = i; + return *this; + } + + operator int() const { return value_; } + + int value_; +}; + +void swap(noncopyable_int & x, noncopyable_int & y) +{ + std::swap(x.value_, y.value_); +} + +#define USE_STD_VECTOR 0 + +#if USE_STD_VECTOR +using vec_type = std::vector<noncopyable_int>; +#else +using vec_type = static_vector<noncopyable_int, 10>; +#endif + + +void test_default_ctor() +{ + vec_type v; + BOOST_TEST(v.empty()); + BOOST_TEST(v.size() == 0u); + +#if !USE_STD_VECTOR + BOOST_TEST(v.max_size() == 10u); + BOOST_TEST(v.capacity() == 10u); +#endif + + BOOST_TEST(v == v); + BOOST_TEST(v <= v); + BOOST_TEST(v >= v); + + BOOST_TEST_THROWS(v.at(0), std::out_of_range); + + vec_type const & cv = v; + BOOST_TEST(cv.empty()); + BOOST_TEST(cv.size() == 0u); + +#if !USE_STD_VECTOR + BOOST_TEST(cv.max_size() == 10u); + BOOST_TEST(cv.capacity() == 10u); +#endif + + BOOST_TEST(cv == cv); + BOOST_TEST(cv <= cv); + BOOST_TEST(cv >= cv); + + BOOST_TEST_THROWS(cv.at(0), std::out_of_range); +} + + +void test_other_ctors_assign_ctor() +{ + { + vec_type v(3); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + } + +#if 0 // initializer_list construction is not supported for move-only value_type. + vec_type v2(std::initializer_list<noncopyable_int>{0, 0, 0}); + BOOST_TEST(v == v2); + + { + std::initializer_list<noncopyable_int> il{3, 2, 1}; + vec_type v(il); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v = il), vec_type &>::value, ""); + + vec_type v2; + v2 = il; + BOOST_TEST(v == v2); + } + + { + std::initializer_list<noncopyable_int> il{3, 2, 1}; + vec_type v; + v.assign(il); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v.assign(il)), void>::value, ""); + + vec_type v2; + v2 = il; + BOOST_TEST(v == v2); + } +#endif + +#if 0 // Code that boils down to fill-insert is not supported for move-only value_type. + { + vec_type v(3, 4); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + vec_type v2 = {4, 4, 4}; + BOOST_TEST(v == v2); + } + + { + vec_type v; + v.assign(3, 4); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert(std::is_same<decltype(v.assign(3, 4)), void>::value, ""); + + vec_type v2 = {4, 4, 4}; + BOOST_TEST(v == v2); + } +#endif + + { + std::array<int, 3> a = {{1, 2, 3}}; + + vec_type v(a.begin(), a.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + vec_type v2; + v2.push_back(1); + v2.push_back(2); + v2.push_back(3); + BOOST_TEST(v == v2); + } + + { + std::array<int, 3> a = {{1, 2, 3}}; + + vec_type v; + v.assign(a.begin(), a.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 3u); + + static_assert( + std::is_same<decltype(v.assign(a.begin(), a.end())), void>::value, + ""); + + vec_type v2; + v2.push_back(1); + v2.push_back(2); + v2.push_back(3); + BOOST_TEST(v == v2); + } +} + + +void test_resize() +{ + { + vec_type v; + + static_assert(std::is_same<decltype(v.resize(1)), void>::value, ""); + + v.resize(3); + BOOST_TEST(v == vec_type(3)); + + v.resize(6); + BOOST_TEST(v == vec_type(6)); + } + + { + vec_type v(6); + + v.resize(3); + BOOST_TEST(v == vec_type(3)); + + v.resize(0); + BOOST_TEST(v == vec_type{}); + } +} + + +void test_assignment_copy_move_equality() +{ + { + vec_type v2; + v2.push_back(4); + v2.push_back(4); + v2.push_back(4); + + vec_type v(std::move(v2)); + BOOST_TEST(v[0] == 4); + BOOST_TEST(v[1] == 4); + BOOST_TEST(v[2] == 4); + BOOST_TEST(v2.empty()); + } + + { + vec_type v; + vec_type v2; + v2.push_back(4); + v2.push_back(4); + v2.push_back(4); + + v = std::move(v2); + BOOST_TEST(v[0] == 4); + BOOST_TEST(v[1] == 4); + BOOST_TEST(v[2] == 4); + BOOST_TEST(v2.empty()); + } +} + + +void test_comparisons() +{ + vec_type sm; + sm.push_back(1); + sm.push_back(2); + sm.push_back(3); + vec_type md; + md.push_back(1); + md.push_back(2); + md.push_back(3); + md.push_back(4); + vec_type lg; + lg.push_back(1); + lg.push_back(2); + lg.push_back(3); + lg.push_back(4); + lg.push_back(5); + + BOOST_TEST(sm == sm); + BOOST_TEST(!(sm == md)); + BOOST_TEST(!(sm == lg)); + + BOOST_TEST(!(sm != sm)); + BOOST_TEST(sm != md); + BOOST_TEST(sm != lg); + + BOOST_TEST(!(sm < sm)); + BOOST_TEST(sm < md); + BOOST_TEST(sm < lg); + + BOOST_TEST(sm <= sm); + BOOST_TEST(sm <= md); + BOOST_TEST(sm <= lg); + + BOOST_TEST(!(sm > sm)); + BOOST_TEST(!(sm > md)); + BOOST_TEST(!(sm > lg)); + + BOOST_TEST(sm >= sm); + BOOST_TEST(!(sm >= md)); + BOOST_TEST(!(sm >= lg)); + + + BOOST_TEST(!(md == sm)); + BOOST_TEST(md == md); + BOOST_TEST(!(md == lg)); + + BOOST_TEST(!(md < sm)); + BOOST_TEST(!(md < md)); + BOOST_TEST(md < lg); + + BOOST_TEST(!(md <= sm)); + BOOST_TEST(md <= md); + BOOST_TEST(md <= lg); + + BOOST_TEST(md > sm); + BOOST_TEST(!(md > md)); + BOOST_TEST(!(md > lg)); + + BOOST_TEST(md >= sm); + BOOST_TEST(md >= md); + BOOST_TEST(!(md >= lg)); + + + BOOST_TEST(!(lg == sm)); + BOOST_TEST(!(lg == md)); + BOOST_TEST(lg == lg); + + BOOST_TEST(!(lg < sm)); + BOOST_TEST(!(lg < md)); + BOOST_TEST(!(lg < lg)); + + BOOST_TEST(!(lg <= sm)); + BOOST_TEST(!(lg <= md)); + BOOST_TEST(lg <= lg); + + BOOST_TEST(lg > sm); + BOOST_TEST(lg > md); + BOOST_TEST(!(lg > lg)); + + BOOST_TEST(lg >= sm); + BOOST_TEST(lg >= md); + BOOST_TEST(lg >= lg); +} + + +void test_swap() +{ + { + vec_type v1; + v1.push_back(4); + v1.push_back(4); + v1.push_back(4); + vec_type v2; + v2.push_back(3); + v2.push_back(3); + v2.push_back(3); + v2.push_back(3); + + static_assert(std::is_same<decltype(v1.swap(v2)), void>::value, ""); + static_assert(std::is_same<decltype(swap(v1, v2)), void>::value, ""); + + v1.swap(v2); + + BOOST_TEST(v1.size() == 4u); + BOOST_TEST(v2.size() == 3u); + + BOOST_TEST(v1[0] == 3); + BOOST_TEST(v2[0] == 4); + } + + { + vec_type v1; + v1.push_back(4); + v1.push_back(4); + v1.push_back(4); + vec_type v2; + v2.push_back(3); + v2.push_back(3); + v2.push_back(3); + v2.push_back(3); + + swap(v1, v2); + + BOOST_TEST(v1.size() == 4u); + BOOST_TEST(v2.size() == 3u); + + BOOST_TEST(v1[0] == 3); + BOOST_TEST(v2[0] == 4); + } +} + +template<typename Iter> +using writable_iter_t = decltype( + *std::declval<Iter>() = + std::declval<typename std::iterator_traits<Iter>::value_type>()); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().begin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().end())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().cbegin())>:: + value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().cend())>:: + value, + ""); + +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().rbegin())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type const &>().rend())>::value, + ""); +static_assert( + ill_formed< + writable_iter_t, + decltype(std::declval<vec_type &>().crbegin())>::value, + ""); +static_assert( + ill_formed<writable_iter_t, decltype(std::declval<vec_type &>().crend())>:: + value, + ""); + +void test_iterators() +{ + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + + static_assert( + std::is_same<decltype(v.begin()), vec_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.end()), vec_type::iterator>::value, ""); + static_assert( + std::is_same<decltype(v.cbegin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), vec_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same<decltype(v.rbegin()), vec_type::reverse_iterator>:: + value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + + std::array<int, 3> const a = {{3, 2, 1}}; + std::array<int, 3> const ra = {{1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + + *v.begin() = 8; + *v.rbegin() = 9; + BOOST_TEST(v[0] == 8); + BOOST_TEST(v[2] == 9); + } + + { + vec_type v_; + v_.push_back(3); + v_.push_back(2); + v_.push_back(1); + vec_type const & v = v_; + + static_assert( + std::is_same<decltype(v.begin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.end()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cbegin()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.cend()), vec_type::const_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.rbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.crbegin()), + vec_type::const_reverse_iterator>::value, + ""); + + std::array<int, 3> const a = {{3, 2, 1}}; + std::array<int, 3> const ra = {{1, 2, 3}}; + + BOOST_TEST(std::equal(v.begin(), v.end(), a.begin(), a.end())); + BOOST_TEST(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); + + BOOST_TEST(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); + BOOST_TEST(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); + } +} + + +void test_emplace_insert() +{ + { + vec_type v; + + int const i = 0; + static_assert( + std::is_same<decltype(v.emplace_back(0)), vec_type::reference>:: + value, + ""); + static_assert( + std::is_same<decltype(v.emplace_back(i)), vec_type::reference>:: + value, + ""); + + v.emplace_back(i); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == i); + + v.emplace_back(1); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 1); + + v.emplace_back(2); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 2); + + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 2); + } + + { + vec_type v; + v.push_back(1); + v.push_back(2); + + int const i = 0; + static_assert( + std::is_same< + decltype(v.emplace(v.begin(), 0)), + vec_type::iterator>::value, + ""); + static_assert( + std::is_same< + decltype(v.emplace(v.begin(), i)), + vec_type::iterator>::value, + ""); + + v.emplace(v.begin(), i); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 2); + + v.emplace(v.end(), 3); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 2); + BOOST_TEST(v[3] == 3); + + v.emplace(v.begin() + 2, 9); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 9); + BOOST_TEST(v[3] == 2); + BOOST_TEST(v[4] == 3); + } + + { + vec_type v; + v.push_back(1); + v.push_back(2); + + std::array<int, 2> a1 = {{0, 0}}; + std::array<int, 1> a2 = {{3}}; + std::array<int, 3> a3 = {{9, 9, 9}}; + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), a1.begin(), a1.end())), + vec_type::iterator>::value, + ""); + + auto const it0 = v.insert(v.begin(), a1.begin(), a1.end()); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 0); + BOOST_TEST(v[2] == 1); + BOOST_TEST(v[3] == 2); + BOOST_TEST(it0 == v.begin()); + + auto const it1 = v.insert(v.end(), a2.begin(), a2.end()); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 0); + BOOST_TEST(v[2] == 1); + BOOST_TEST(v[3] == 2); + BOOST_TEST(v[4] == 3); + BOOST_TEST(it1 == v.begin() + 4); + + auto const it2 = v.insert(v.begin() + 2, a3.begin(), a3.end()); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 0); + BOOST_TEST(v[2] == 9); + BOOST_TEST(v[3] == 9); + BOOST_TEST(v[4] == 9); + BOOST_TEST(v[5] == 1); + BOOST_TEST(v[6] == 2); + BOOST_TEST(v[7] == 3); + BOOST_TEST(it2 == v.begin() + 2); + } + + { + vec_type v; + v.push_back(1); + v.push_back(2); + + int const i = 0; + static_assert( + std::is_same<decltype(v.insert(v.begin(), 0)), vec_type::iterator>:: + value, + ""); + static_assert( + std::is_same<decltype(v.insert(v.begin(), i)), vec_type::iterator>:: + value, + ""); + + v.emplace(v.begin(), i); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 2); + + v.emplace(v.end(), 3); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 2); + BOOST_TEST(v[3] == 3); + + v.emplace(v.begin() + 2, 9); + BOOST_TEST(v[0] == 0); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 9); + BOOST_TEST(v[3] == 2); + BOOST_TEST(v[4] == 3); + } + +#if 0 // Fill-insert is not supported for move-only value_type. + { + vec_type v; + v.push_back(1); + v.push_back(2); + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), 3, 0)), + vec_type::iterator>::value, + ""); + + v.insert(v.begin(), 2, 0); + v.insert(v.end(), 1, 3); + v.insert(v.begin() + 2, 3, 9); + } +#endif + +#if 0 // initializer_list-insert is not supported for move-only value_type. + { + vec_type v; + v.push_back(1); + v.push_back(2); + + static_assert( + std::is_same< + decltype(v.insert(v.begin(), std::initializer_list<noncopyable_int>{0, 0})), + vec_type::iterator>::value, + ""); + + v.insert(v.begin(), std::initializer_list<noncopyable_int>{0, 0}); + v.insert(v.end(), std::initializer_list<noncopyable_int>{3}); + v.insert(v.begin() + 2, std::initializer_list<noncopyable_int>{9, 9, 9}); + } +#endif +} + + +void test_erase() +{ + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + + static_assert( + std::is_same< + decltype(v.erase(v.begin(), v.end())), + vec_type::iterator>::value, + ""); + static_assert( + std::is_same<decltype(v.erase(v.begin())), vec_type::iterator>:: + value, + ""); + + v.erase(v.begin(), v.end()); + BOOST_TEST(v.empty()); + BOOST_TEST(v.size() == 0u); + } + + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + v.erase(v.begin() + 1, v.end()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 1u); + BOOST_TEST(v[0] == 3); + } + + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + v.erase(v.begin(), v.end() - 1); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 1u); + BOOST_TEST(v[0] == 1); + } + + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + v.erase(v.begin()); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v[0] == 2); + BOOST_TEST(v[1] == 1); + } + + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + v.erase(v.begin() + 1); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 1); + } + + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + v.erase(v.begin() + 2); + BOOST_TEST(!v.empty()); + BOOST_TEST(v.size() == 2u); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + } +} + +template< + typename Container, + typename ValueType = typename Container::value_type> +using lvalue_push_front_t = decltype( + std::declval<Container &>().push_front(std::declval<ValueType const &>())); +template< + typename Container, + typename ValueType = typename Container::value_type> +using rvalue_push_front_t = decltype(std::declval<Container &>().push_front(0)); +template<typename Container> +using pop_front_t = decltype(std::declval<Container &>().pop_front()); + +static_assert(ill_formed<lvalue_push_front_t, vec_type>::value, ""); +static_assert(ill_formed<rvalue_push_front_t, vec_type>::value, ""); +static_assert(ill_formed<pop_front_t, vec_type>::value, ""); + +void test_front_back() +{ + { + vec_type v; + + int const i = 0; + static_assert(std::is_same<decltype(v.push_back(0)), void>::value, ""); + static_assert(std::is_same<decltype(v.push_back(i)), void>::value, ""); + static_assert(std::is_same<decltype(v.pop_back()), void>::value, ""); + + v.emplace_back(i); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == i); + + v.emplace_back(1); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 1); + + v.emplace_back(2); + BOOST_TEST(v.front() == i); + BOOST_TEST(v.back() == 2); + + static_assert(std::is_same<decltype(v.front()), noncopyable_int &>::value, ""); + static_assert(std::is_same<decltype(v.back()), noncopyable_int &>::value, ""); + + v.front() = 9; + v.back() = 8; + BOOST_TEST(v[0] == 9); + BOOST_TEST(v[1] == 1); + BOOST_TEST(v[2] == 8); + + v.pop_back(); + BOOST_TEST(v[0] == 9); + BOOST_TEST(v[1] == 1); + } + + { + vec_type v_; + v_.push_back(3); + v_.push_back(2); + v_.push_back(1); + vec_type const & v = v_; + BOOST_TEST(v.front() == 3); + BOOST_TEST(v.back() == 1); + + static_assert( + std::is_same<decltype(v.front()), noncopyable_int const &>::value, ""); + static_assert(std::is_same<decltype(v.back()), noncopyable_int const &>::value, ""); + } +} + + +void test_data_index_at() +{ + { + vec_type v; + v.push_back(3); + v.push_back(2); + v.push_back(1); + BOOST_TEST(v.data()[0] == 3); + BOOST_TEST(v.data()[1] == 2); + BOOST_TEST(v.data()[2] == 1); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(3), std::out_of_range); + + static_assert(std::is_same<decltype(v.data()), noncopyable_int *>::value, ""); + static_assert(std::is_same<decltype(v[0]), noncopyable_int &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), noncopyable_int &>::value, ""); + + v[0] = 8; + v.at(1) = 9; + BOOST_TEST(v[0] == 8); + BOOST_TEST(v[1] == 9); + BOOST_TEST(v[2] == 1); + } + + { + vec_type v_; + v_.push_back(3); + v_.push_back(2); + v_.push_back(1); + vec_type const & v = v_; + BOOST_TEST(v.data()[0] == 3); + BOOST_TEST(v.data()[1] == 2); + BOOST_TEST(v.data()[2] == 1); + BOOST_TEST(v[0] == 3); + BOOST_TEST(v[1] == 2); + BOOST_TEST(v[2] == 1); + BOOST_TEST_NO_THROW(v.at(0)); + BOOST_TEST_NO_THROW(v.at(1)); + BOOST_TEST_NO_THROW(v.at(2)); + BOOST_TEST_THROWS(v.at(3), std::out_of_range); + + static_assert(std::is_same<decltype(v.data()), noncopyable_int const *>::value, ""); + static_assert(std::is_same<decltype(v[0]), noncopyable_int const &>::value, ""); + static_assert(std::is_same<decltype(v.at(0)), noncopyable_int const &>::value, ""); + } +} + +int main() +{ + test_default_ctor(); + test_other_ctors_assign_ctor(); + test_resize(); + test_assignment_copy_move_equality(); + test_comparisons(); + test_swap(); + test_iterators(); + test_emplace_insert(); + test_erase(); + test_front_back(); + test_data_index_at(); + return boost::report_errors(); +} diff --git a/src/boost/libs/stl_interfaces/test/view_tests.hpp b/src/boost/libs/stl_interfaces/test/view_tests.hpp new file mode 100644 index 000000000..124abc3e2 --- /dev/null +++ b/src/boost/libs/stl_interfaces/test/view_tests.hpp @@ -0,0 +1,40 @@ +// 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 BOOST_STL_INTERFACES_VIEW_TESTING_HPP +#define BOOST_STL_INTERFACES_VIEW_TESTING_HPP + +#include <boost/stl_interfaces/view_interface.hpp> + + +template< + typename Iterator, + typename Sentinel, + boost::stl_interfaces::element_layout Contiguity> +struct subrange + : boost::stl_interfaces:: + view_interface<subrange<Iterator, Sentinel, Contiguity>, Contiguity> +{ + subrange() = default; + constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {} + + constexpr auto begin() const { return first_; } + constexpr auto end() const { return last_; } + +private: + Iterator first_; + Sentinel last_; +}; + +template< + boost::stl_interfaces::element_layout Contiguity, + typename Iterator, + typename Sentinel> +auto range(Iterator i, Sentinel s) +{ + return subrange<Iterator, Sentinel, Contiguity>(i, s); +} + +#endif |