forked from OctaForge/libostd
POD => trivial, also clarify tstrlen
This commit is contained in:
parent
dab034d9e0
commit
69d5d11da1
2 changed files with 23 additions and 9 deletions
|
@ -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;
|
||||
|
||||
/** @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<T> 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,
|
||||
|
|
|
@ -20,24 +20,38 @@ template<typename C>
|
|||
inline std::size_t tstrlen_impl(C const *p) noexcept {
|
||||
using SL = std::numeric_limits<std::size_t>;
|
||||
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();
|
||||
/* 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<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) {}
|
||||
p = reinterpret_cast<C const *>(wp);
|
||||
}
|
||||
sloop:
|
||||
/* either all of the string if goto'd, or contains terminating zero */
|
||||
for (; *p; ++p) {}
|
||||
return (p - bp);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue