summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/stl_interfaces
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/boost/libs/stl_interfaces
parentInitial commit. (diff)
downloadceph-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')
-rw-r--r--src/boost/libs/stl_interfaces/CMakeLists.txt107
-rw-r--r--src/boost/libs/stl_interfaces/LICENSE_1_0.txt23
-rw-r--r--src/boost/libs/stl_interfaces/README.md199
-rw-r--r--src/boost/libs/stl_interfaces/cmake/dependencies.cmake40
-rw-r--r--src/boost/libs/stl_interfaces/example/CMakeLists.txt35
-rw-r--r--src/boost/libs/stl_interfaces/example/back_insert_iterator.cpp79
-rw-r--r--src/boost/libs/stl_interfaces/example/drop_while_view.cpp137
-rw-r--r--src/boost/libs/stl_interfaces/example/filtered_int_iterator.cpp92
-rw-r--r--src/boost/libs/stl_interfaces/example/interoperability.cpp87
-rw-r--r--src/boost/libs/stl_interfaces/example/node_iterator.cpp90
-rw-r--r--src/boost/libs/stl_interfaces/example/random_access_iterator.cpp55
-rw-r--r--src/boost/libs/stl_interfaces/example/repeated_chars_iterator.cpp60
-rw-r--r--src/boost/libs/stl_interfaces/example/reverse_iterator.cpp124
-rw-r--r--src/boost/libs/stl_interfaces/example/static_vector.cpp23
-rw-r--r--src/boost/libs/stl_interfaces/example/static_vector.hpp282
-rw-r--r--src/boost/libs/stl_interfaces/example/zip_proxy_iterator.cpp119
-rw-r--r--src/boost/libs/stl_interfaces/index.html17
-rw-r--r--src/boost/libs/stl_interfaces/meta/libraries.json9
-rwxr-xr-xsrc/boost/libs/stl_interfaces/test/CMakeLists.txt55
-rw-r--r--src/boost/libs/stl_interfaces/test/Jamfile.v228
-rw-r--r--src/boost/libs/stl_interfaces/test/array.cpp586
-rw-r--r--src/boost/libs/stl_interfaces/test/bidirectional.cpp669
-rw-r--r--src/boost/libs/stl_interfaces/test/compile_seq_cont_rvalue_constrained_pop_back.cpp116
-rw-r--r--src/boost/libs/stl_interfaces/test/compile_tests_main.cpp11
-rw-r--r--src/boost/libs/stl_interfaces/test/detail.cpp103
-rw-r--r--src/boost/libs/stl_interfaces/test/forward.cpp342
-rw-r--r--src/boost/libs/stl_interfaces/test/ill_formed.hpp17
-rw-r--r--src/boost/libs/stl_interfaces/test/input.cpp395
-rw-r--r--src/boost/libs/stl_interfaces/test/output.cpp130
-rw-r--r--src/boost/libs/stl_interfaces/test/random_access.cpp1035
-rw-r--r--src/boost/libs/stl_interfaces/test/reverse_iter.cpp243
-rw-r--r--src/boost/libs/stl_interfaces/test/static_vec.cpp773
-rw-r--r--src/boost/libs/stl_interfaces/test/static_vec_noncopyable.cpp921
-rw-r--r--src/boost/libs/stl_interfaces/test/view_tests.hpp40
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