diff options
Diffstat (limited to 'libc/src')
-rw-r--r-- | libc/src/__support/FPUtil/CMakeLists.txt | 13 | ||||
-rw-r--r-- | libc/src/__support/FPUtil/bfloat16.h | 25 | ||||
-rw-r--r-- | libc/src/__support/FPUtil/comparison_operations.h | 114 | ||||
-rw-r--r-- | libc/src/__support/FPUtil/rounding_mode.h | 67 | ||||
-rw-r--r-- | libc/src/__support/GPU/allocator.cpp | 138 | ||||
-rw-r--r-- | libc/src/__support/RPC/rpc_server.h | 6 | ||||
-rw-r--r-- | libc/src/__support/wchar/mbrtowc.cpp | 3 | ||||
-rw-r--r-- | libc/src/wchar/CMakeLists.txt | 14 | ||||
-rw-r--r-- | libc/src/wchar/mbtowc.cpp | 5 | ||||
-rw-r--r-- | libc/src/wchar/wchar_utils.h | 45 | ||||
-rw-r--r-- | libc/src/wchar/wcscspn.cpp | 18 | ||||
-rw-r--r-- | libc/src/wchar/wcsspn.cpp | 18 |
12 files changed, 349 insertions, 117 deletions
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index cc941f2..3024ac6 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -16,6 +16,7 @@ add_header_library( rounding_mode.h DEPENDS libc.hdr.fenv_macros + libc.src.__support.CPP.type_traits libc.src.__support.macros.attributes libc.src.__support.macros.properties.architectures libc.src.__support.macros.sanitizer @@ -210,6 +211,17 @@ add_header_library( ) add_header_library( + comparison_operations + HDRS + comparison_operations.h + DEPENDS + .fenv_impl + .fp_bits + libc.src.__support.CPP.type_traits + libc.src.__support.macros.config +) + +add_header_library( hypot HDRS Hypot.h @@ -263,6 +275,7 @@ add_header_library( bfloat16.h DEPENDS .cast + .comparison_operations .dyadic_float libc.src.__support.CPP.bit libc.src.__support.CPP.type_traits diff --git a/libc/src/__support/FPUtil/bfloat16.h b/libc/src/__support/FPUtil/bfloat16.h index bc0b8b2..84a0dca 100644 --- a/libc/src/__support/FPUtil/bfloat16.h +++ b/libc/src/__support/FPUtil/bfloat16.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/comparison_operations.h" #include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/macros/config.h" #include "src/__support/macros/properties/types.h" @@ -57,6 +58,30 @@ struct BFloat16 { uint32_t x_bits = static_cast<uint32_t>(bits) << 16U; return cpp::bit_cast<float>(x_bits); } + + LIBC_INLINE bool operator==(BFloat16 other) const { + return fputil::equals(*this, other); + } + + LIBC_INLINE bool operator!=(BFloat16 other) const { + return !fputil::equals(*this, other); + } + + LIBC_INLINE bool operator<(BFloat16 other) const { + return fputil::less_than(*this, other); + } + + LIBC_INLINE bool operator<=(BFloat16 other) const { + return fputil::less_than_or_equals(*this, other); + } + + LIBC_INLINE bool operator>(BFloat16 other) const { + return fputil::greater_than(*this, other); + } + + LIBC_INLINE bool operator>=(BFloat16 other) const { + return fputil::greater_than_or_equals(*this, other); + } }; // struct BFloat16 } // namespace fputil diff --git a/libc/src/__support/FPUtil/comparison_operations.h b/libc/src/__support/FPUtil/comparison_operations.h new file mode 100644 index 0000000..ff62ce0 --- /dev/null +++ b/libc/src/__support/FPUtil/comparison_operations.h @@ -0,0 +1,114 @@ +//===-- Comparison operations on floating point numbers ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H + +#include "FEnvImpl.h" +#include "FPBits.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// All predicates are hereby implemented as per IEEE Std 754-2019 +// Implements compareQuietEqual predicate +// Rules for comparison within the same floating point type +// 1. +0 = −0 +// 2. (i) +inf = +inf +// (ii) -inf = -inf +// (iii) -inf != +inf +// 3. Any comparison with NaN returns false +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> equals(T x, + T y) { + using FPBits = FPBits<T>; + FPBits x_bits(x); + FPBits y_bits(y); + + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) + fputil::raise_except_if_required(FE_INVALID); + + // NaN == x returns false for every x + if (x_bits.is_nan() || y_bits.is_nan()) + return false; + + // +/- 0 == +/- 0 + if (x_bits.is_zero() && y_bits.is_zero()) + return true; + + return x_bits.uintval() == y_bits.uintval(); +} + +// Implements compareSignalingLess predicate +// Section 5.11 Rules: +// 1. -inf < x (x != -inf) +// 2. x < +inf (x != +inf) +// 3. Any comparison with NaN return false +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> less_than(T x, + T y) { + using FPBits = FPBits<T>; + FPBits x_bits(x); + FPBits y_bits(y); + + // Any comparison with NaN returns false + if (x_bits.is_nan() || y_bits.is_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return false; + } + + if (x_bits.is_zero() && y_bits.is_zero()) + return false; + + if (x_bits.is_neg() && y_bits.is_pos()) + return true; + + if (x_bits.is_pos() && y_bits.is_neg()) + return false; + + // since floating-point numbers are stored in the format: s | e | m + // we can directly compare the uintval's + + // both negative + if (x_bits.is_neg()) + return x_bits.uintval() > y_bits.uintval(); + + // both positive + return x_bits.uintval() < y_bits.uintval(); +} + +// Implements compareSignalingGreater predicate +// x < y => y > x +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> +greater_than(T x, T y) { + return less_than(y, x); +} + +// Implements compareSignalingLessEqual predicate +// x <= y => (x < y) || (x == y) +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> +less_than_or_equals(T x, T y) { + return less_than(x, y) || equals(x, y); +} + +// Implements compareSignalingGreaterEqual predicate +// x >= y => (x > y) || (x == y) => (y < x) || (x == y) +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, bool> +greater_than_or_equals(T x, T y) { + return less_than(y, x) || equals(x, y); +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_COMPARISONOPERATIONS_H diff --git a/libc/src/__support/FPUtil/rounding_mode.h b/libc/src/__support/FPUtil/rounding_mode.h index bc66d09..4ee0a0b 100644 --- a/libc/src/__support/FPUtil/rounding_mode.h +++ b/libc/src/__support/FPUtil/rounding_mode.h @@ -10,6 +10,7 @@ #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H #include "hdr/fenv_macros.h" +#include "src/__support/CPP/type_traits.h" // is_constant_evaluated #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" @@ -20,18 +21,26 @@ namespace fputil { // Using the following observation: // 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO // = 0x1.000002f for FE_UPWARD. -LIBC_INLINE bool fenv_is_round_up() { - volatile float x = 0x1.0p-25f; - return (1.0f + x != 1.0f); +LIBC_INLINE static constexpr bool fenv_is_round_up() { + if (cpp::is_constant_evaluated()) { + return false; + } else { + volatile float x = 0x1.0p-25f; + return (1.0f + x != 1.0f); + } } // Quick free-standing test whether fegetround() == FE_DOWNWARD. // Using the following observation: // -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO // = -0x1.000002f for FE_DOWNWARD. -LIBC_INLINE bool fenv_is_round_down() { - volatile float x = 0x1.0p-25f; - return (-1.0f - x != -1.0f); +LIBC_INLINE static constexpr bool fenv_is_round_down() { + if (cpp::is_constant_evaluated()) { + return false; + } else { + volatile float x = 0x1.0p-25f; + return (-1.0f - x != -1.0f); + } } // Quick free-standing test whether fegetround() == FE_TONEAREST. @@ -40,10 +49,14 @@ LIBC_INLINE bool fenv_is_round_down() { // = 0x1.100002p0f for FE_UPWARD, // 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD // = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO -LIBC_INLINE bool fenv_is_round_to_nearest() { - static volatile float x = 0x1.0p-24f; - float y = x; - return (1.5f + y == 1.5f - y); +LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() { + if (cpp::is_constant_evaluated()) { + return true; + } else { + volatile float x = 0x1.0p-24f; + float y = 1.5f + x; + return (y == 1.5f - x); + } } // Quick free-standing test whether fegetround() == FE_TOWARDZERO. @@ -56,23 +69,31 @@ LIBC_INLINE bool fenv_is_round_to_nearest() { // (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO // = 2^-22 for FE_TONEAREST, FE_UPWARD // = 0 for FE_DOWNWARD -LIBC_INLINE bool fenv_is_round_to_zero() { - static volatile float x = 0x1.0p-24f; - float y = x; - return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); +LIBC_INLINE static constexpr bool fenv_is_round_to_zero() { + if (cpp::is_constant_evaluated()) { + return false; + } else { + volatile float x = 0x1.0p-24f; + volatile float y = 0x1.000002p0f + x; + return (y + (-1.0f - x) == 0x1.0p-23f); + } } // Quick free standing get rounding mode based on the above observations. -LIBC_INLINE int quick_get_round() { - static volatile float x = 0x1.0p-24f; - float y = x; - float z = (0x1.000002p0f + y) + (-1.0f - y); +LIBC_INLINE static constexpr int quick_get_round() { + if (cpp::is_constant_evaluated()) { + return FE_TONEAREST; + } else { + volatile float x = 0x1.0p-24f; + volatile float y = 0x1.000002p0f + x; + float z = y + (-1.0f - x); - if (z == 0.0f) - return FE_DOWNWARD; - if (z == 0x1.0p-23f) - return FE_TOWARDZERO; - return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; + if (z == 0.0f) + return FE_DOWNWARD; + if (z == 0x1.0p-23f) + return FE_TOWARDZERO; + return (2.0f + x == 2.0f) ? FE_TONEAREST : FE_UPWARD; + } } } // namespace fputil diff --git a/libc/src/__support/GPU/allocator.cpp b/libc/src/__support/GPU/allocator.cpp index 7923fbb..866aea7 100644 --- a/libc/src/__support/GPU/allocator.cpp +++ b/libc/src/__support/GPU/allocator.cpp @@ -34,13 +34,12 @@ constexpr static uint32_t BITS_IN_WORD = sizeof(uint32_t) * 8; constexpr static uint32_t MIN_SIZE = 16; constexpr static uint32_t MIN_ALIGNMENT = MIN_SIZE - 1; +// The number of times to attempt claiming an in-progress slab allocation. +constexpr static uint32_t MAX_TRIES = 128; + // A sentinel used to indicate an invalid but non-null pointer value. constexpr static uint64_t SENTINEL = cpp::numeric_limits<uint64_t>::max(); -// The number of times we will try starting on a single index before skipping -// past it. -constexpr static uint32_t MAX_TRIES = 512; - static_assert(!(ARRAY_SIZE & (ARRAY_SIZE - 1)), "Must be a power of two"); namespace impl { @@ -92,20 +91,10 @@ static inline uint32_t xorshift32(uint32_t &state) { return state * 0x9e3779bb; } -// Final stage of murmurhash used to get a unique index for the global array -static inline uint32_t hash(uint32_t x) { - x ^= x >> 16; - x *= 0x85ebca6b; - x ^= x >> 13; - x *= 0xc2b2ae35; - x ^= x >> 16; - return x; -} - // Rounds the input value to the closest permitted chunk size. Here we accept // the sum of the closest three powers of two. For a 2MiB slab size this is 48 // different chunk sizes. This gives us average internal fragmentation of 87.5%. -static inline uint32_t get_chunk_size(uint32_t x) { +static inline constexpr uint32_t get_chunk_size(uint32_t x) { uint32_t y = x < MIN_SIZE ? MIN_SIZE : x; uint32_t pow2 = BITS_IN_WORD - cpp::countl_zero(y - 1); @@ -123,6 +112,16 @@ static inline uint32_t get_chunk_size(uint32_t x) { return (s3 + MIN_ALIGNMENT) & ~MIN_ALIGNMENT; } +// Converts a chunk size into an index suitable for a statically sized array. +static inline constexpr uint32_t get_chunk_id(uint32_t x) { + if (x <= MIN_SIZE) + return 0; + uint32_t y = x >> 4; + if (x < MIN_SIZE << 2) + return cpp::popcount(y); + return cpp::popcount(y) + 3 * (BITS_IN_WORD - cpp::countl_zero(y)) - 7; +} + // Rounds to the nearest power of two. template <uint32_t N, typename T> static inline constexpr T round_up(const T x) { @@ -143,6 +142,12 @@ static inline constexpr bool is_pow2(uint64_t x) { return x && (x & (x - 1)) == 0; } +// Where this chunk size should start looking in the global array. +static inline constexpr uint32_t start_index(uint32_t chunk_index) { + return (ARRAY_SIZE * impl::get_chunk_id(chunk_index)) / + impl::get_chunk_id(SLAB_SIZE / 2); +} + } // namespace impl /// A slab allocator used to hand out identically sized slabs of memory. @@ -251,12 +256,18 @@ struct Slab { // The uniform mask represents which lanes contain a uniform target pointer. // We attempt to place these next to each other. void *result = nullptr; + uint32_t after = ~0u; + uint32_t old_index = 0; for (uint64_t mask = lane_mask; mask; mask = gpu::ballot(lane_mask, !result)) { if (result) continue; - uint32_t start = gpu::broadcast_value(lane_mask, impl::xorshift32(state)); + // We try using any known empty bits from the previous attempt first. + uint32_t start = gpu::shuffle(mask, cpp::countr_zero(uniform & mask), + ~after ? (old_index & ~(BITS_IN_WORD - 1)) + + cpp::countr_zero(~after) + : impl::xorshift32(state)); uint32_t id = impl::lane_count(uniform & mask); uint32_t index = (start + id) % usable_bits(chunk_size); @@ -266,8 +277,9 @@ struct Slab { // Get the mask of bits destined for the same slot and coalesce it. uint64_t match = uniform & gpu::match_any(mask, slot); uint32_t length = cpp::popcount(match); - uint32_t bitmask = static_cast<uint32_t>((uint64_t(1) << length) - 1) - << bit; + uint32_t bitmask = gpu::shuffle( + mask, cpp::countr_zero(match), + static_cast<uint32_t>((uint64_t(1) << length) - 1) << bit); uint32_t before = 0; if (gpu::get_lane_id() == static_cast<uint32_t>(cpp::countr_zero(match))) @@ -278,6 +290,9 @@ struct Slab { result = ptr_from_index(index, chunk_size); else sleep_briefly(); + + after = before | bitmask; + old_index = index; } cpp::atomic_thread_fence(cpp::MemoryOrder::ACQUIRE); @@ -451,66 +466,65 @@ public: // The global array used to search for a valid slab to allocate from. static GuardPtr slots[ARRAY_SIZE] = {}; +// Keep a cache of the last successful slot for each chunk size. Initialize it +// to an even spread of the total size. Must be updated if the chunking scheme +// changes. +#define S(X) (impl::start_index(X)) +static cpp::Atomic<uint32_t> indices[] = { + S(16), S(32), S(48), S(64), S(96), S(112), S(128), + S(192), S(224), S(256), S(384), S(448), S(512), S(768), + S(896), S(1024), S(1536), S(1792), S(2048), S(3072), S(3584), + S(4096), S(6144), S(7168), S(8192), S(12288), S(14336), S(16384), + S(24576), S(28672), S(32768), S(49152), S(57344), S(65536), S(98304), + S(114688), S(131072), S(196608), S(229376), S(262144), S(393216), S(458752), + S(524288), S(786432), S(917504), S(1048576)}; +#undef S + // Tries to find a slab in the table that can support the given chunk size. static Slab *find_slab(uint32_t chunk_size) { - // We start at a hashed value to spread out different chunk sizes. - uint32_t start = impl::hash(chunk_size); - uint64_t lane_mask = gpu::get_lane_mask(); - uint64_t uniform = gpu::match_any(lane_mask, chunk_size); - - Slab *result = nullptr; - uint32_t nudge = 0; - for (uint64_t mask = lane_mask; mask; - mask = gpu::ballot(lane_mask, !result), ++nudge) { - uint32_t index = cpp::numeric_limits<uint32_t>::max(); - for (uint32_t offset = nudge / MAX_TRIES; - gpu::ballot(lane_mask, index == cpp::numeric_limits<uint32_t>::max()); - offset += cpp::popcount(uniform & lane_mask)) { - uint32_t candidate = - (start + offset + impl::lane_count(uniform & lane_mask)) % ARRAY_SIZE; - uint64_t available = - gpu::ballot(lane_mask, slots[candidate].use_count() < - Slab::available_chunks(chunk_size)); - uint32_t new_index = gpu::shuffle( - lane_mask, cpp::countr_zero(available & uniform), candidate); - - // Each uniform group will use the first empty slot they find. - if ((index == cpp::numeric_limits<uint32_t>::max() && - (available & uniform))) - index = new_index; - - // Guaruntees that this loop will eventuall exit if there is no space. - if (offset >= ARRAY_SIZE) { - result = reinterpret_cast<Slab *>(SENTINEL); - index = 0; - } - } + // We start at the index of the last successful allocation for this kind. + uint32_t chunk_id = impl::get_chunk_id(chunk_size); + uint32_t start = indices[chunk_id].load(cpp::MemoryOrder::RELAXED); + uint64_t uniform = gpu::match_any(gpu::get_lane_mask(), chunk_size); + + for (uint32_t offset = 0; offset < ARRAY_SIZE; ++offset) { + uint32_t index = + !offset ? start : (impl::start_index(chunk_size) + offset) % ARRAY_SIZE; - // Try to claim a slot for the found slot. - if (!result) { + if (slots[index].use_count() < Slab::available_chunks(chunk_size)) { + uint64_t lane_mask = gpu::get_lane_mask(); uint64_t reserved = 0; - Slab *slab = slots[index].try_lock(lane_mask & mask, uniform & mask, + + Slab *slab = slots[index].try_lock(lane_mask, uniform & lane_mask, reserved, chunk_size, index); + + // If there is a slab allocation in progress we retry a few times. + for (uint32_t retries = 0; + retries < MAX_TRIES && !slab && reserved != SENTINEL; retries++) { + uint64_t lane_mask = gpu::get_lane_mask(); + slab = slots[index].try_lock(lane_mask, uniform & lane_mask, reserved, + chunk_size, index); + sleep_briefly(); + } + // If we find a slab with a matching chunk size then we store the result. // Otherwise, we need to free the claimed lock and continue. In the case - // of out-of-memory we return a sentinel value. + // of out-of-memory we receive a sentinel value and return a failure. if (slab && reserved <= Slab::available_chunks(chunk_size) && slab->get_chunk_size() == chunk_size) { - result = slab; + if (index != start) + indices[chunk_id].store(index, cpp::MemoryOrder::RELAXED); + return slab; } else if (slab && (reserved > Slab::available_chunks(chunk_size) || slab->get_chunk_size() != chunk_size)) { - if (slab->get_chunk_size() != chunk_size) - start = index + 1; slots[index].unlock(gpu::get_lane_mask(), gpu::get_lane_mask() & uniform); - } else if (!slab && reserved == cpp::numeric_limits<uint64_t>::max()) { - result = reinterpret_cast<Slab *>(SENTINEL); - } else { - sleep_briefly(); + } else if (!slab && reserved == SENTINEL) { + return nullptr; } } } - return result; + return nullptr; } // Release the lock associated with a given slab. diff --git a/libc/src/__support/RPC/rpc_server.h b/libc/src/__support/RPC/rpc_server.h index dc3d803..beea4dd 100644 --- a/libc/src/__support/RPC/rpc_server.h +++ b/libc/src/__support/RPC/rpc_server.h @@ -15,13 +15,17 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_RPC_RPC_SERVER_H #define LLVM_LIBC_SRC___SUPPORT_RPC_RPC_SERVER_H +#include "src/__support/macros/properties/compiler.h" + // Workaround for missing __has_builtin in < GCC 10. #ifndef __has_builtin #define __has_builtin(x) 0 #endif // Workaround for missing __builtin_is_constant_evaluated in < GCC 10. -#ifndef __builtin_is_constant_evaluated +// Also this builtin is defined for GCC 9. +#if !(__has_builtin(__builtin_is_constant_evaluated) || \ + (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900))) #define __builtin_is_constant_evaluated(x) 0 #endif diff --git a/libc/src/__support/wchar/mbrtowc.cpp b/libc/src/__support/wchar/mbrtowc.cpp index 90ba934..0f730d6 100644 --- a/libc/src/__support/wchar/mbrtowc.cpp +++ b/libc/src/__support/wchar/mbrtowc.cpp @@ -37,7 +37,8 @@ ErrorOr<size_t> mbrtowc(wchar_t *__restrict pwc, const char *__restrict s, } auto wc = char_conv.pop_utf32(); if (wc.has_value()) { - *pwc = wc.value(); + if (pwc != nullptr) + *pwc = wc.value(); // null terminator -> return 0 if (wc.value() == L'\0') return 0; diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt index 7ace1a6..159778d 100644 --- a/libc/src/wchar/CMakeLists.txt +++ b/libc/src/wchar/CMakeLists.txt @@ -1,3 +1,13 @@ +add_header_library( + wchar_utils + HDRS + wchar_utils.h + DEPENDS + libc.hdr.types.size_t + libc.hdr.types.wchar_t + libc.src.__support.common +) + add_entrypoint_object( wcslen SRCS @@ -255,6 +265,8 @@ add_entrypoint_object( DEPENDS libc.hdr.wchar_macros libc.hdr.types.size_t + libc.src.wchar.wchar_utils + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -266,6 +278,8 @@ add_entrypoint_object( DEPENDS libc.hdr.wchar_macros libc.hdr.types.size_t + libc.src.wchar.wchar_utils + libc.src.__support.macros.null_check ) add_entrypoint_object( diff --git a/libc/src/wchar/mbtowc.cpp b/libc/src/wchar/mbtowc.cpp index eae39ba..6d099d4 100644 --- a/libc/src/wchar/mbtowc.cpp +++ b/libc/src/wchar/mbtowc.cpp @@ -25,10 +25,7 @@ LLVM_LIBC_FUNCTION(int, mbtowc, if (s == nullptr) return 0; internal::mbstate internal_mbstate; - // temp ptr to use if pwc is nullptr - wchar_t buf[1]; - auto ret = - internal::mbrtowc(pwc == nullptr ? buf : pwc, s, n, &internal_mbstate); + auto ret = internal::mbrtowc(pwc, s, n, &internal_mbstate); if (!ret.has_value() || static_cast<int>(ret.value()) == -2) { // Encoding failure libc_errno = EILSEQ; diff --git a/libc/src/wchar/wchar_utils.h b/libc/src/wchar/wchar_utils.h new file mode 100644 index 0000000..e0218c7 --- /dev/null +++ b/libc/src/wchar/wchar_utils.h @@ -0,0 +1,45 @@ +//===-- wchar utils ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_WCHAR_WCHAR_UTILS_H +#define LLVM_LIBC_SRC_WCHAR_WCHAR_UTILS_H + +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// returns true if the character exists in the string +LIBC_INLINE static bool wcschr(wchar_t c, const wchar_t *str) { + for (int n = 0; str[n]; ++n) { + if (str[n] == c) + return true; + } + return false; +} + +// bool should be true for wcscspn for complimentary span +// should be false for wcsspn since we want it to span +LIBC_INLINE static size_t wcsspn(const wchar_t *s1, const wchar_t *s2, + bool not_match_set) { + size_t i = 0; + for (; s1[i]; ++i) { + bool in_set = wcschr(s1[i], s2); + if (in_set == not_match_set) + return i; + } + return i; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_WCHAR_WCHAR_UTILS_H diff --git a/libc/src/wchar/wcscspn.cpp b/libc/src/wchar/wcscspn.cpp index 8869d84..34f3451 100644 --- a/libc/src/wchar/wcscspn.cpp +++ b/libc/src/wchar/wcscspn.cpp @@ -12,23 +12,15 @@ #include "hdr/types/wchar_t.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" +#include "wchar_utils.h" namespace LIBC_NAMESPACE_DECL { -bool check(wchar_t c, const wchar_t *s2) { - for (int n = 0; s2[n]; ++n) { - if (s2[n] == c) - return false; - } - return true; -} LLVM_LIBC_FUNCTION(size_t, wcscspn, (const wchar_t *s1, const wchar_t *s2)) { - size_t i = 0; - for (; s1[i]; ++i) { - if (!check(s1[i], s2)) - return i; - } - return i; + LIBC_CRASH_ON_NULLPTR(s1); + LIBC_CRASH_ON_NULLPTR(s2); + return internal::wcsspn(s1, s2, /*not_match_set=*/true); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/wchar/wcsspn.cpp b/libc/src/wchar/wcsspn.cpp index 23de381..ae2cf5a 100644 --- a/libc/src/wchar/wcsspn.cpp +++ b/libc/src/wchar/wcsspn.cpp @@ -12,23 +12,15 @@ #include "hdr/types/wchar_t.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" +#include "wchar_utils.h" namespace LIBC_NAMESPACE_DECL { -bool check(wchar_t c, const wchar_t *s2) { - for (int n = 0; s2[n]; ++n) { - if (s2[n] == c) - return true; - } - return false; -} LLVM_LIBC_FUNCTION(size_t, wcsspn, (const wchar_t *s1, const wchar_t *s2)) { - size_t i = 0; - for (; s1[i]; ++i) { - if (!check(s1[i], s2)) - return i; - } - return i; + LIBC_CRASH_ON_NULLPTR(s1); + LIBC_CRASH_ON_NULLPTR(s2); + return internal::wcsspn(s1, s2, /*not_match_set=*/false); } } // namespace LIBC_NAMESPACE_DECL |