diff options
Diffstat (limited to 'icu4c/source/common/bytesinkutil.h')
-rw-r--r-- | icu4c/source/common/bytesinkutil.h | 112 |
1 files changed, 90 insertions, 22 deletions
diff --git a/icu4c/source/common/bytesinkutil.h b/icu4c/source/common/bytesinkutil.h index 929c71fbe..b3bd487be 100644 --- a/icu4c/source/common/bytesinkutil.h +++ b/icu4c/source/common/bytesinkutil.h @@ -7,18 +7,52 @@ #ifndef BYTESINKUTIL_H #define BYTESINKUTIL_H +#include <type_traits> + #include "unicode/utypes.h" #include "unicode/bytestream.h" #include "unicode/edits.h" +#include "charstr.h" #include "cmemory.h" #include "uassert.h" +#include "ustr_imp.h" U_NAMESPACE_BEGIN class ByteSink; -class CharString; class Edits; +class U_COMMON_API CharStringByteSink : public ByteSink { +public: + CharStringByteSink(CharString* dest); + ~CharStringByteSink() override; + + CharStringByteSink() = delete; + CharStringByteSink(const CharStringByteSink&) = delete; + CharStringByteSink& operator=(const CharStringByteSink&) = delete; + + void Append(const char* bytes, int32_t n) override; + + char* GetAppendBuffer(int32_t min_capacity, + int32_t desired_capacity_hint, + char* scratch, + int32_t scratch_capacity, + int32_t* result_capacity) override; + +private: + CharString& dest_; +}; + +// CharString doesn't provide the public API that StringByteSink requires a +// string class to have so this template specialization replaces the default +// implementation of StringByteSink<CharString> with CharStringByteSink. +template<> +class StringByteSink<CharString> : public CharStringByteSink { + public: + StringByteSink(CharString* dest) : CharStringByteSink(dest) { } + StringByteSink(CharString* dest, int32_t /*initialAppendCapacity*/) : CharStringByteSink(dest) { } +}; + class U_COMMON_API ByteSinkUtil { public: ByteSinkUtil() = delete; // all static @@ -57,30 +91,64 @@ public: ByteSink &sink, uint32_t options, Edits *edits, UErrorCode &errorCode); -private: - static void appendNonEmptyUnchanged(const uint8_t *s, int32_t length, - ByteSink &sink, uint32_t options, Edits *edits); -}; - -class U_COMMON_API CharStringByteSink : public ByteSink { -public: - CharStringByteSink(CharString* dest); - ~CharStringByteSink() override; - - CharStringByteSink() = delete; - CharStringByteSink(const CharStringByteSink&) = delete; - CharStringByteSink& operator=(const CharStringByteSink&) = delete; - - void Append(const char* bytes, int32_t n) override; + /** + * Calls a lambda that writes to a ByteSink with a CheckedArrayByteSink + * and then returns through u_terminateChars(), in order to implement + * the classic ICU4C C API writing to a fix sized buffer on top of a + * contemporary C++ API. + * + * @param buffer receiving buffer + * @param capacity capacity of receiving buffer + * @param lambda that gets called with the sink as an argument + * @param status set to U_BUFFER_OVERFLOW_ERROR on overflow + * @return number of bytes written, or needed (in case of overflow) + * @internal + */ + template <typename F, + typename = std::enable_if_t< + std::is_invocable_r_v<void, F, ByteSink&, UErrorCode&>>> + static int32_t viaByteSinkToTerminatedChars(char* buffer, int32_t capacity, + F&& lambda, + UErrorCode& status) { + if (U_FAILURE(status)) { return 0; } + CheckedArrayByteSink sink(buffer, capacity); + lambda(sink, status); + if (U_FAILURE(status)) { return 0; } + + int32_t reslen = sink.NumberOfBytesAppended(); + + if (sink.Overflowed()) { + status = U_BUFFER_OVERFLOW_ERROR; + return reslen; + } + + return u_terminateChars(buffer, capacity, reslen, &status); + } - char* GetAppendBuffer(int32_t min_capacity, - int32_t desired_capacity_hint, - char* scratch, - int32_t scratch_capacity, - int32_t* result_capacity) override; + /** + * Calls a lambda that writes to a ByteSink with a CharStringByteSink and + * then returns a CharString, in order to implement a contemporary C++ API + * on top of a C/C++ compatibility ByteSink API. + * + * @param lambda that gets called with the sink as an argument + * @param status to check and report + * @return the resulting string, or an empty string (in case of error) + * @internal + */ + template <typename F, + typename = std::enable_if_t< + std::is_invocable_r_v<void, F, ByteSink&, UErrorCode&>>> + static CharString viaByteSinkToCharString(F&& lambda, UErrorCode& status) { + if (U_FAILURE(status)) { return {}; } + CharString result; + CharStringByteSink sink(&result); + lambda(sink, status); + return result; + } private: - CharString& dest_; + static void appendNonEmptyUnchanged(const uint8_t *s, int32_t length, + ByteSink &sink, uint32_t options, Edits *edits); }; U_NAMESPACE_END |