blob: 1fa3723b79ef965e9c2471ae6efcd6212a8ac0e2 [file] [log] [blame]
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_STRING16_H
#define ANDROID_STRING16_H
#include <iostream>
#include <string>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/TypeHelpers.h>
#if __has_include(<string_view>)
#include <string_view>
#define HAS_STRING_VIEW
#endif
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
template <size_t N>
class StaticString16;
// DO NOT USE: please use std::u16string
//! This is a string holding UTF-16 characters.
class String16
{
public:
String16();
String16(const String16& o);
String16(String16&& o) noexcept;
String16(const String16& o,
size_t len,
size_t begin=0);
explicit String16(const char16_t* o);
explicit String16(const char16_t* o, size_t len);
explicit String16(const String8& o);
explicit String16(const char* o);
explicit String16(const char* o, size_t len);
~String16();
inline const char16_t* c_str() const;
inline const char16_t* string() const;
size_t size() const;
inline bool empty() const;
inline size_t length() const;
void setTo(const String16& other);
status_t setTo(const char16_t* other);
status_t setTo(const char16_t* other, size_t len);
status_t setTo(const String16& other,
size_t len,
size_t begin=0);
status_t append(const String16& other);
status_t append(const char16_t* other, size_t len);
inline String16& operator=(const String16& other);
String16& operator=(String16&& other) noexcept;
inline String16& operator+=(const String16& other);
inline String16 operator+(const String16& other) const;
status_t insert(size_t pos, const char16_t* chrs);
status_t insert(size_t pos,
const char16_t* chrs, size_t len);
ssize_t findFirst(char16_t c) const;
ssize_t findLast(char16_t c) const;
bool startsWith(const String16& prefix) const;
bool startsWith(const char16_t* prefix) const;
bool contains(const char16_t* chrs) const;
inline bool contains(const String16& other) const;
status_t replaceAll(char16_t replaceThis,
char16_t withThis);
inline int compare(const String16& other) const;
inline bool operator<(const String16& other) const;
inline bool operator<=(const String16& other) const;
inline bool operator==(const String16& other) const;
inline bool operator!=(const String16& other) const;
inline bool operator>=(const String16& other) const;
inline bool operator>(const String16& other) const;
inline bool operator<(const char16_t* other) const;
inline bool operator<=(const char16_t* other) const;
inline bool operator==(const char16_t* other) const;
inline bool operator!=(const char16_t* other) const;
inline bool operator>=(const char16_t* other) const;
inline bool operator>(const char16_t* other) const;
inline operator const char16_t*() const;
#ifdef HAS_STRING_VIEW
// Implicit cast to std::u16string is not implemented on purpose - u16string_view is much
// lighter and if one needs, they can still create u16string from u16string_view.
inline operator std::u16string_view() const;
#endif
// 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) {}
};
// String16 can be trivially moved using memcpy() because moving does not
// require any change to the underlying SharedBuffer contents or reference count.
ANDROID_TRIVIAL_MOVE_TRAIT(String16)
static inline std::ostream& operator<<(std::ostream& os, const String16& str) {
os << String8(str);
return os;
}
// ---------------------------------------------------------------------------
/*
* 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)
{
return lhs.compare(rhs);
}
inline int strictly_order_type(const String16& lhs, const String16& rhs)
{
return compare_type(lhs, rhs) < 0;
}
inline const char16_t* String16::c_str() const
{
return mString;
}
inline const char16_t* String16::string() const
{
return mString;
}
inline bool String16::empty() const
{
return length() == 0;
}
inline size_t String16::length() const
{
return size();
}
inline bool String16::contains(const String16& other) const
{
return contains(other.c_str());
}
inline String16& String16::operator=(const String16& other)
{
setTo(other);
return *this;
}
inline String16& String16::operator+=(const String16& other)
{
append(other);
return *this;
}
inline String16 String16::operator+(const String16& other) const
{
String16 tmp(*this);
tmp += other;
return tmp;
}
inline int String16::compare(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size());
}
inline bool String16::operator<(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) < 0;
}
inline bool String16::operator<=(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) <= 0;
}
inline bool String16::operator==(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) == 0;
}
inline bool String16::operator!=(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) != 0;
}
inline bool String16::operator>=(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) >= 0;
}
inline bool String16::operator>(const String16& other) const
{
return strzcmp16(mString, size(), other.mString, other.size()) > 0;
}
inline bool String16::operator<(const char16_t* other) const
{
return strcmp16(mString, other) < 0;
}
inline bool String16::operator<=(const char16_t* other) const
{
return strcmp16(mString, other) <= 0;
}
inline bool String16::operator==(const char16_t* other) const
{
return strcmp16(mString, other) == 0;
}
inline bool String16::operator!=(const char16_t* other) const
{
return strcmp16(mString, other) != 0;
}
inline bool String16::operator>=(const char16_t* other) const
{
return strcmp16(mString, other) >= 0;
}
inline bool String16::operator>(const char16_t* other) const
{
return strcmp16(mString, other) > 0;
}
inline String16::operator const char16_t*() const
{
return mString;
}
inline String16::operator std::u16string_view() const
{
return {mString, length()};
}
} // namespace android
// ---------------------------------------------------------------------------
#undef HAS_STRING_VIEW
#endif // ANDROID_STRING16_H