summaryrefslogtreecommitdiff
path: root/libutils/include/utils/String16.h
blob: c0e3f1eba3adf873ccc4c1fdfd21f72d646b07d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/*
 * 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>

// ---------------------------------------------------------------------------

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:
    /*
     * Use String16(StaticLinkage) if you're statically linking against
     * libutils and declaring an empty static String16, e.g.:
     *
     *   static String16 sAStaticEmptyString(String16::kEmptyString);
     *   static String16 sAnotherStaticEmptyString(sAStaticEmptyString);
     */
    enum StaticLinkage { kEmptyString };

                                String16();
    explicit                    String16(StaticLinkage);
                                String16(const String16& o);
                                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*     string() const;

private:
    static inline std::string   std_string(const String16& str);
public:
            size_t              size() 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);

    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;

            status_t            makeLower();

            status_t            replaceAll(char16_t replaceThis,
                                           char16_t withThis);

            status_t            remove(size_t len, size_t begin=0);

    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;

    // 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
// 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).c_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::string() const
{
    return mString;
}

inline std::string String16::std_string(const String16& str)
{
    return std::string(String8(str).string());
}

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;
}

}  // namespace android

// ---------------------------------------------------------------------------

#endif // ANDROID_STRING16_H