diff --git a/ostd/stream.hh b/ostd/stream.hh index 6dd2dc5..8de3a99 100644 --- a/ostd/stream.hh +++ b/ostd/stream.hh @@ -84,7 +84,7 @@ enum class stream_seek { }; -template> +template> struct stream_range; /** @brief Thrown on stream errors. */ @@ -398,7 +398,7 @@ struct stream { * By default, it's a `char` range that can be read from if the stream * can be read from and written into if the stream can be written into. * You can override the type by passing in the template parameter. The - * type must always be POD. + * type must always be trivial. * * @tparam T The type to use for reading/writing (`char` by default). * @@ -422,7 +422,7 @@ struct stream { /** @brief Writes several values into the stream. * * Uses write_bytes() to write `count` values from `v` into the stream. - * The type must be POD. + * The type must be trivial. * * @throws ostd::stream_error on write failure. */ @@ -433,7 +433,7 @@ struct stream { /** @brief Writes a single value into the stream. * - * Uses write_bytes() to write the value. The type must be POD. + * Uses write_bytes() to write the value. The type must be trivial. * * @throws ostd::stream_error on write failure. */ @@ -447,7 +447,7 @@ struct stream { * Uses read_bytes() to read `count` values into `v` from the stream. * If an end-of-stream is encountered while reading, this does not * throw, but it returns the number of entire values successfully read. - * The type must be POD. + * The type must be trivial. * * @returns The number of whole values read. * @@ -462,7 +462,7 @@ struct stream { /** @brief Reads a single value from the stream. * * If the value couldn't be read (reading failed or end-of-stream - * occured), this throws ostd::stream_error. The type must be POD. + * occured), this throws ostd::stream_error. The type must be trivial. * * @throws ostd::stream_error on read failure or end-of-stream. */ @@ -476,7 +476,7 @@ struct stream { /** @brief Reads a single value from the stream. * * If the value couldn't be read (reading failed or end-of-stream - * occured), this throws ostd::stream_error. The type must be POD. + * occured), this throws ostd::stream_error. The type must be trivial. * * @returns The read value. * @@ -548,7 +548,7 @@ private: * example). * * This template is a specialization of undefined base type because stream - * ranges only work with POD types. + * ranges only work with trivial types. * * @see stream_line_range */ @@ -660,7 +660,7 @@ inline stream_range stream::iter() { * The lines are read using ostd::stream::get_line(). * * You can provide a custom type for characters, by default it's `char`. - * It must be POD. + * It must be trivial. * * You can also provide a custom type used to hold the line, which must be a * container type over `T` which can append at the end. By default, diff --git a/src/string.cc b/src/string.cc index 94281ea..65ac807 100644 --- a/src/string.cc +++ b/src/string.cc @@ -20,24 +20,38 @@ template inline std::size_t tstrlen_impl(C const *p) noexcept { using SL = std::numeric_limits; using UL = std::numeric_limits>; + /* low bits of each UL contained in SL (0000000100000001... etc) */ constexpr std::size_t Lbits = SL::max() / UL::max(); + /* high bits of each UL contained in SL (1000000010000000... etc) */ constexpr std::size_t Hbits = Lbits << (UL::digits - 1); C const *bp = p; + /* 1 unit or less per size_t, simple loop */ if constexpr(sizeof(C) >= sizeof(std::size_t)) { goto sloop; } + /* need a pointer aligned to sizeof(size_t) */ for (; std::uintptr_t(p) % sizeof(std::size_t); ++p) { if (!*p) { return (p - bp); } } { + /* (e.g. x86_64 => sizeof(size_t) == 8 * sizeof(char) */ auto *wp = reinterpret_cast(p); + /* check if any unit in the size_t is zero, in binary: + * + * XXX1 - 0001 => XXX0; XXX0 & YYY0 => 0000; 0000 & 1000 => 0000 + * XX10 - 0001 => XX01; XX01 & YY01 => 0001; 0001 & 1000 => 0000 + * 0000 - 0001 => 1111; 1111 & 1111 => 1111; 1111 & 1000 => 1000 + * + * if the check passes, a terminating zero is in that size_t, break + */ for (; !(((*wp - Lbits) & ~*wp) & Hbits); ++wp) {} p = reinterpret_cast(wp); } sloop: + /* either all of the string if goto'd, or contains terminating zero */ for (; *p; ++p) {} return (p - bp); }