swar.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2023 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_DETAIL_SWAR_HPP_INCLUDED
5 #define LEXY_DETAIL_SWAR_HPP_INCLUDED
6 
7 #include <climits>
8 #include <cstdint>
9 #include <cstring>
10 #include <lexy/_detail/config.hpp>
11 #include <lexy/input/base.hpp>
12 
13 #if defined(_MSC_VER)
14 # include <intrin.h>
15 #endif
16 
17 namespace lexy::_detail
18 {
19 // Contains the chars in little endian order; rightmost bits are first char.
20 using swar_int = std::uintmax_t;
21 
22 // The number of chars that can fit into one SWAR.
23 template <typename CharT>
24 constexpr auto swar_length = [] {
25  static_assert(sizeof(CharT) < sizeof(swar_int) && sizeof(swar_int) % sizeof(CharT) == 0);
26  return sizeof(swar_int) / sizeof(CharT);
27 }();
28 
29 template <typename CharT>
30 constexpr auto char_bit_size = sizeof(CharT) * CHAR_BIT;
31 
32 template <typename CharT>
33 constexpr auto make_uchar(CharT c)
34 {
35  if constexpr (std::is_same_v<CharT, LEXY_CHAR8_T>)
36  // Not all libstdc++ support char8_t and std::make_unsigned_t.
37  return c;
38  else
39  return std::make_unsigned_t<CharT>(c);
40 }
41 template <typename CharT>
42 using uchar_t = decltype(make_uchar(CharT()));
43 
44 // Returns a swar_int filled with the specific char.
45 template <typename CharT>
46 constexpr swar_int swar_fill(CharT _c)
47 {
48  auto c = make_uchar(_c);
49 
50  auto result = swar_int(0);
51  for (auto i = 0u; i != swar_length<CharT>; ++i)
52  {
53  result <<= char_bit_size<CharT>;
54  result |= c;
55  }
56  return result;
57 }
58 
59 // Returns a swar_int filled with the complement of the specific char.
60 template <typename CharT>
61 constexpr swar_int swar_fill_compl(CharT _c)
62 {
63  auto c = uchar_t<CharT>(~uchar_t<CharT>(_c));
64 
65  auto result = swar_int(0);
66  for (auto i = 0u; i != swar_length<CharT>; ++i)
67  {
68  result <<= char_bit_size<CharT>;
69  result |= c;
70  }
71  return result;
72 }
73 
74 constexpr void _swar_pack(swar_int&, int) {}
75 template <typename H, typename... T>
76 constexpr void _swar_pack(swar_int& result, int index, H h, T... t)
77 {
78  if (std::size_t(index) == char_bit_size<swar_int>)
79  return;
80 
81  if (index >= 0)
82  result |= swar_int(make_uchar(h)) << index;
83 
84  _swar_pack(result, index + int(char_bit_size<H>), t...);
85 }
86 
87 template <typename CharT>
89 {
92  std::size_t count;
93 
94  constexpr CharT operator[](std::size_t idx) const
95  {
96  constexpr auto mask = (swar_int(1) << char_bit_size<CharT>)-1;
97  return (value >> idx * char_bit_size<CharT>)&mask;
98  }
99 };
100 
101 // Returns a swar_int containing the specified characters.
102 // If more are provided than fit, will only take the first couple ones.
103 template <int SkipFirstNChars = 0, typename... CharT>
104 constexpr auto swar_pack(CharT... cs)
105 {
106  using char_type = std::common_type_t<CharT...>;
107  swar_pack_result<char_type> result{0, 0, 0};
108 
109  _swar_pack(result.value, -SkipFirstNChars * int(char_bit_size<char_type>), cs...);
110 
111  auto count = int(sizeof...(CharT)) - SkipFirstNChars;
112  if (count <= 0)
113  {
114  result.mask = 0;
115  result.count = 0;
116  }
117  else if (count >= int(swar_length<char_type>))
118  {
119  result.mask = swar_int(-1);
120  result.count = swar_length<char_type>;
121  }
122  else
123  {
124  result.mask = swar_int(swar_int(1) << count * int(char_bit_size<char_type>)) - 1;
125  result.count = std::size_t(count);
126  }
127 
128  return result;
129 }
130 
131 // Returns the index of the char that is different between lhs and rhs.
132 template <typename CharT>
133 constexpr std::size_t swar_find_difference(swar_int lhs, swar_int rhs)
134 {
135  if (lhs == rhs)
136  return swar_length<CharT>;
137 
138  auto mask = lhs ^ rhs;
139 
140 #if defined(__GNUC__)
141  auto bit_idx = __builtin_ctzll(mask);
142 #elif defined(_MSC_VER)
143  unsigned long bit_idx;
144  if (!_BitScanForward64(&bit_idx, mask))
145  bit_idx = 64;
146 #else
147 # error "unsupported compiler; please file an issue"
148 #endif
149 
150  return std::size_t(bit_idx) / char_bit_size<CharT>;
151 }
152 
153 // Returns true if v has a char less than N.
154 template <typename CharT, CharT N>
155 constexpr bool swar_has_char_less(swar_int v)
156 {
157  // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
158 
159  constexpr auto offset = swar_fill(CharT(N));
160  auto zero_or_msb = v - offset;
161 
162  constexpr auto msb_mask = swar_fill(CharT(1 << (char_bit_size<CharT> - 1)));
163  auto not_msb = ~v & msb_mask;
164 
165  return zero_or_msb & not_msb;
166 }
167 
168 // Returns true if v has a zero char.
169 template <typename CharT>
170 constexpr bool swar_has_zero(swar_int v)
171 {
172  return swar_has_char_less<CharT, 1>(v);
173 }
174 
175 // Returns true if v contains the specified char.
176 template <typename CharT, CharT C>
177 constexpr bool swar_has_char(swar_int v)
178 {
179  if constexpr (C == 0)
180  {
181  return swar_has_zero<CharT>(v);
182  }
183  else
184  {
185  constexpr auto mask = swar_fill(C);
186  return swar_has_zero<CharT>(v ^ mask);
187  }
188 }
189 } // namespace lexy::_detail
190 
191 namespace lexy::_detail
192 {
194 {};
195 template <typename Reader>
196 constexpr auto is_swar_reader = std::is_base_of_v<_swar_base, Reader>;
197 
198 template <typename Derived>
200 {
201 public:
203  {
204  auto ptr = static_cast<const Derived&>(*this).position();
205 
206  swar_int result;
207 #if LEXY_IS_LITTLE_ENDIAN
208  std::memcpy(&result, ptr, sizeof(swar_int));
209 #else
210  using char_type = typename Derived::encoding::char_type;
211  auto dst = reinterpret_cast<char*>(&result);
212  auto length = sizeof(swar_int) / sizeof(char_type);
213  for (auto i = 0u; i != length; ++i)
214  {
215  std::memcpy(dst + i, ptr + length - i - 1, sizeof(char_type));
216  }
217 #endif
218  return result;
219  }
220 
221  void bump_swar()
222  {
223  auto ptr = static_cast<Derived&>(*this).position();
224  ptr += swar_length<typename Derived::encoding::char_type>;
225  static_cast<Derived&>(*this).set_position(ptr);
226  }
227  void bump_swar(std::size_t char_count)
228  {
229  auto ptr = static_cast<Derived&>(*this).position();
230  ptr += char_count;
231  static_cast<Derived&>(*this).set_position(ptr);
232  }
233 };
234 
235 constexpr std::size_t round_size_for_swar(std::size_t size_in_bytes)
236 {
237  // We round up to the next multiple.
238  if (auto remainder = size_in_bytes % sizeof(swar_int); remainder > 0)
239  size_in_bytes += sizeof(swar_int) - remainder;
240  // Then add one extra space of padding on top.
241  size_in_bytes += sizeof(swar_int);
242  return size_in_bytes;
243 }
244 } // namespace lexy::_detail
245 
246 #endif // LEXY_DETAIL_SWAR_HPP_INCLUDED
247 
lexy::_detail::char_bit_size
constexpr auto char_bit_size
Definition: swar.hpp:30
magic_enum::char_type
string_view::value_type char_type
Definition: magic_enum.hpp:145
config.hpp
lexy::_detail::swar_has_zero
constexpr bool swar_has_zero(swar_int v)
Definition: swar.hpp:170
lexy::_detail::swar_int
std::uintmax_t swar_int
Definition: swar.hpp:20
lexy::_detail::round_size_for_swar
constexpr std::size_t round_size_for_swar(std::size_t size_in_bytes)
Definition: swar.hpp:235
lexy::_detail::swar_find_difference
constexpr std::size_t swar_find_difference(swar_int lhs, swar_int rhs)
Definition: swar.hpp:133
lexy::_detail::swar_pack
constexpr auto swar_pack(CharT... cs)
Definition: swar.hpp:104
lexy::_detail::uchar_t
decltype(make_uchar(CharT())) uchar_t
Definition: swar.hpp:42
lexy::_detail::swar_has_char
constexpr bool swar_has_char(swar_int v)
Definition: swar.hpp:177
lexy::count
constexpr auto count
Sink that counts all arguments.
Definition: fold.hpp:88
lexy::_detail::swar_reader_base::bump_swar
void bump_swar(std::size_t char_count)
Definition: swar.hpp:227
lexy::_detail::_swar_base
Definition: swar.hpp:193
lexy::_detail::swar_pack_result::count
std::size_t count
Definition: swar.hpp:92
lexy::_detail::swar_reader_base::peek_swar
swar_int peek_swar() const
Definition: swar.hpp:202
lexy::_detail::swar_reader_base::bump_swar
void bump_swar()
Definition: swar.hpp:221
lexy::_detail::swar_pack_result
Definition: swar.hpp:88
lexy::_detail
Definition: any_ref.hpp:12
lexy::_detail::swar_pack_result::mask
swar_int mask
Definition: swar.hpp:91
lexy::_detail::swar_has_char_less
constexpr bool swar_has_char_less(swar_int v)
Definition: swar.hpp:155
lexy::_detail::swar_pack_result::operator[]
constexpr CharT operator[](std::size_t idx) const
Definition: swar.hpp:94
lexy::_detail::swar_reader_base
Definition: swar.hpp:199
base.hpp
lexy::_detail::is_swar_reader
constexpr auto is_swar_reader
Definition: swar.hpp:196
lexy::_detail::make_uchar
constexpr auto make_uchar(CharT c)
Definition: swar.hpp:33
lexy::_detail::swar_pack_result::value
swar_int value
Definition: swar.hpp:90
lexy::_detail::swar_fill_compl
constexpr swar_int swar_fill_compl(CharT _c)
Definition: swar.hpp:61
lexy::_detail::_swar_pack
constexpr void _swar_pack(swar_int &, int)
Definition: swar.hpp:74
lexy::_detail::swar_fill
constexpr swar_int swar_fill(CharT _c)
Definition: swar.hpp:46
lexy::_detail::swar_length
constexpr auto swar_length
Definition: swar.hpp:24


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:08