Skip to content

Commit

Permalink
detect vec, arr, string w/out causing hard errors
Browse files Browse the repository at this point in the history
  • Loading branch information
isidorostsa committed Sep 20, 2023
1 parent a43f622 commit 82f2907
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2007-2022 Hartmut Kaiser
// Copyright (c) 2023 Isidoros Tsaousis-Seiras
//
// SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
Expand All @@ -24,49 +25,86 @@ namespace hpx::traits {
using iter_value_type_t =
typename std::iterator_traits<Iter>::value_type;

template <typename T>
inline constexpr bool has_valid_array_v =
std::is_copy_assignable_v<T> && !std::is_function_v<T>;

template <typename Iter, typename Enable = void>
struct is_std_array_iterator : std::false_type
{
};

template <typename Iter>
struct is_std_array_iterator<Iter,
std::enable_if_t<has_valid_array_v<iter_value_type_t<Iter>>>>
: std::bool_constant<(
std::is_same_v<
typename std::array<iter_value_type_t<Iter>, 1>::iterator,
Iter> ||
std::is_same_v<typename std::array<iter_value_type_t<Iter>,
1>::const_iterator,
Iter>)>
{
};

template <typename T>
inline constexpr bool has_valid_vector_v =
std::is_copy_assignable_v<T> && !std::is_function_v<T>;

template <typename T, typename Enable = void>
struct is_known_contiguous_iterator : std::false_type
struct is_std_vector_iterator : std::false_type
{
};

template <typename Iter>
struct is_known_contiguous_iterator<Iter,
std::enable_if_t<!std::is_array_v<Iter>>>
struct is_std_vector_iterator<Iter,
std::enable_if_t<has_valid_vector_v<iter_value_type_t<Iter>>>>
: std::bool_constant<
std::is_same_v< // for std::vector
std::is_same_v<
typename std::vector<iter_value_type_t<Iter>>::iterator,
Iter> ||
std::is_same_v<typename std::vector<
iter_value_type_t<Iter>>::const_iterator,
Iter> || // for std::array
std::is_same_v<
typename std::array<iter_value_type_t<Iter>, 1>::iterator,
Iter>>
{
};

template <typename T>
inline constexpr bool has_valid_basic_string_v =
std::is_copy_assignable_v<T> && !std::is_function_v<T> &&
std::is_trivial_v<T>;

template <typename T, typename Enable = void>
struct is_std_basic_string_iterator : std::false_type
{
};

template <typename Iter>
struct is_std_basic_string_iterator<Iter,
std::enable_if_t<has_valid_basic_string_v<iter_value_type_t<Iter>>>>
: std::bool_constant<
std::is_same_v<typename std::basic_string<
iter_value_type_t<Iter>>::iterator,
Iter> ||
std::is_same_v<typename std::array<iter_value_type_t<Iter>,
1>::const_iterator,
Iter> || // for std::string
std::is_same_v<typename std::string::iterator, Iter> ||
std::is_same_v<typename std::string::const_iterator, Iter>>
std::is_same_v<typename std::basic_string<
iter_value_type_t<Iter>>::const_iterator,
Iter>>
{
};
} // namespace detail

template <typename Iter,
bool not_known_contiguous_iterator =
// When _GLIBCXX_DEBUG is defined vectors are contiguous, but the iterators
// are not plain pointers.
#if defined(_GLIBCXX_DEBUG)
false
#else
detail::is_known_contiguous_iterator<Iter>::value
#endif
>
struct is_contiguous_iterator : std::is_pointer<Iter>::type
{
};
template <typename Iter>
struct is_known_contiguous_iterator
: std::bool_constant<is_std_array_iterator<Iter>::value ||
is_std_vector_iterator<Iter>::value ||
is_std_basic_string_iterator<Iter>::value>
{
};
} // namespace detail

template <typename Iter>
struct is_contiguous_iterator<Iter, true> : std::true_type
struct is_contiguous_iterator
: std::bool_constant<std::is_pointer_v<Iter> ||
detail::is_known_contiguous_iterator<Iter>::value>
{
};

Expand Down
35 changes: 30 additions & 5 deletions libs/core/type_support/tests/unit/is_contiguous_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,24 @@

#include <array>
#include <cassert>
#include <iterator>
#include <string>
#include <vector>

#include <hpx/type_support/is_contiguous_iterator.hpp>

using hpx::traits::is_contiguous_iterator_v;
using namespace hpx::traits::detail;
using namespace hpx::traits;

// std::vector<int>::iterator is a contiguous iterator
static_assert(has_valid_vector_v<int>);

static_assert(is_contiguous_iterator_v<std::vector<int>::iterator>);
static_assert(is_std_vector_iterator<std::vector<int>::iterator>::value);

static_assert(is_contiguous_iterator_v<std::vector<int>::const_iterator>);
static_assert(is_std_vector_iterator<std::vector<int>::const_iterator>::value);

// reverse_iterator is not a contiguous iterator
static_assert(!is_contiguous_iterator_v<std::vector<int>::reverse_iterator>);
static_assert(
Expand All @@ -31,19 +40,35 @@ static_assert(
// pointers are contiguous iterators
static_assert(is_contiguous_iterator_v<int*>);
static_assert(is_contiguous_iterator_v<int const*>);

// std::string::iterator is a contiguous iterator
static_assert(is_contiguous_iterator_v<std::string::iterator>);
static_assert(is_contiguous_iterator_v<std::string::const_iterator>);

// Pointers to arrays are still pointers
static_assert(is_contiguous_iterator_v<int (*)[]>);
static_assert(is_contiguous_iterator_v<int const (*)[]>);
static_assert(is_contiguous_iterator_v<int (*)[4]>);
static_assert(is_contiguous_iterator_v<int const (*)[4]>);

// arrays are not contiguous iterators
// Pointers to functions are still pointers
static_assert(is_contiguous_iterator_v<int (*)()>);
static_assert(is_contiguous_iterator_v<int const (*)()>);

// c-style arrays are not contiguous iterators
static_assert(!is_contiguous_iterator_v<int[]>);
static_assert(!is_contiguous_iterator_v<int[4]>);
static_assert(!is_contiguous_iterator_v<int const[]>);
static_assert(!is_contiguous_iterator_v<int const[4]>);

// std::string::iterator is a contiguous iterator
static_assert(is_contiguous_iterator_v<std::string::iterator>);
static_assert(is_contiguous_iterator_v<std::string::const_iterator>);
// Unknown type iterators to "weird"
// types should not cause compile errors
using function_iterator =
std::iterator<std::random_access_iterator_tag, int(int, int)>;
using empty_array_iterator =
std::iterator<std::random_access_iterator_tag, int[]>;

static_assert(!is_contiguous_iterator_v<function_iterator>);
static_assert(!is_contiguous_iterator_v<empty_array_iterator>);

int main(int, char*[]) {}

0 comments on commit 82f2907

Please sign in to comment.