ReactOS 0.4.16-dev-737-g3368adc
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
24namespace
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_UCRT_ENABLE_EXTENDED_ISA
82
83 template <strnlen_mode Mode, __crt_simd_isa Isa, typename Element>
85 _When_(maximum_count > _String_length_(string), _Post_satisfies_(return == _String_length_(string)))
86 _When_(maximum_count <= _String_length_(string), _Post_satisfies_(return == maximum_count))
87 static __inline size_t __cdecl common_strnlen_simd(
88 Element const* const string,
89 size_t const maximum_count
90 ) throw()
91 {
92 using traits = __crt_simd_traits<Isa, Element>;
93
94 // For efficient SIMD processing of the string, we will use a typical three-
95 // -phase computation:
96 //
97 // [1] We compute the number of bytes from the start of the string to the
98 // next element_size boundary and process these bytes individually. If
99 // we find a \0 we return immediately.
100 //
101 // [2] At this point, we now have a pointer to an aligned block of bytes.
102 // We process bytes in element_size chunks until there are fewer than
103 // element_size bytes remaining to be examined. If we find a chunk
104 // that contains a \0 we break out of the loop without advancing to
105 // the next chunk, to let the phase 3 loop reexamine the chunk.
106 //
107 // [3] We process the remaining bytes individually. If we find a \0 we
108 // return immediately.
109 //
110 // Note that in phase [2] we may read bytes beyond the terminator (and thus
111 // beyond the end of the string). This is okay, because we are reading
112 // aligned chunks, so a chunk will never straddle a page boundary and if we
113 // can read any byte from the chunk we can read all bytes from the chunk.
114 //
115 // Here we go...
116 uintptr_t const string_integer = reinterpret_cast<uintptr_t>(string);
117 if (string_integer % traits::element_size != 0)
118 {
119 // If the input string is itself unaligned (e.g. if it is a wchar_t*
120 // with an odd address), we can't align for vector processing. Switch
121 // back to the slow implementation:
122 return common_strnlen_c<Mode>(string, maximum_count);
123 }
124
125 // [1] Alignment Loop (Prefix)
126 uintptr_t const prefix_forward_offset = string_integer % traits::pack_size;
127 uintptr_t const prefix_reverse_offset = prefix_forward_offset == 0
128 ? 0
129 : traits::pack_size - prefix_forward_offset;
130
131 size_t const prefix_count = __min(maximum_count, prefix_reverse_offset / traits::element_size);
132 size_t const prefix_result = common_strnlen_c<bounded>(string, prefix_count);
133 if (prefix_result != prefix_count)
134 {
135 return prefix_result;
136 }
137
138 Element const* it = string + prefix_result;
139
140 // [2] Aligned Vector Loop (Middle)
141 __crt_simd_cleanup_guard<Isa> const simd_cleanup;
142
143 typename traits::pack_type const zero = traits::get_zero_pack();
144
145 size_t const middle_and_suffix_count = maximum_count - prefix_count;
146 size_t const suffix_count = middle_and_suffix_count % traits::pack_size;
147 size_t const middle_count = middle_and_suffix_count - suffix_count;
148
149 Element const* const middle_last = it + middle_count;
150 while (!last_reached<Mode>(it, middle_last))
151 {
152 auto const element_it = reinterpret_cast<typename traits::pack_type const*>(it);
153
154 bool const element_has_terminator = traits::compute_byte_mask(traits::compare_equals(*element_it, zero)) != 0;
155 if (element_has_terminator)
156 {
157 break;
158 }
159
160 it += traits::elements_per_pack;
161 }
162
163 // [3] Remainder Loop (Suffix)
164 Element const* const suffix_last = string + maximum_count;
165 for (; !last_reached<Mode>(it, suffix_last) && *it != '\0'; ++it)
166 {
167 }
168
169 // Either we have exhausted the buffer or we have found the terminator:
170 return static_cast<size_t>(it - string);
171 }
172
173_UCRT_RESTORE_DEFAULT_ISA
174
175#endif // _CRT_SIMD_SUPPORT_AVAILABLE
176
177template <strnlen_mode Mode, typename Element>
179_When_(maximum_count > _String_length_(string), _Post_satisfies_(return == _String_length_(string)))
180_When_(maximum_count <= _String_length_(string), _Post_satisfies_(return == maximum_count))
181static __forceinline size_t __cdecl common_strnlen(
182 Element const* const string,
183 size_t const maximum_count
184 ) throw()
185{
186 #ifdef _CRT_SIMD_SUPPORT_AVAILABLE
188 {
189 return common_strnlen_simd<Mode, __crt_simd_isa::avx2>(string, maximum_count);
190 }
192 {
193 return common_strnlen_simd<Mode, __crt_simd_isa::sse2>(string, maximum_count);
194 }
195 #endif
196
197 return common_strnlen_c<Mode>(string, maximum_count);
198}
199
200#if !defined(_M_ARM64) && !defined(_M_ARM64EC)
201
202extern "C" size_t __cdecl strnlen(
203 char const* const string,
204 size_t const maximum_count
205 )
206{
207 return common_strnlen<bounded>(reinterpret_cast<uint8_t const*>(string), maximum_count);
208}
209
210extern "C" size_t __cdecl wcsnlen(
211 wchar_t const* const string,
212 size_t const maximum_count
213 )
214{
215 return common_strnlen<bounded>(reinterpret_cast<uint16_t const*>(string), maximum_count);
216}
217
218#pragma function(wcslen)
219
220extern "C" size_t __cdecl wcslen(
221 wchar_t const* const string
222 )
223{
224 return common_strnlen<unbounded>(reinterpret_cast<uint16_t const*>(string), _CRT_UNBOUNDED_BUFFER_SIZE);
225}
226
227#endif // _M_ARM64
#define __inline
Definition: _wctype.cpp:15
#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
#define __min(a, b)
Definition: stdlib.h:102
@ __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:325
int zero
Definition: sehframes.cpp:29
size_t __cdecl strnlen(char const *const string, size_t const maximum_count)
Definition: strnlen.cpp:202
static __forceinline bool __cdecl last_reached(void const *const it, void const *const last)
Definition: strnlen.cpp:37
size_t __cdecl wcslen(wchar_t const *const string)
Definition: strnlen.cpp:220
__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:210
_Check_return_ size_t const maximum_count throw()
Definition: strnlen.cpp:67
#define const
Definition: zconf.h:233