@@ -59,35 +59,110 @@ std::size_t c_strLength(const char *s) {
5959 constexpr auto MSBs = S{S::MostSignificantBit};
6060 for (auto base = s;; base += 8 ) {
6161 memcpy (&bytes.m_v , base, 8 );
62- // A null byte is detected in two steps:
63- // 1. it has the MSB off, and
64- // the least significant bits are also off.
65- // The swar library allows the detection of lsbs off
66- // By comparing greater equal to 0,
67- // 0 can only be greater-equal to a byte with LSBs 0
68- auto haveMSB_cleared = bytes ^ MSBs;
69- auto lsbNulls = zoo::swar::greaterEqual_MSB_off (S{0 }, bytes);
70- auto nulls = swar::asBooleanSWAR (haveMSB_cleared & lsbNulls);
71- if (nulls) {
62+ auto nulls = zoo::swar::equals (bytes, S{0 });
63+ if (nulls) { // there is a null!
7264 auto firstNullIndex = nulls.lsbIndex ();
7365 return firstNullIndex + (base - s);
7466 }
7567 }
7668}
7769
78- std::size_t c_strLength_MoreNaturalButSlightlyWorse (const char *s) {
70+ std::size_t c_strLength_ManualComparison (const char *s) {
7971 std::size_t rv = 0 ;
8072 using S = swar::SWAR<8 , std::size_t >;
8173 S bytes;
8274 constexpr auto MSBs = S{S::MostSignificantBit};
8375 for (auto base = s;; base += 8 ) {
8476 memcpy (&bytes.m_v , base, 8 );
85- auto nulls = zoo::swar::equals (bytes, S{0 });
86- if (nulls) { // there is a null!
77+ // A null byte is detected in two steps:
78+ // 1. it has the MSB off, and
79+ // the least significant bits are also off.
80+ // The swar library allows the detection of lsbs off
81+ // By comparing greater equal to 0,
82+ // 0 can only be greater-equal to a byte with LSBs 0
83+ auto haveMSB_cleared = bytes ^ MSBs;
84+ auto lsbNulls = zoo::swar::greaterEqual_MSB_off (S{0 }, bytes & ~MSBs);
85+ auto nulls = swar::asBooleanSWAR (haveMSB_cleared & lsbNulls);
86+ if (nulls) {
8787 auto firstNullIndex = nulls.lsbIndex ();
8888 return firstNullIndex + (base - s);
8989 }
9090 }
9191}
9292
9393}
94+
95+ // / \brief This is the last non-platform specific "generic" strlen in GLibC.
96+ // / Taken from https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=string/strlen.c;hb=6d7e8eda9b85b08f207a6dc6f187e94e4817270f
97+ // / that dates to 2023-01-06 (a year ago at the time of writing)
98+ std::size_t
99+ STRLEN_old (const char *str)
100+ {
101+ const char *char_ptr;
102+ const unsigned long int *longword_ptr;
103+ unsigned long int longword, himagic, lomagic;
104+
105+ /* Handle the first few characters by reading one character at a time.
106+ Do this until CHAR_PTR is aligned on a longword boundary. */
107+ for (char_ptr = str; ((unsigned long int ) char_ptr
108+ & (sizeof (longword) - 1 )) != 0 ;
109+ ++char_ptr)
110+ if (*char_ptr == ' \0 ' )
111+ return char_ptr - str;
112+
113+ /* All these elucidatory comments refer to 4-byte longwords,
114+ but the theory applies equally well to 8-byte longwords. */
115+
116+ longword_ptr = (unsigned long int *) char_ptr;
117+
118+ /* Computing (longword - lomagic) sets the high bit of any corresponding
119+ byte that is either zero or greater than 0x80. The latter case can be
120+ filtered out by computing (~longword & himagic). The final result
121+ will always be non-zero if one of the bytes of longword is zero. */
122+ himagic = 0x80808080L ;
123+ lomagic = 0x01010101L ;
124+ if (sizeof (longword) > 4 )
125+ {
126+ /* 64-bit version of the magic. */
127+ /* Do the shift in two steps to avoid a warning if long has 32 bits. */
128+ himagic = ((himagic << 16 ) << 16 ) | himagic;
129+ lomagic = ((lomagic << 16 ) << 16 ) | lomagic;
130+ }
131+ if (sizeof (longword) > 8 )
132+ abort ();
133+
134+ /* Instead of the traditional loop which tests each character,
135+ we will test a longword at a time. The tricky part is testing
136+ if *any of the four* bytes in the longword in question are zero. */
137+ for (;;)
138+ {
139+ longword = *longword_ptr++;
140+
141+ if (((longword - lomagic) & ~longword & himagic) != 0 )
142+ {
143+ /* Which of the bytes was the zero? */
144+
145+ const char *cp = (const char *) (longword_ptr - 1 );
146+
147+ if (cp[0 ] == 0 )
148+ return cp - str;
149+ if (cp[1 ] == 0 )
150+ return cp - str + 1 ;
151+ if (cp[2 ] == 0 )
152+ return cp - str + 2 ;
153+ if (cp[3 ] == 0 )
154+ return cp - str + 3 ;
155+ if (sizeof (longword) > 4 )
156+ {
157+ if (cp[4 ] == 0 )
158+ return cp - str + 4 ;
159+ if (cp[5 ] == 0 )
160+ return cp - str + 5 ;
161+ if (cp[6 ] == 0 )
162+ return cp - str + 6 ;
163+ if (cp[7 ] == 0 )
164+ return cp - str + 7 ;
165+ }
166+ }
167+ }
168+ }
0 commit comments