1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef _CONSTEXPR_CHAR_TRAITS
11 #define _CONSTEXPR_CHAR_TRAITS
12
13 #include <string>
14 #include <cassert>
15 #include <cstddef>
16
17 #include "test_macros.h"
18
19 // Tests whether the pointer p is in the range [first, last).
20 //
21 // Precondition: The range [first, last) is a valid range.
22 //
23 // Typically the pointers are compared with less than. This is not allowed when
24 // the pointers belong to different ranges, which is UB. Typically, this is
25 // benign at run-time, however since UB is not allowed during constant
26 // evaluation this does not compile. This function does the validation without
27 // UB.
28 //
29 // When p is in the range [first, last) the data can be copied from the
30 // beginning to the end. Otherwise it needs to be copied from the end to the
31 // beginning.
32 template <class CharT>
is_pointer_in_range(const CharT * first,const CharT * last,const CharT * p)33 TEST_CONSTEXPR_CXX14 bool is_pointer_in_range(const CharT* first, const CharT* last, const CharT* p) {
34 if (first == p) // Needed when n == 0
35 return true;
36
37 for (; first != last; ++first)
38 if (first == p)
39 return true;
40
41 return false;
42 }
43
44 template <class CharT>
45 struct constexpr_char_traits
46 {
47 typedef CharT char_type;
48 typedef int int_type;
49 typedef std::streamoff off_type;
50 typedef std::streampos pos_type;
51 typedef std::mbstate_t state_type;
52 // The comparison_category is omitted so the class will have weak_ordering
53 // in C++20. This is intentional.
54
assignconstexpr_char_traits55 static TEST_CONSTEXPR_CXX14 void assign(char_type& c1, const char_type& c2) TEST_NOEXCEPT
56 {c1 = c2;}
57
eqconstexpr_char_traits58 static TEST_CONSTEXPR bool eq(char_type c1, char_type c2) TEST_NOEXCEPT
59 {return c1 == c2;}
60
ltconstexpr_char_traits61 static TEST_CONSTEXPR bool lt(char_type c1, char_type c2) TEST_NOEXCEPT
62 {return c1 < c2;}
63
64 static TEST_CONSTEXPR_CXX14 int compare(const char_type* s1, const char_type* s2, std::size_t n);
65 static TEST_CONSTEXPR_CXX14 std::size_t length(const char_type* s);
66 static TEST_CONSTEXPR_CXX14 const char_type* find(const char_type* s, std::size_t n, const char_type& a);
67 static TEST_CONSTEXPR_CXX14 char_type* move(char_type* s1, const char_type* s2, std::size_t n);
68 static TEST_CONSTEXPR_CXX14 char_type* copy(char_type* s1, const char_type* s2, std::size_t n);
69 static TEST_CONSTEXPR_CXX14 char_type* assign(char_type* s, std::size_t n, char_type a);
70
not_eofconstexpr_char_traits71 static TEST_CONSTEXPR int_type not_eof(int_type c) TEST_NOEXCEPT
72 {return eq_int_type(c, eof()) ? ~eof() : c;}
73
to_char_typeconstexpr_char_traits74 static TEST_CONSTEXPR char_type to_char_type(int_type c) TEST_NOEXCEPT
75 {return char_type(c);}
76
to_int_typeconstexpr_char_traits77 static TEST_CONSTEXPR int_type to_int_type(char_type c) TEST_NOEXCEPT
78 {return int_type(c);}
79
eq_int_typeconstexpr_char_traits80 static TEST_CONSTEXPR bool eq_int_type(int_type c1, int_type c2) TEST_NOEXCEPT
81 {return c1 == c2;}
82
eofconstexpr_char_traits83 static TEST_CONSTEXPR int_type eof() TEST_NOEXCEPT
84 {return int_type(EOF);}
85 };
86
87
88 template <class CharT>
89 TEST_CONSTEXPR_CXX14 int
compare(const char_type * s1,const char_type * s2,std::size_t n)90 constexpr_char_traits<CharT>::compare(const char_type* s1, const char_type* s2, std::size_t n)
91 {
92 for (; n; --n, ++s1, ++s2)
93 {
94 if (lt(*s1, *s2))
95 return -1;
96 if (lt(*s2, *s1))
97 return 1;
98 }
99 return 0;
100 }
101
102 template <class CharT>
103 TEST_CONSTEXPR_CXX14 std::size_t
length(const char_type * s)104 constexpr_char_traits<CharT>::length(const char_type* s)
105 {
106 std::size_t len = 0;
107 for (; !eq(*s, char_type(0)); ++s)
108 ++len;
109 return len;
110 }
111
112 template <class CharT>
113 TEST_CONSTEXPR_CXX14 const CharT*
find(const char_type * s,std::size_t n,const char_type & a)114 constexpr_char_traits<CharT>::find(const char_type* s, std::size_t n, const char_type& a)
115 {
116 for (; n; --n)
117 {
118 if (eq(*s, a))
119 return s;
120 ++s;
121 }
122 return 0;
123 }
124
125 template <class CharT>
move(char_type * s1,const char_type * s2,std::size_t n)126 TEST_CONSTEXPR_CXX14 CharT* constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n) {
127 if (s1 == s2)
128 return s1;
129
130 char_type* r = s1;
131 if (is_pointer_in_range(s1, s1 + n, s2)) {
132 for (; n; --n)
133 assign(*s1++, *s2++);
134 } else {
135 s1 += n;
136 s2 += n;
137 for (; n; --n)
138 assign(*--s1, *--s2);
139 }
140 return r;
141 }
142
143 template <class CharT>
144 TEST_CONSTEXPR_CXX14 CharT*
copy(char_type * s1,const char_type * s2,std::size_t n)145 constexpr_char_traits<CharT>::copy(char_type* s1, const char_type* s2, std::size_t n)
146 {
147 if (!TEST_IS_CONSTANT_EVALUATED) // fails in constexpr because we might be comparing unrelated pointers
148 assert(s2 < s1 || s2 >= s1+n);
149 char_type* r = s1;
150 for (; n; --n, ++s1, ++s2)
151 assign(*s1, *s2);
152 return r;
153 }
154
155 template <class CharT>
156 TEST_CONSTEXPR_CXX14 CharT*
assign(char_type * s,std::size_t n,char_type a)157 constexpr_char_traits<CharT>::assign(char_type* s, std::size_t n, char_type a)
158 {
159 char_type* r = s;
160 for (; n; --n, ++s)
161 assign(*s, a);
162 return r;
163 }
164
165 #endif // _CONSTEXPR_CHAR_TRAITS
166