1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef AAPT_STRING_PIECE_H
18#define AAPT_STRING_PIECE_H
19
20#include <ostream>
21#include <string>
22#include <utils/String8.h>
23#include <utils/Unicode.h>
24
25namespace aapt {
26
27/**
28 * Read only wrapper around basic C strings.
29 * Prevents excessive copying.
30 *
31 * WARNING: When creating from std::basic_string<>, moving the original
32 * std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
33 * BasicStringPiece<> should only be used transitively.
34 */
35template <typename TChar>
36class BasicStringPiece {
37public:
38    using const_iterator = const TChar*;
39    using difference_type = size_t;
40
41    BasicStringPiece();
42    BasicStringPiece(const BasicStringPiece<TChar>& str);
43    BasicStringPiece(const std::basic_string<TChar>& str);
44    BasicStringPiece(const TChar* str);
45    BasicStringPiece(const TChar* str, size_t len);
46
47    BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
48    BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
49
50    BasicStringPiece<TChar> substr(size_t start, size_t len) const;
51    BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
52                                   BasicStringPiece<TChar>::const_iterator end) const;
53
54    const TChar* data() const;
55    size_t length() const;
56    size_t size() const;
57    bool empty() const;
58    std::basic_string<TChar> toString() const;
59
60    bool contains(const BasicStringPiece<TChar>& rhs) const;
61    int compare(const BasicStringPiece<TChar>& rhs) const;
62    bool operator<(const BasicStringPiece<TChar>& rhs) const;
63    bool operator>(const BasicStringPiece<TChar>& rhs) const;
64    bool operator==(const BasicStringPiece<TChar>& rhs) const;
65    bool operator!=(const BasicStringPiece<TChar>& rhs) const;
66
67    const_iterator begin() const;
68    const_iterator end() const;
69
70private:
71    const TChar* mData;
72    size_t mLength;
73};
74
75using StringPiece = BasicStringPiece<char>;
76using StringPiece16 = BasicStringPiece<char16_t>;
77
78//
79// BasicStringPiece implementation.
80//
81
82template <typename TChar>
83inline BasicStringPiece<TChar>::BasicStringPiece() : mData(nullptr) , mLength(0) {
84}
85
86template <typename TChar>
87inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str) :
88        mData(str.mData), mLength(str.mLength) {
89}
90
91template <typename TChar>
92inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str) :
93        mData(str.data()), mLength(str.length()) {
94}
95
96template <>
97inline BasicStringPiece<char>::BasicStringPiece(const char* str) :
98        mData(str), mLength(str != nullptr ? strlen(str) : 0) {
99}
100
101template <>
102inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str) :
103        mData(str), mLength(str != nullptr ? strlen16(str) : 0) {
104}
105
106template <typename TChar>
107inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len) :
108        mData(str), mLength(len) {
109}
110
111template <typename TChar>
112inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
113        const BasicStringPiece<TChar>& rhs) {
114    mData = rhs.mData;
115    mLength = rhs.mLength;
116    return *this;
117}
118
119template <typename TChar>
120inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
121    mData = str;
122    mLength = len;
123    return *this;
124}
125
126
127template <typename TChar>
128inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
129    if (start + len > mLength) {
130        return BasicStringPiece<TChar>();
131    }
132    return BasicStringPiece<TChar>(mData + start, len);
133}
134
135template <typename TChar>
136inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
137        BasicStringPiece<TChar>::const_iterator begin,
138        BasicStringPiece<TChar>::const_iterator end) const {
139    return BasicStringPiece<TChar>(begin, end - begin);
140}
141
142template <typename TChar>
143inline const TChar* BasicStringPiece<TChar>::data() const {
144    return mData;
145}
146
147template <typename TChar>
148inline size_t BasicStringPiece<TChar>::length() const {
149    return mLength;
150}
151
152template <typename TChar>
153inline size_t BasicStringPiece<TChar>::size() const {
154    return mLength;
155}
156
157template <typename TChar>
158inline bool BasicStringPiece<TChar>::empty() const {
159    return mLength == 0;
160}
161
162template <typename TChar>
163inline std::basic_string<TChar> BasicStringPiece<TChar>::toString() const {
164    return std::basic_string<TChar>(mData, mLength);
165}
166
167template <>
168inline bool BasicStringPiece<char>::contains(const BasicStringPiece<char>& rhs) const {
169    if (!mData || !rhs.mData) {
170        return false;
171    }
172    if (rhs.mLength > mLength) {
173        return false;
174    }
175    return strstr(mData, rhs.mData) != nullptr;
176}
177
178template <>
179inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
180    const char nullStr = '\0';
181    const char* b1 = mData != nullptr ? mData : &nullStr;
182    const char* e1 = b1 + mLength;
183    const char* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
184    const char* e2 = b2 + rhs.mLength;
185
186    while (b1 < e1 && b2 < e2) {
187        const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
188        if (d) {
189            return d;
190        }
191    }
192    return static_cast<int>(mLength - rhs.mLength);
193}
194
195inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
196    android::String8 utf8(str.data(), str.size());
197    return out.write(utf8.string(), utf8.size());
198}
199
200template <>
201inline bool BasicStringPiece<char16_t>::contains(const BasicStringPiece<char16_t>& rhs) const {
202    if (!mData || !rhs.mData) {
203        return false;
204    }
205    if (rhs.mLength > mLength) {
206        return false;
207    }
208    return strstr16(mData, rhs.mData) != nullptr;
209}
210
211template <>
212inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
213    const char16_t nullStr = u'\0';
214    const char16_t* b1 = mData != nullptr ? mData : &nullStr;
215    const char16_t* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
216    return strzcmp16(b1, mLength, b2, rhs.mLength);
217}
218
219template <typename TChar>
220inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
221    return compare(rhs) < 0;
222}
223
224template <typename TChar>
225inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
226    return compare(rhs) > 0;
227}
228
229template <typename TChar>
230inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
231    return compare(rhs) == 0;
232}
233
234template <typename TChar>
235inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
236    return compare(rhs) != 0;
237}
238
239template <typename TChar>
240inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
241    return mData;
242}
243
244template <typename TChar>
245inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
246    return mData + mLength;
247}
248
249inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
250    return out.write(str.data(), str.size());
251}
252
253} // namespace aapt
254
255inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
256    android::String8 utf8(str.data(), str.size());
257    return out.write(utf8.string(), utf8.size());
258}
259
260#endif // AAPT_STRING_PIECE_H
261