Skip to content

Commit

Permalink
🩹 Fix type_traits for gcc < 5
Browse files Browse the repository at this point in the history
The gcc compiler for versions prior to gcc-5 did not implement the
type_traits into its entirety. In particular, the aligned_union and
traits for triviality were not implemented.

aligned_union is easy to implement, and has been added to this project.
The triviality traits are a little more complicated, since they require
compiler support to detect (e.g. intrinsics). Several of them can be
implemented through traits that gcc < 5 offered that were
pre-standardization -- such as 'has_trivial_copy' over
'is_trivially_copy_constructible' -- but many of them simply cannot be
implemented without compiler hooks.

The ones that could be implemented have been, and the ones that can't
be implemented have been left defined as 'false_type', since support
is simply unavailable.

https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2014
  • Loading branch information
bitwizeshift committed Mar 3, 2020
1 parent 0296059 commit 87325cc
Showing 1 changed file with 153 additions and 2 deletions.
155 changes: 153 additions & 2 deletions include/bpstd/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@
#include <type_traits>
#include <cstddef> // std::size_t

// GCC versions prior to gcc-5 did not implement the type traits for triviality
// in completion. Several traits are implemented under a different names from
// pre-standardization, such as 'has_trivial_copy_destructor' instead of
// 'is_trivially_destructible'. However, most of these cannot be implemented
// without compiler support.
//
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2014
#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
# define BPSTD_HAS_TRIVIAL_TYPE_TRAITS 0
#else
# define BPSTD_HAS_TRIVIAL_TYPE_TRAITS 1
#endif

namespace bpstd {

//============================================================================
Expand Down Expand Up @@ -475,9 +488,21 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_copyable = std::is_trivially_copyable<T>;

#else

// std::is_trivially_copyable is not implemented in gcc < 5, and unfortunately
// can't be implemented without compiler intrinsics. This definition is
// left out to avoid problems
template <typename T>
using is_trivially_copyable = false_type;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_copyable_v = is_trivially_copyable<T>::value;
Expand Down Expand Up @@ -715,8 +740,34 @@ namespace bpstd {

//----------------------------------------------------------------------------

template <std::size_t Len, typename...Ts>
using aligned_union = std::aligned_union<Len, Ts...>;
namespace detail {

template <std::size_t...Sizes>
struct largest;

template <std::size_t Size0, std::size_t Size1, std::size_t...Sizes>
struct largest<Size0, Size1, Sizes...>
: largest<(Size0 > Size1 ? Size0 : Size1), Sizes...>{};

template <std::size_t Size0>
struct largest<Size0> : integral_constant<std::size_t,Size0>{};

} // namespace detail

// gcc < 5 does not implement 'std::aligned_union', despite it being a type
// in the C++11 standard -- so it's implemented here to ensure that its
// available.
template <std::size_t Len, typename... Ts>
struct aligned_union
{
static constexpr std::size_t alignment_value = detail::largest<alignof(Ts)...>::value;
static constexpr std::size_t size_value = detail::largest<Len, sizeof(Ts)...>::value;

struct type
{
alignas(alignment_value) char buffer[size_value];
};
};

template <std::size_t Len, typename...Ts>
using aligned_union_t = typename aligned_union<Len, Ts...>::type;
Expand Down Expand Up @@ -767,9 +818,22 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T, typename...Args>
using is_trivially_constructible = std::is_trivially_constructible<T, Args...>;

#else

// std::is_trivially_constructible is not implemented in gcc < 5, and
// there exists no utilities to implement it in the language without extensions.
// This is left defined to false_type so that the trait may be used, despite
// yielding incorrect results
template <typename T, typename...Args>
using is_trivially_constructible = false_type;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T, typename...Args>
BPSTD_CPP17_INLINE constexpr auto is_trivially_constructible_v = is_trivially_constructible<T>::value;
Expand Down Expand Up @@ -797,9 +861,21 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_default_constructible = std::is_trivially_default_constructible<T>;

#else

// std::is_trivially_default_constructible is not implemented in gcc < 5,
// however there exists a non-standard
// 'std::has_trivial_default_constructor' which performs a similar check
template <typename T>
using is_trivially_default_constructible = std::has_trivial_default_constructor<T>;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_default_constructible_v = is_trivially_default_constructible<T>::value;
Expand Down Expand Up @@ -827,9 +903,21 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;

#else

// std::is_trivially_copy_constructible is not implemented in gcc < 5,
// however there exists a non-standard
// 'std::has_trivial_copy_constructor' which performs a similar check
template <typename T>
using is_trivially_copy_constructible = std::has_trivial_copy_constructor<T>;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_copy_constructible_v = is_trivially_copy_constructible<T>::value;
Expand Down Expand Up @@ -857,9 +945,22 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_move_constructible = std::is_trivially_move_constructible<T>;

#else

// std::is_trivially_move_constructible is not implemented in gcc < 5, and
// there exists no utilities to implement it in the language without extensions.
// This is left defined to false_type so that the trait may be used, despite
// yielding incorrect results
template <typename T>
using is_trivially_move_constructible = false_type;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_move_constructible_v = is_trivially_move_constructible<T>::value;
Expand Down Expand Up @@ -887,9 +988,22 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T, typename U>
using is_trivially_assignable = std::is_trivially_assignable<T, U>;

#else

// std::is_trivially_assignable is not implemented in gcc < 5, and
// there exists no utilities to implement it in the language without extensions.
// This is left defined to false_type so that the trait may be used, despite
// yielding incorrect results
template <typename T, typename U>
using is_trivially_assignable = false_type;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T, typename U>
BPSTD_CPP17_INLINE constexpr auto is_trivially_assignable_v = is_trivially_assignable<T, U>::value;
Expand Down Expand Up @@ -917,9 +1031,21 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_copy_assignable = std::is_trivially_copy_assignable<T>;

#else

// std::is_trivially_copy_assignable is not implemented in gcc < 5,
// however there exists a non-standard
// 'std::has_trivial_copy_assign' which performs a similar check
template <typename T>
using is_trivially_copy_assignable = std::has_trivial_copy_assign<T>;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_copy_assignable_v = is_trivially_copy_assignable<T>::value;
Expand Down Expand Up @@ -947,9 +1073,22 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_move_assignable = std::is_trivially_move_assignable<T>;

#else

// std::is_trivially_move_assignable is not implemented in gcc < 5, and
// there exists no utilities to implement it in the language without extensions.
// This is left defined to false_type so that the trait may be used, despite
// yielding incorrect results
template <typename T>
using is_trivially_move_assignable = false_type;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_move_assignable_v = is_trivially_move_assignable<T>::value;
Expand Down Expand Up @@ -977,9 +1116,21 @@ namespace bpstd {

//----------------------------------------------------------------------------

#if BPSTD_HAS_TRIVIAL_TYPE_TRAITS

template <typename T>
using is_trivially_destructible = std::is_trivially_destructible<T>;

#else

// std::is_trivially_destructible is not implemented in gcc < 5, however there
// exists a non-standard '__has_trivial_destructor' which performs a
// similar check
template <typename T>
using is_trivially_destructible = bool_constant<(__has_trivial_destructor(T))>;

#endif

#if BPSTD_HAS_TEMPLATE_VARIABLES
template <typename T>
BPSTD_CPP17_INLINE constexpr auto is_trivially_destructible_v = is_trivially_destructible<T>::value;
Expand Down

0 comments on commit 87325cc

Please sign in to comment.