diff options
author | Vic Yang <victoryang@google.com> | 2019-09-05 13:18:27 -0700 |
---|---|---|
committer | Vic Yang <victoryang@google.com> | 2019-09-05 13:19:14 -0700 |
commit | 9fb93edd5bd4531f72faadfb269a0aa25d413b5d (patch) | |
tree | 72e8c274e883d168e1be903d69d0da6bb98866e6 /libutils/include/utils/String16.h | |
parent | 8bea425845ce232c272d8adc9e3149d49ba91a6f (diff) |
Reland "libutils: Introduce StaticString16""
This reverts commit 1270e4fbf17402fb01dbfa7928a654d41d8553ee.
Bug: 138856262
Test: Run unit tests.
Change-Id: I37be01d7d4f98a83078870cb0917275336fa2bbd
Merged-In: I8da93f2c9b95183e32d4a2ea895f90c449abbe4d
Diffstat (limited to 'libutils/include/utils/String16.h')
-rw-r--r-- | libutils/include/utils/String16.h | 114 |
1 files changed, 111 insertions, 3 deletions
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h index afbc2edc5..adc3e7de9 100644 --- a/libutils/include/utils/String16.h +++ b/libutils/include/utils/String16.h @@ -37,13 +37,17 @@ namespace android { class String8; +template <size_t N> +class StaticString16; + // DO NOT USE: please use std::u16string //! This is a string holding UTF-16 characters. class String16 { public: - /* use String16(StaticLinkage) if you're statically linking against + /* + * Use String16(StaticLinkage) if you're statically linking against * libutils and declaring an empty static String16, e.g.: * * static String16 sAStaticEmptyString(String16::kEmptyString); @@ -123,8 +127,76 @@ public: inline operator const char16_t*() const; -private: - const char16_t* mString; + // Static and non-static String16 behave the same for the users, so + // this method isn't of much use for the users. It is public for testing. + bool isStaticString() const; + + private: + /* + * A flag indicating the type of underlying buffer. + */ + static constexpr uint32_t kIsSharedBufferAllocated = 0x80000000; + + /* + * alloc() returns void* so that SharedBuffer class is not exposed. + */ + static void* alloc(size_t size); + static char16_t* allocFromUTF8(const char* u8str, size_t u8len); + static char16_t* allocFromUTF16(const char16_t* u16str, size_t u16len); + + /* + * edit() and editResize() return void* so that SharedBuffer class + * is not exposed. + */ + void* edit(); + void* editResize(size_t new_size); + + void acquire(); + void release(); + + size_t staticStringSize() const; + + const char16_t* mString; + +protected: + /* + * Data structure used to allocate static storage for static String16. + * + * Note that this data structure and SharedBuffer are used interchangably + * as the underlying data structure for a String16. Therefore, the layout + * of this data structure must match the part in SharedBuffer that is + * visible to String16. + */ + template <size_t N> + struct StaticData { + // The high bit of 'size' is used as a flag. + static_assert(N - 1 < kIsSharedBufferAllocated, "StaticString16 too long!"); + constexpr StaticData() : size(N - 1), data{0} {} + const uint32_t size; + char16_t data[N]; + + constexpr StaticData(const StaticData<N>&) = default; + }; + + /* + * Helper function for constructing a StaticData object. + */ + template <size_t N> + static constexpr const StaticData<N> makeStaticData(const char16_t (&s)[N]) { + StaticData<N> r; + // The 'size' field is at the same location where mClientMetadata would + // be for a SharedBuffer. We do NOT set kIsSharedBufferAllocated flag + // here. + for (size_t i = 0; i < N - 1; ++i) r.data[i] = s[i]; + return r; + } + + template <size_t N> + explicit constexpr String16(const StaticData<N>& s) : mString(s.data) {} + +public: + template <size_t N> + explicit constexpr String16(const StaticString16<N>& s) : mString(s.mString) {} }; // String16 can be trivially moved using memcpy() because moving does not @@ -132,6 +204,42 @@ private: ANDROID_TRIVIAL_MOVE_TRAIT(String16) // --------------------------------------------------------------------------- + +/* + * A StaticString16 object is a specialized String16 object. Instead of holding + * the string data in a ref counted SharedBuffer object, it holds data in a + * buffer within StaticString16 itself. Note that this buffer is NOT ref + * counted and is assumed to be available for as long as there is at least a + * String16 object using it. Therefore, one must be extra careful to NEVER + * assign a StaticString16 to a String16 that outlives the StaticString16 + * object. + * + * THE SAFEST APPROACH IS TO USE StaticString16 ONLY AS GLOBAL VARIABLES. + * + * A StaticString16 SHOULD NEVER APPEAR IN APIs. USE String16 INSTEAD. + */ +template <size_t N> +class StaticString16 : public String16 { +public: + constexpr StaticString16(const char16_t (&s)[N]) : String16(mData), mData(makeStaticData(s)) {} + + constexpr StaticString16(const StaticString16<N>& other) + : String16(mData), mData(other.mData) {} + + constexpr StaticString16(const StaticString16<N>&&) = delete; + + // There is no reason why one would want to 'new' a StaticString16. Delete + // it to discourage misuse. + static void* operator new(std::size_t) = delete; + +private: + const StaticData<N> mData; +}; + +template <typename F> +StaticString16(const F&)->StaticString16<sizeof(F) / sizeof(char16_t)>; + +// --------------------------------------------------------------------------- // No user servicable parts below. inline int compare_type(const String16& lhs, const String16& rhs) |