summaryrefslogtreecommitdiff
path: root/libutils/include/utils/String16.h
diff options
context:
space:
mode:
authorVic Yang <victoryang@google.com>2019-09-05 13:18:27 -0700
committerVic Yang <victoryang@google.com>2019-09-05 13:19:14 -0700
commit9fb93edd5bd4531f72faadfb269a0aa25d413b5d (patch)
tree72e8c274e883d168e1be903d69d0da6bb98866e6 /libutils/include/utils/String16.h
parent8bea425845ce232c272d8adc9e3149d49ba91a6f (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.h114
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)