ReactOS 0.4.16-dev-1946-g52006dd
strnlen.cpp
Go to the documentation of this file.
1//
2// strnlen.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines strnlen and wcsnlen, which return the length of a null-terminated
7// string, not including the null terminator itself, up to the specified maximum
8// number of characters.
9//
10#include <corecrt_internal.h>
12#include <stdlib.h>
13#include <string.h>
14
15
16
17// Disable "warning C4752: found Intel(R) Advanced Vector Extensions; consider
18// using /arch:AVX." We verify that we can use AVX2 before we execute those
19// instructions.
20#pragma warning(disable: 4752)
21
22
23
24//namespace // clang doesn't like this!
25//{
27 {
28 bounded, // strnlen mode; maximum_count is respected
29 unbounded, // strlen mode; maximum_count is ignored
30 };
31//}
32
33// This function returns true if we have reached the end of the range to be
34// searched for a terminator. For the bounded strnlen functions, we must
35// test to see whether
36template <strnlen_mode Mode>
37static __forceinline bool __cdecl last_reached(
38 void const* const it,
39 void const* const last
40 ) throw()
41{
42 return it == last;
43}
44
45template <>
47 void const* const it,
48 void const* const last
49 ) throw()
50{
53
54 return false;
55}
56
57
58
59// An implementation of strnlen using plain C, suitable for any architecture:
60template <strnlen_mode Mode, typename Element>
62_When_(maximum_count > _String_length_(string), _Post_satisfies_(return == _String_length_(string)))
63_When_(maximum_count <= _String_length_(string), _Post_satisfies_(return == maximum_count))
64static __forceinline size_t __cdecl common_strnlen_c(
65 Element const* const string,
66 size_t const maximum_count
68{
69 Element const* const last = string + maximum_count;
70 Element const* it = string;
71
72 for (; !last_reached<Mode>(it, last) && *it != '\0'; ++it)
73 {
74 }
75
76 return static_cast<size_t>(it - string);
77}
78
79#ifdef _CRT_SIMD_SUPPORT_AVAILABLE
80
81
82 template <strnlen_mode Mode, __crt_simd_isa Isa, typename Element>
84 _When_(maximum_count > _String_length_(string), _Post_satisfies_(return == _String_length_(string)))
85 _When_(maximum_count <= _String_length_(string), _Post_satisfies_(return == maximum_count))
86 size_t __cdecl common_strnlen_simd(
87 Element const* const string,
88 size_t const maximum_count
89 ) throw()
90#if (defined(__GNUC__) || defined(__clang__)) && !defined(_UCRT_BUILD_SSE2) && !defined(_UCRT_BUILD_AVX2)
91 ;
92#else
93 {
94 using traits = __crt_simd_traits<Isa, Element>;
95
96 // For efficient SIMD processing of the string, we will use a typical three-
97 // -phase computation:
98 //
99 // [1] We compute the number of bytes from the start of the string to the
100 // next element_size boundary and process these bytes individually. If
101 // we find a \0 we return immediately.
102 //
103 // [2] At this point, we now have a pointer to an aligned block of bytes.
104 // We process bytes in element_size chunks until there are fewer than
105 // element_size bytes remaining to be examined. If we find a chunk
106 // that contains a \0 we break out of the loop without advancing to
107 // the next chunk, to let the phase 3 loop reexamine the chunk.
108 //
109 // [3] We process the remaining bytes individually. If we find a \0 we
110 // return immediately.
111 //
112 // Note that in phase [2] we may read bytes beyond the terminator (and thus
113 // beyond the end of the string). This is okay, because we are reading
114 // aligned chunks, so a chunk will never straddle a page boundary and if we
115 // can read any byte from the chunk we can read all bytes from the chunk.
116 //
117 // Here we go...
118 uintptr_t const string_integer = reinterpret_cast<uintptr_t>(string);
119 if (string_integer % traits::element_size != 0)
120 {
121 // If the input string is itself unaligned (e.g. if it is a wchar_t*
122 // with an odd address), we can't align for vector processing. Switch
123 // back to the slow implementation:
124 return common_strnlen_c<Mode>(string, maximum_count);
125 }
126
127 // [1] Alignment Loop (Prefix)
128 uintptr_t const prefix_forward_offset = string_integer % traits::pack_size;
129 uintptr_t const prefix_reverse_offset = prefix_forward_offset == 0
130 ? 0
131 : traits::pack_size - prefix_forward_offset;
132
133 size_t const prefix_count = __min(maximum_count, prefix_reverse_offset / traits::element_size);
134 size_t const prefix_result = common_strnlen_c<bounded>(string, prefix_count);
135 if (prefix_result != prefix_count)
136 {
137 return prefix_result;
138 }
139
140 Element const* it = string + prefix_result;
141
142 // [2] Aligned Vector Loop (Middle)
143 __crt_simd_cleanup_guard<Isa> const simd_cleanup;
144
145 typename traits::pack_type const zero = traits::get_zero_pack();
146
147 size_t const middle_and_suffix_count = maximum_count - prefix_count;
148 size_t const suffix_count = middle_and_suffix_count % traits::pack_size;
149 size_t const middle_count = middle_and_suffix_count - suffix_count;
150
151 Element const* const middle_last = it + middle_count;
152 while (!last_reached<Mode>(it, middle_last))
153 {
154 auto const element_it = reinterpret_cast<typename traits::pack_type const*>(it);
155
156 bool const element_has_terminator = traits::compute_byte_mask(traits::compare_equals(*element_it, zero)) != 0;
157 if (element_has_terminator)
158 {
159 break;
160 }
161
162 it += traits::elements_per_pack;
163 }
164
165 // [3] Remainder Loop (Suffix)
166 Element const* const suffix_last = string + maximum_count;
167 for (; !last_reached<Mode>(it, suffix_last) && *it != '\0'; ++it)
168 {
169 }
170
171 // Either we have exhausted the buffer or we have found the terminator:
172 return static_cast<size_t>(it - string);
173 }
174
175#endif // (defined(__GNUC__) || defined(__clang__)) && !defined(_UCRT_BUILD_SSE2) && !defined(_UCRT_BUILD_AVX2)
176
177#endif // _CRT_SIMD_SUPPORT_AVAILABLE
178
179#if !defined(_UCRT_BUILD_SSE2) && !defined(_UCRT_BUILD_AVX2)
180
181template <strnlen_mode Mode, typename Element>
183_When_(maximum_count > _String_length_(string), _Post_satisfies_(return == _String_length_(string)))
184_When_(maximum_count <= _String_length_(string), _Post_satisfies_(return == maximum_count))
185static __forceinline size_t __cdecl common_strnlen(
186 Element const* const string,
187 size_t const maximum_count
188 ) throw()
189{
190 #ifdef _CRT_SIMD_SUPPORT_AVAILABLE
192 {
193 return common_strnlen_simd<Mode, __crt_simd_isa::avx2>(string, maximum_count);
194 }
196 {
197 return common_strnlen_simd<Mode, __crt_simd_isa::sse2>(string, maximum_count);
198 }
199 #endif
200
201 return common_strnlen_c<Mode>(string, maximum_count);
202}
203
204#if !defined(_M_ARM64) && !defined(_M_ARM64EC)
205
206extern "C" size_t __cdecl strnlen(
207 char const* const string,
208 size_t const maximum_count
209 )
210{
211 return common_strnlen<bounded>(reinterpret_cast<uint8_t const*>(string), maximum_count);
212}
213
214extern "C" size_t __cdecl wcsnlen(
215 wchar_t const* const string,
216 size_t const maximum_count
217 )
218{
219 return common_strnlen<bounded>(reinterpret_cast<uint16_t const*>(string), maximum_count);
220}
221
222#pragma function(wcslen)
223
224extern "C" size_t __cdecl wcslen(
225 wchar_t const* const string
226 )
227{
228 return common_strnlen<unbounded>(reinterpret_cast<uint16_t const*>(string), _CRT_UNBOUNDED_BUFFER_SIZE);
229}
230
231#endif // _M_ARM64
232#endif // !defined(_UCRT_BUILD_SSE2) && !defined(_UCRT_BUILD_AVX2)
#define __cdecl
Definition: accygwin.h:79
unsigned short int uint16_t
Definition: acefiex.h:54
return
Definition: dirsup.c:529
#define _CRT_UNBOUNDED_BUFFER_SIZE
char typename[32]
Definition: main.c:84
@ __ISA_AVAILABLE_SSE2
@ __ISA_AVAILABLE_AVX2
int __isa_available
unsigned int uintptr_t
Definition: intrin.h:47
char string[160]
Definition: util.h:11
static UINT UINT last
Definition: font.c:45
BYTE uint8_t
Definition: msvideo1.c:66
#define _Check_return_
Definition: no_sal2.h:60
#define _Post_satisfies_(e)
Definition: no_sal2.h:66
#define _When_(c, a)
Definition: no_sal2.h:38
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define __min(a, b)
Definition: stdlib.h:102
int zero
Definition: sehframes.cpp:29
size_t __cdecl strnlen(char const *const string, size_t const maximum_count)
Definition: strnlen.cpp:206
static __forceinline bool __cdecl last_reached(void const *const it, void const *const last)
Definition: strnlen.cpp:37
strnlen_mode
Definition: strnlen.cpp:27
@ unbounded
Definition: strnlen.cpp:29
@ bounded
Definition: strnlen.cpp:28
size_t __cdecl wcslen(wchar_t const *const string)
Definition: strnlen.cpp:224
__forceinline bool __cdecl last_reached< unbounded >(void const *const it, void const *const last)
Definition: strnlen.cpp:46
size_t __cdecl wcsnlen(wchar_t const *const string, size_t const maximum_count)
Definition: strnlen.cpp:214
_Check_return_ size_t const maximum_count throw()
Definition: strnlen.cpp:67
#define const
Definition: zconf.h:233