1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H
10 #define _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H
11 
12 #include <__config>
13 #include <__type_traits/integral_constant.h>
14 #include <__type_traits/is_same.h>
15 #include <__type_traits/is_unsigned.h>
16 #include <__type_traits/remove_cv.h>
17 #include <__type_traits/void_t.h>
18 #include <__utility/declval.h>
19 
20 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21 #  pragma GCC system_header
22 #endif
23 
24 _LIBCPP_BEGIN_NAMESPACE_STD
25 
26 // A type is_trivially_lexicographically_comparable if the expression `a <=> b` (or their pre-C++20 equivalents) is
27 // equivalent to `std::memcmp(&a, &b, sizeof(T))` (with `a` and `b` being of type `T`). There is currently no builtin to
28 // tell us whether that's the case for arbitrary types, so we can only do this for known types. Specifically, these are
29 // currently unsigned integer types with a sizeof(T) == 1.
30 //
31 // bool is trivially lexicographically comparable, because e.g. false <=> true is valid code. Furthermore, the standard
32 // says that [basic.fundamental] "Type bool is a distinct type that has the same object representation, value
33 // representation, and alignment requirements as an implementation-defined unsigned integer type. The values of type
34 // bool are true and false."
35 // This means that bool has to be unsigned and has exactly two values. This means that having anything other than the
36 // `true` or `false` value representations in a bool is UB.
37 //
38 // The following types are not trivially lexicographically comparable:
39 // signed integer types: `char(-1) < char(1)`, but memcmp compares `unsigned char`s
40 // unsigned integer types with sizeof(T) > 1: depending on the endianness, the LSB might be the first byte to be
41 //                                            compared. This means that when comparing unsigned(129) and unsigned(2)
42 //                                            using memcmp(), the result would be that 2 > 129.
43 //                                            TODO: Do we want to enable this on big-endian systems?
44 
45 template <class _Tp, class _Up>
46 struct __libcpp_is_trivially_lexicographically_comparable
47     : integral_constant<bool,
48                         is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value && sizeof(_Tp) == 1 &&
49                             is_unsigned<_Tp>::value> {};
50 
51 _LIBCPP_END_NAMESPACE_STD
52 
53 #endif // _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_LEXICOGRAPHICALLY_COMPARABLE_H
54