POD => trivial, also clarify tstrlen
parent
dab034d9e0
commit
69d5d11da1
|
@ -84,7 +84,7 @@ enum class stream_seek {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T = char, bool = std::is_pod_v<T>>
|
template<typename T = char, bool = std::is_trivial_v<T>>
|
||||||
struct stream_range;
|
struct stream_range;
|
||||||
|
|
||||||
/** @brief Thrown on stream errors. */
|
/** @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
|
* 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.
|
* 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
|
* 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).
|
* @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.
|
/** @brief Writes several values into the stream.
|
||||||
*
|
*
|
||||||
* Uses write_bytes() to write `count` values from `v` 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.
|
* @throws ostd::stream_error on write failure.
|
||||||
*/
|
*/
|
||||||
|
@ -433,7 +433,7 @@ struct stream {
|
||||||
|
|
||||||
/** @brief Writes a single value into the 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.
|
* @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.
|
* Uses read_bytes() to read `count` values into `v` from the stream.
|
||||||
* If an end-of-stream is encountered while reading, this does not
|
* If an end-of-stream is encountered while reading, this does not
|
||||||
* throw, but it returns the number of entire values successfully read.
|
* 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.
|
* @returns The number of whole values read.
|
||||||
*
|
*
|
||||||
|
@ -462,7 +462,7 @@ struct stream {
|
||||||
/** @brief Reads a single value from the stream.
|
/** @brief Reads a single value from the stream.
|
||||||
*
|
*
|
||||||
* If the value couldn't be read (reading failed or end-of-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.
|
* @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.
|
/** @brief Reads a single value from the stream.
|
||||||
*
|
*
|
||||||
* If the value couldn't be read (reading failed or end-of-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.
|
* @returns The read value.
|
||||||
*
|
*
|
||||||
|
@ -548,7 +548,7 @@ private:
|
||||||
* example).
|
* example).
|
||||||
*
|
*
|
||||||
* This template is a specialization of undefined base type because stream
|
* 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
|
* @see stream_line_range
|
||||||
*/
|
*/
|
||||||
|
@ -660,7 +660,7 @@ inline stream_range<T> stream::iter() {
|
||||||
* The lines are read using ostd::stream::get_line().
|
* The lines are read using ostd::stream::get_line().
|
||||||
*
|
*
|
||||||
* You can provide a custom type for characters, by default it's `char`.
|
* 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
|
* 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,
|
* container type over `T` which can append at the end. By default,
|
||||||
|
|
|
@ -20,24 +20,38 @@ template<typename C>
|
||||||
inline std::size_t tstrlen_impl(C const *p) noexcept {
|
inline std::size_t tstrlen_impl(C const *p) noexcept {
|
||||||
using SL = std::numeric_limits<std::size_t>;
|
using SL = std::numeric_limits<std::size_t>;
|
||||||
using UL = std::numeric_limits<std::make_unsigned_t<C>>;
|
using UL = std::numeric_limits<std::make_unsigned_t<C>>;
|
||||||
|
/* low bits of each UL contained in SL (0000000100000001... etc) */
|
||||||
constexpr std::size_t Lbits = SL::max() / UL::max();
|
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);
|
constexpr std::size_t Hbits = Lbits << (UL::digits - 1);
|
||||||
|
|
||||||
C const *bp = p;
|
C const *bp = p;
|
||||||
|
/* 1 unit or less per size_t, simple loop */
|
||||||
if constexpr(sizeof(C) >= sizeof(std::size_t)) {
|
if constexpr(sizeof(C) >= sizeof(std::size_t)) {
|
||||||
goto sloop;
|
goto sloop;
|
||||||
}
|
}
|
||||||
|
/* need a pointer aligned to sizeof(size_t) */
|
||||||
for (; std::uintptr_t(p) % sizeof(std::size_t); ++p) {
|
for (; std::uintptr_t(p) % sizeof(std::size_t); ++p) {
|
||||||
if (!*p) {
|
if (!*p) {
|
||||||
return (p - bp);
|
return (p - bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
/* (e.g. x86_64 => sizeof(size_t) == 8 * sizeof(char) */
|
||||||
auto *wp = reinterpret_cast<std::size_t const *>(p);
|
auto *wp = reinterpret_cast<std::size_t const *>(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) {}
|
for (; !(((*wp - Lbits) & ~*wp) & Hbits); ++wp) {}
|
||||||
p = reinterpret_cast<C const *>(wp);
|
p = reinterpret_cast<C const *>(wp);
|
||||||
}
|
}
|
||||||
sloop:
|
sloop:
|
||||||
|
/* either all of the string if goto'd, or contains terminating zero */
|
||||||
for (; *p; ++p) {}
|
for (; *p; ++p) {}
|
||||||
return (p - bp);
|
return (p - bp);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue