39 static constexpr size_t npos = SIZE_MAX;
41 kmp_str_ref(
const char *str) : data(str), len(str ? strlen(str) : 0) {}
42 kmp_str_ref(
const char *str,
size_t len) : data(str), len(len) {
43 assert((data || !len) &&
"len must be 0 for nullptr data");
56 if (memcmp(data, prefix.data, prefix.len) != 0)
66 bool allow_negative =
false);
74 template <
typename Fn>
size_t count_while(
const Fn &predicate)
const {
75 static_assert(std::is_invocable_r_v<bool, Fn, char>,
76 "predicate must be callable as bool(char)");
78 return n == npos ? len : n;
91 template <
typename Fn>
void drop_while(
const Fn &predicate) {
92 static_assert(std::is_invocable_r_v<bool, Fn, char>,
93 "predicate must be callable as bool(char)");
98 bool empty()
const {
return len == 0; }
103 template <
typename Fn>
size_t find_if(
const Fn &predicate)
const {
104 static_assert(std::is_invocable_r_v<bool, Fn, char>,
105 "predicate must be callable as bool(char)");
107 while (i < len && !predicate(data[i]))
109 return i < len ? i : npos;
115 template <
typename Fn>
size_t find_if_not(
const Fn &predicate)
const {
116 static_assert(std::is_invocable_r_v<bool, Fn, char>,
117 "predicate must be callable as bool(char)");
118 return find_if([predicate](
char c) {
return !predicate(c); });
123 size_t size()
const {
return length(); }
128 return static_cast<bool>(isspace(
static_cast<unsigned char>(c)));
135 static_assert(std::is_invocable_r_v<bool, Fn, char>,
136 "predicate must be callable as bool(char)");
141 const char *
begin()
const {
return data; }
142 const char *end()
const {
return data + len; }
148template <
typename T,
size_t INLINE_THRESHOLD = 8>
class kmp_vector final {
149 static_assert(std::is_copy_constructible_v<T>,
150 "T must be copy constructible");
151 static_assert(std::is_destructible_v<T>,
"T must be destructible");
154 bool operator()(
const T &a,
const T &b)
const {
return a == b; }
157 T inline_data[INLINE_THRESHOLD];
158 T *data = inline_data;
160 size_t capacity = INLINE_THRESHOLD;
162 void copy_data(T *dst,
const T *src,
size_t num_elements) {
163 if constexpr (std::is_trivially_copyable_v<T>) {
164 memcpy(dst, src, num_elements *
sizeof(T));
166 for (
size_t i = 0; i < num_elements; i++)
167 new (&dst[i]) T(src[i]);
174 void grow(
size_t MinSize = 0) {
176 if (MinSize <= capacity)
180 capacity = capacity + (capacity / 2) + 1;
182 T *old_data = data != inline_data ? data :
nullptr;
184 static_cast<T *
>(KMP_INTERNAL_REALLOC(old_data, capacity *
sizeof(T)));
186 KMP_FATAL(MemoryAllocFailed);
189 copy_data(data, inline_data, count);
192 void init(
size_t new_capacity,
const T *init_data,
size_t new_count) {
193 assert(new_capacity >= new_count &&
194 "more elements requested than capacity");
195 if (new_capacity > capacity)
198 copy_data(data, init_data, new_count);
204 assert(empty() &&
"must be empty before overwriting");
205 if (other.data == other.inline_data) {
207 init(other.capacity, other.data, other.count);
212 capacity = other.capacity;
217 void reset(
bool free_data) {
218 if (free_data && data != inline_data) {
220 KMP_INTERNAL_FREE(data);
224 capacity = INLINE_THRESHOLD;
230 explicit kmp_vector(
size_t capacity = 0) { init(capacity,
nullptr, 0); }
232 kmp_vector(
size_t capacity,
const T *init_data,
size_t count) {
233 init(capacity, init_data, count);
237 init(other.capacity, other.data, other.count);
243 if (
this != &other) {
245 init(other.capacity, other.data, other.count);
251 if (
this != &other) {
260 if constexpr (!std::is_trivially_destructible_v<T>) {
261 for (
size_t i = 0; i < count; i++)
270 template <
typename Fn = default_eq>
271 bool contains(
const T &value,
const Fn &comp = Fn{})
const {
272 static_assert(std::is_invocable_r_v<bool, Fn, const T &, const T &>,
273 "predicate must be callable as bool(const T &, const T &)");
274 for (
size_t i = 0; i < count; i++) {
275 if (comp(data[i], value))
281 bool empty()
const {
return !count; }
286 template <
typename Fn = default_eq>
288 static_assert(std::is_invocable_r_v<bool, Fn, const T &, const T &>,
289 "predicate must be callable as bool(const T &, const T &)");
290 for (
const T &val : *
this) {
294 for (
const T &val : other) {
303 if (count == capacity)
305 if constexpr (std::is_trivially_copyable_v<T>)
306 data[count++] = value;
308 new (&data[count++]) T(value);
314 if (new_capacity > capacity)
318 size_t size()
const {
return count; }
320 T &operator[](
size_t index) {
321 assert(index < count &&
"Index out of bounds");
324 const T &operator[](
size_t index)
const {
325 assert(index < count &&
"Index out of bounds");
331 T *end() {
return data + count; }
332 const T *
begin()
const {
return data; }
333 const T *end()
const {
return data + count; }
kmp_str_ref is a non-owning string class (similar to llvm::StringRef).
kmp_str_ref take_while(const Fn &predicate) const
size_t find_if_not(const Fn &predicate) const
size_t length() const
Get the length of the string.
bool consume_front(kmp_str_ref prefix)
bool consume_integer(int &value, bool allow_zero=true, bool allow_negative=false)
bool empty() const
Check if the string is empty.
size_t find_if(const Fn &predicate) const
size_t count_while(const Fn &predicate) const
const char * begin() const
Iterator support (raw pointers work as iterators for contiguous storage)
void skip_space()
Drop space from the start of the string.
void drop_front(size_t n)
void drop_while(const Fn &predicate)
Drop characters from the string while the predicate returns true.
void move_from(kmp_vector &&other)
Move data from other vector to this vector (which must be emptied before)
void clear()
Destroy all elements in the vector. Doesn't free the memory.
T * begin()
Iterator support (raw pointers work as iterators for contiguous storage)
void push_back(const T &value)
Add a new element to the end of the vector.
void grow(size_t MinSize=0)
void reserve(size_t new_capacity)
bool is_set_equal(const kmp_vector &other, const Fn &comp=Fn{}) const
bool contains(const T &value, const Fn &comp=Fn{}) const