1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
//===-- String utils --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Standalone string utility functions. Utilities requiring memory allocations
// should be placed in allocating_string_utils.h instead.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_STRING_STRING_UTILS_H
#define LLVM_LIBC_SRC_STRING_STRING_UTILS_H
#include "hdr/types/size_t.h"
#include "src/__support/CPP/bitset.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
#include "src/string/memory_utils/inline_memcpy.h"
#include "src/string/string_length.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
// Returns the maximum length span that contains only characters not found in
// 'segment'. If no characters are found, returns the length of 'src'.
LIBC_INLINE size_t complementary_span(const char *src, const char *segment) {
const char *initial = src;
cpp::bitset<256> bitset;
for (; *segment; ++segment)
bitset.set(*reinterpret_cast<const unsigned char *>(segment));
for (; *src && !bitset.test(*reinterpret_cast<const unsigned char *>(src));
++src)
;
return static_cast<size_t>(src - initial);
}
// Given the similarities between strtok and strtok_r, we can implement both
// using a utility function. On the first call, 'src' is scanned for the
// first character not found in 'delimiter_string'. Once found, it scans until
// the first character in the 'delimiter_string' or the null terminator is
// found. We define this span as a token. The end of the token is appended with
// a null terminator, and the token is returned. The point where the last token
// is found is then stored within 'context' for subsequent calls. Subsequent
// calls will use 'context' when a nullptr is passed in for 'src'. Once the null
// terminating character is reached, returns a nullptr.
template <bool SkipDelim = true>
LIBC_INLINE char *string_token(char *__restrict src,
const char *__restrict delimiter_string,
char **__restrict context) {
// Return nullptr immediately if both src AND context are nullptr
if (LIBC_UNLIKELY(src == nullptr && ((src = *context) == nullptr)))
return nullptr;
static_assert(CHAR_BIT == 8, "bitset of 256 assumes char is 8 bits");
cpp::bitset<256> delims;
for (; *delimiter_string != '\0'; ++delimiter_string)
delims.set(*reinterpret_cast<const unsigned char *>(delimiter_string));
unsigned char *tok_start = reinterpret_cast<unsigned char *>(src);
if constexpr (SkipDelim)
while (*tok_start != '\0' && delims.test(*tok_start))
++tok_start;
if (*tok_start == '\0' && SkipDelim) {
*context = nullptr;
return nullptr;
}
unsigned char *tok_end = tok_start;
while (*tok_end != '\0' && !delims.test(*tok_end))
++tok_end;
if (*tok_end == '\0') {
*context = nullptr;
} else {
*tok_end = '\0';
*context = reinterpret_cast<char *>(tok_end + 1);
}
return reinterpret_cast<char *>(tok_start);
}
LIBC_INLINE size_t strlcpy(char *__restrict dst, const char *__restrict src,
size_t size) {
size_t len = internal::string_length(src);
if (!size)
return len;
size_t n = len < size - 1 ? len : size - 1;
inline_memcpy(dst, src, n);
dst[n] = '\0';
return len;
}
template <bool ReturnNull = true>
LIBC_INLINE constexpr static char *strchr_implementation(const char *src,
int c) {
char ch = static_cast<char>(c);
for (; *src && *src != ch; ++src)
;
char *ret = ReturnNull ? nullptr : const_cast<char *>(src);
return *src == ch ? const_cast<char *>(src) : ret;
}
LIBC_INLINE constexpr static char *strrchr_implementation(const char *src,
int c) {
char ch = static_cast<char>(c);
char *last_occurrence = nullptr;
while (true) {
if (*src == ch)
last_occurrence = const_cast<char *>(src);
if (!*src)
return last_occurrence;
++src;
}
}
// Returns the first occurrence of 'ch' within the first 'n' characters of
// 'src'. If 'ch' is not found, returns nullptr.
LIBC_INLINE void *find_first_character(const unsigned char *src,
unsigned char ch, size_t max_strlen) {
return find_first_character_impl(src, ch, max_strlen);
}
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STRING_STRING_UTILS_H
|