/* *****************************************************************************
* kblib is a general utility library for C++14 and C++17, intended to provide
* performant high-level abstractions and more expressive ways to do simple
* things.
*
* Copyright (c) 2021 killerbee
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
* ****************************************************************************/
/**
* @file
* @brief Contains some type traits not in the standard library that are useful
* in the implementation of kblib.
*
* @author killerbee
* @date 2019-2021
* @copyright GNU General Public Licence v3.0
*/
#ifndef KBLIB_TRAITS_H_INCLUDED_
#define KBLIB_TRAITS_H_INCLUDED_
#include "fakestd.h"
#include "tdecl.h"
#include
#include
#include
#include
namespace KBLIB_NS {
// contains_types adapted from code by Maarten Bamelis,
// https://stackoverflow.com/a/42581257/1924641
/**
* @brief Determines if T is a type in Tuple, which must be a std::tuple.
*/
template
struct contains_type;
template
struct contains_type, U>
: contains_type, U> {};
template
struct contains_type, T> : std::true_type {};
template
struct contains_type, T> : std::false_type {};
template
KBLIB_CONSTANT_V contains_type_v = contains_type::value;
/**
* @brief Determines if Lhs contains all of the types in Rhs, where both are
* std::tuples.
*/
template
struct contains_types;
template
struct contains_types>
: std::integral_constant<
bool, contains_type::value
and contains_types>::value> {};
template
struct contains_types> : std::true_type {};
template
KBLIB_CONSTANT_V contains_types_v = contains_types::value;
template
struct list_as_tuple;
template class Tuple, typename... Ts>
struct list_as_tuple> {
using type = std::tuple;
};
namespace detail {
/**
* @brief Truncates an array to its first N elements.
*
* @param arr An array of at least N elements to truncate.
* @param Is An implementation detail.
* @return std::array An array consisting of the first N
* elements of arr.
*/
template
KBLIB_NODISCARD constexpr auto trim_array(const T (&arr)[N],
std::integer_sequence)
-> std::array::size()> {
return {arr[I]...};
}
} // namespace detail
/**
* @brief Truncates the last trim elements from an array.
*
* @param arr The array to trim.
* @return std::array The trimmed array.
*/
template >
KBLIB_NODISCARD constexpr auto trim_array(const T (&arr)[N])
-> std::array {
return detail::trim_array(arr, Indices{});
}
/**
* @brief Creates an array of only the meaningful characters in a string
* literal, and not the null terminator.
*
* @param arr A string literal to strip the null terminator from.
* @return std::array A std::array of the meaningful characters of
* the string literal.
*/
template >
KBLIB_NODISCARD constexpr auto remove_null_terminator(const char (&arr)[N])
-> std::array {
return detail::trim_array(arr, Indices{});
}
template
struct is_unbounded_array : std::false_type {};
template
struct is_unbounded_array : std::true_type {};
template
struct is_bounded_array : std::false_type {};
template
struct is_bounded_array : std::true_type {};
template
/**
* @brief A simple identity alias for simplifying some compound type
* declarations, such as function pointers.
*/
using alias = T;
/**
* @brief Ignores its first template argument entirely, and returns its second
*/
template
struct ignore {
using type = T;
};
/**
* @brief An alias for ignore::type
*
*/
template
using ignore_t = typename ignore::type;
/**
* @brief Creates a T with the same object representation as the given F.
*
* T and F must be the same size and must both be trivially copyable.
*
* @note Will be fully replaceable by std::bit_cast in C++20.
*
* @param v A value to reinterpret.
* @return T The reinterpreted value.
*/
template
KBLIB_NODISCARD auto byte_cast(F v) noexcept -> T {
static_assert(
sizeof(T) == sizeof(F),
"Source and destination types for byte_cast must be the same size.");
static_assert(std::is_trivially_copyable::value
and std::is_trivially_copyable::value,
"Source and destination types for byte_cast must be trivially "
"copyable.");
T ret{};
std::memcpy(&ret, &v, sizeof(T));
return ret;
}
namespace detail {
template ().resize(0))>
auto calc_resizable(int) noexcept -> std::true_type;
template ::value>
auto calc_resizable(int) noexcept -> std::false_type;
template
auto calc_resizable(...) noexcept -> std::false_type;
} // namespace detail
// Note that when a type that is not resizable, but also doesn't have a
// constexpr size, is passed, there is a hard error.
/**
* True if and only if C is a resizable container.
*/
template
KBLIB_CONSTANT_V is_resizable_v = decltype(detail::calc_resizable(0))::value;
template
struct is_resizable : bool_constant> {};
template
KBLIB_CONSTANT_V has_reserve_v = false;
template
KBLIB_CONSTANT_V
has_reserve_v().reserve(0))>> = true;
/**
* @brief True if and only if C contains an accessible reserve() member.
*/
template
struct has_reserve : bool_constant> {};
/**
* @brief Attempt to reserve capacity in a container. No-op if unsupported.
*
* @param c The container to modify.
* @param s The requested capacity.
*/
template , int>::type = 0>
auto try_reserve(C& c, std::size_t s) noexcept(noexcept(c.reserve(s))) -> void {
c.reserve(s);
return;
}
/**
* @brief Attempt to reserve capacity in a container. No-op if unsupported.
*
* @param c The container to modify.
* @param s The requested capacity.
*/
template , int>::type = 0>
auto try_reserve(C&, std::size_t) noexcept -> void {
return;
}
/**
* @brief Type trait to determine if a container is contiguous.
*
*/
template
KBLIB_CONSTANT_V is_contiguous_v = false;
template
KBLIB_CONSTANT_V
is_contiguous_v().data())>> = true;
template
struct is_contiguous : bool_constant> {};
template
struct class_of;
template
struct class_of {
using type = T;
};
template
using class_of_t = typename class_of::type;
#if __cpp_nontype_template_parameter_auto
template
using class_t = typename class_of::type;
#endif
template
struct member_of;
template
struct member_of {
using type = M;
};
template
using member_of_t = typename member_of::type;
#if __cpp_nontype_template_parameter_auto
/**
* @brief The type of member pointed to by M.
*
*/
template
using member_t = member_of_t;
#endif
template
struct return_type;
template
struct return_type : meta_type {};
template
struct return_type : meta_type {};
template
struct return_type : meta_type {};
template
struct return_type : meta_type {};
template
struct exists : std::true_type {};
template
struct is_input_iterator : std::false_type {};
template
struct is_input_iterator<
T, void_if_t::iterator_category>::value>>
: std::true_type {};
template
KBLIB_CONSTANT_V is_input_iterator_v = is_input_iterator::value;
template
struct is_forward_iterator : std::false_type {};
template
struct is_forward_iterator<
T, void_if_t::iterator_category>::value>>
: std::true_type {};
template
KBLIB_CONSTANT_V is_forward_iterator_v = is_forward_iterator::value;
template
struct is_bidirectional_iterator : std::false_type {};
template
struct is_bidirectional_iterator<
T, void_if_t::iterator_category>::value>>
: std::true_type {};
template
KBLIB_CONSTANT_V is_bidirectional_iterator_v
= is_bidirectional_iterator::value;
template
struct is_random_access_iterator : std::false_type {};
template
struct is_random_access_iterator<
T, void_if_t::iterator_category>::value>>
: std::true_type {};
template
KBLIB_CONSTANT_V is_random_access_iterator_v
= is_random_access_iterator::value;
/**
* @brief Type trait that determines the iterator type for a range.
*
*/
template
struct iterator_type_for;
template
struct iterator_type_for {
using type = T*;
};
template
struct iterator_type_for()))>> {
using type = decltype(begin(std::declval()));
};
template
using iterator_type_for_t = typename iterator_type_for::type;
template
struct is_iterable : std::false_type {};
template
struct is_iterable()))>::value>>
: std::true_type {};
template
struct is_iterable : std::true_type {};
template
struct is_iterable : std::true_type {};
template
KBLIB_CONSTANT_V is_iterable_v = is_iterable::value;
template
struct is_iterator : std::false_type {};
template
struct is_iterator<
T, void_t(), void(), ++std::declval())>>
: std::true_type {};
template
KBLIB_CONSTANT_V is_iterator_v = is_iterator::value;
/**
* @brief Abbreviated name for std::is_reference::value for C++14.
*
*/
template
KBLIB_CONSTANT_V is_reference_v = std::is_reference::value;
/**
* @brief Abbreviated name for std::remove_reference::type for C++14.
*
*/
template
using remove_reference_t = typename std::remove_reference::type;
/**
* @brief Names the EOF value for the given character type in std::char_traits.
*/
template
KBLIB_CONSTANT auto eof = std::char_traits::eof();
template
struct type_constant {
constexpr operator T() const noexcept { return V; }
static constexpr T value = V;
};
#if __cpp_nontype_template_parameter_auto
template
using type_constant_for = type_constant;
#endif
template
struct is_aliasing_type : std::false_type {};
template <>
struct is_aliasing_type : std::true_type {};
template <>
struct is_aliasing_type : std::true_type {};
#if __cpp_lib_byte
template <>
struct is_aliasing_type : std::true_type {};
#endif
template
KBLIB_CONSTANT_V is_aliasing_type_v = is_aliasing_type::value;
} // namespace KBLIB_NS
#endif // KBLIB_TRAITS_H_INCLUDED_