-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added to_array * Suppress unused warnings * Fix unused warnings (2) * Workaround msvc 14.0 bug * Workaround MSVC problems with moving arrays * MSVC workaround in constexpr test * Further MSVC fixes * Disable rvalue tests for MSVC 14.0 * Incorrect argument spec * constexpr checks * const test * Disable rvalues for msvc 14.1 * Docs * Added more const tests * Correct static_asserts * Update type requirements in docs * Corrected return types and conditions * Doc updates
- Loading branch information
Showing
6 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
//// | ||
Copyright 2024 Ruben Perez Hidalgo | ||
Distributed under the Boost Software License, Version 1.0. | ||
https://www.boost.org/LICENSE_1_0.txt | ||
//// | ||
|
||
[#to_array] | ||
# <boost/compat/to_array.hpp> | ||
:idprefix: ref_to_array_ | ||
|
||
## Description | ||
|
||
The header `<boost/compat/to_array.hpp>` implements, in a portable way, the C++20 | ||
`std::to_array` function, present in the `<array>` header. | ||
|
||
`to_array` creates a `std::array` from a single-dimensional C array, | ||
performing an element-wise copy or move. | ||
|
||
## Example | ||
|
||
```cpp | ||
int input [] = {1, 2, 3}; | ||
std::array<int, 3> output = boost::compat::to_array(input); | ||
assert(( | ||
output == std::array<int, 3>{{1, 2, 3}} | ||
)); | ||
``` | ||
|
||
## Synopsis | ||
|
||
```cpp | ||
namespace boost | ||
{ | ||
namespace compat | ||
{ | ||
|
||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]); | ||
|
||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]); | ||
|
||
} // namespace compat | ||
} // namespace boost | ||
``` | ||
|
||
## to_array | ||
|
||
```cpp | ||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]); | ||
``` | ||
|
||
[horizontal] | ||
Effects:;; Creates an array of `N` elements by copying elements in `a`. | ||
For every `i` in `0, ..., N-1`, copy-initializes the i-th element | ||
in the output array from `a[i]`. | ||
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&> && !std::is_array_v<T>`. | ||
Otherwise, the overload is ill-formed. | ||
|
||
|
||
```cpp | ||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cvref_t<T>, N> to_array(T (&a)[N]); | ||
``` | ||
|
||
[horizontal] | ||
Effects:;; Creates an array of `N` elements by moving elements in `a`. | ||
For every `i` in `0, ..., N-1`, move-initializes the i-th element | ||
in the output array from `std::move(a[i])`. | ||
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&&> && !std::is_array_v<T>`. | ||
Otherwise, the overload is ill-formed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#ifndef BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED | ||
#define BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED | ||
|
||
// Copyright 2024 Ruben Perez Hidalgo | ||
// Distributed under the Boost Software License, Version 1.0. | ||
// https://www.boost.org/LICENSE_1_0.txt | ||
|
||
#include <boost/compat/integer_sequence.hpp> | ||
#include <boost/compat/type_traits.hpp> | ||
|
||
#include <array> | ||
#include <cstddef> | ||
#include <type_traits> | ||
#include <utility> | ||
|
||
namespace boost { | ||
namespace compat { | ||
|
||
namespace detail { | ||
|
||
template <class T, std::size_t N, std::size_t... I> | ||
constexpr std::array<remove_cv_t<T>, N> to_array_lvalue(T (&a)[N], index_sequence<I...>) | ||
{ | ||
return {{a[I]...}}; | ||
} | ||
|
||
template <class T, std::size_t N, std::size_t... I> | ||
constexpr std::array<remove_cv_t<T>, N> to_array_rvalue(T (&&a)[N], index_sequence<I...>) | ||
{ | ||
return {{std::move(a[I])...}}; | ||
} | ||
|
||
} // namespace detail | ||
|
||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]) | ||
{ | ||
static_assert( | ||
std::is_constructible<remove_cv_t<T>, T&>::value, | ||
"This overload requires the resulting element type to be constructible from T&" | ||
); | ||
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays"); | ||
return detail::to_array_lvalue(a, make_index_sequence<N>{}); | ||
} | ||
|
||
template <class T, std::size_t N> | ||
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]) | ||
{ | ||
static_assert( | ||
std::is_constructible<remove_cv_t<T>, T&&>::value, | ||
"This overload requires the resulting element type to be constructible from T&&" | ||
); | ||
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays"); | ||
return detail::to_array_rvalue(static_cast<T(&&)[N]>(a), make_index_sequence<N>{}); | ||
} | ||
|
||
} // namespace compat | ||
} // namespace boost | ||
|
||
#endif // BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright 2024 Ruben Perez Hidalgo. | ||
// Distributed under the Boost Software License, Version 1.0. | ||
// https://www.boost.org/LICENSE_1_0.txt | ||
|
||
#include <boost/compat/to_array.hpp> | ||
#include <boost/core/lightweight_test.hpp> | ||
|
||
#include <array> | ||
#include <vector> | ||
|
||
namespace compat = boost::compat; | ||
|
||
int main() | ||
{ | ||
{ | ||
// regular C array | ||
int input[] = {1, 2}; | ||
auto output = compat::to_array(input); | ||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 1); | ||
BOOST_TEST_EQ(output[1], 2); | ||
} | ||
{ | ||
// regular C array, const | ||
const int input[] = {1, 2}; | ||
auto output = compat::to_array(input); | ||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 1); | ||
BOOST_TEST_EQ(output[1], 2); | ||
} | ||
{ | ||
// values not moved | ||
const std::vector<int> vec{1, 2}; | ||
std::vector<int> input[]{vec}; | ||
auto output = compat::to_array(input); | ||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, ""); | ||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end()); | ||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified | ||
} | ||
{ | ||
// const values work | ||
const std::vector<int> vec{1, 2}; | ||
const std::vector<int> input[]{vec}; | ||
auto output = compat::to_array(input); | ||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, ""); | ||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end()); | ||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified | ||
} | ||
{ | ||
// constexpr check | ||
constexpr int input[] = {1, 2, 3}; | ||
constexpr auto output = compat::to_array(input); | ||
static_assert(std::is_same<decltype(output), const std::array<int, 3>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 1); | ||
BOOST_TEST_EQ(output[1], 2); | ||
BOOST_TEST_EQ(output[2], 3); | ||
} | ||
|
||
return boost::report_errors(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2024 Ruben Perez Hidalgo. | ||
// Distributed under the Boost Software License, Version 1.0. | ||
// https://www.boost.org/LICENSE_1_0.txt | ||
|
||
#include <boost/compat/to_array.hpp> | ||
#include <boost/core/lightweight_test.hpp> | ||
|
||
#include <array> | ||
#include <memory> | ||
#include <utility> | ||
#include <vector> | ||
|
||
namespace compat = boost::compat; | ||
|
||
int main() | ||
{ | ||
{ | ||
// regular C array | ||
int input[] = {5, 6}; | ||
auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 5); | ||
BOOST_TEST_EQ(output[1], 6); | ||
} | ||
{ | ||
// regular C array, const | ||
const int input[] = {5, 6}; | ||
auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 5); | ||
BOOST_TEST_EQ(output[1], 6); | ||
} | ||
{ | ||
// values moved | ||
const std::vector<int> vec{1, 2}; | ||
std::vector<int> input[]{vec}; | ||
auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, ""); | ||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end()); | ||
BOOST_TEST(input[0].empty()); // input left in a moved-from state | ||
} | ||
{ | ||
// const values work (although they don't result in an effective move) | ||
const std::vector<int> vec{1, 2}; | ||
const std::vector<int> input[]{vec}; | ||
auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, ""); | ||
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end()); | ||
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified | ||
} | ||
{ | ||
// move-only types work | ||
std::unique_ptr<int> input[] = {std::unique_ptr<int>{new int(42)}}; | ||
int* ptr = input[0].get(); | ||
auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), std::array<std::unique_ptr<int>, 1>>::value, ""); | ||
BOOST_TEST_EQ(output[0].get(), ptr); | ||
BOOST_TEST_EQ(input[0].get(), nullptr); // input left in a moved-from state | ||
} | ||
{ | ||
// constexpr check | ||
constexpr int input[] = {1, 2, 3}; | ||
constexpr auto output = compat::to_array(std::move(input)); | ||
static_assert(std::is_same<decltype(output), const std::array<int, 3>>::value, ""); | ||
BOOST_TEST_EQ(output[0], 1); | ||
BOOST_TEST_EQ(output[1], 2); | ||
BOOST_TEST_EQ(output[2], 3); | ||
} | ||
|
||
return boost::report_errors(); | ||
} |