blob: de938228b30db62b8ca3592683a3f8b81102a050 [file] [log] [blame]
/*
* Copyright (C) 2015 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 AAPT_STRING_PIECE_H
#define AAPT_STRING_PIECE_H
#include <utils/JenkinsHash.h>
#include <utils/String8.h>
#include <utils/Unicode.h>
#include <ostream>
#include <string>
namespace aapt {
/**
* Read only wrapper around basic C strings.
* Prevents excessive copying.
*
* WARNING: When creating from std::basic_string<>, moving the original
* std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
* BasicStringPiece<> should only be used transitively.
*/
template <typename TChar>
class BasicStringPiece {
public:
using const_iterator = const TChar*;
using difference_type = size_t;
// End of string marker.
constexpr static const size_t npos = static_cast<size_t>(-1);
BasicStringPiece();
BasicStringPiece(const BasicStringPiece<TChar>& str);
BasicStringPiece(const std::basic_string<TChar>& str); // NOLINT(implicit)
BasicStringPiece(const TChar* str); // NOLINT(implicit)
BasicStringPiece(const TChar* str, size_t len);
BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
BasicStringPiece<TChar> substr(
BasicStringPiece<TChar>::const_iterator begin,
BasicStringPiece<TChar>::const_iterator end) const;
const TChar* data() const;
size_t length() const;
size_t size() const;
bool empty() const;
std::basic_string<TChar> toString() const;
bool contains(const BasicStringPiece<TChar>& rhs) const;
int compare(const BasicStringPiece<TChar>& rhs) const;
bool operator<(const BasicStringPiece<TChar>& rhs) const;
bool operator>(const BasicStringPiece<TChar>& rhs) const;
bool operator==(const BasicStringPiece<TChar>& rhs) const;
bool operator!=(const BasicStringPiece<TChar>& rhs) const;
const_iterator begin() const;
const_iterator end() const;
private:
const TChar* mData;
size_t mLength;
};
using StringPiece = BasicStringPiece<char>;
using StringPiece16 = BasicStringPiece<char16_t>;
//
// BasicStringPiece implementation.
//
template <typename TChar>
constexpr const size_t BasicStringPiece<TChar>::npos;
template <typename TChar>
inline BasicStringPiece<TChar>::BasicStringPiece()
: mData(nullptr), mLength(0) {}
template <typename TChar>
inline BasicStringPiece<TChar>::BasicStringPiece(
const BasicStringPiece<TChar>& str)
: mData(str.mData), mLength(str.mLength) {}
template <typename TChar>
inline BasicStringPiece<TChar>::BasicStringPiece(
const std::basic_string<TChar>& str)
: mData(str.data()), mLength(str.length()) {}
template <>
inline BasicStringPiece<char>::BasicStringPiece(const char* str)
: mData(str), mLength(str != nullptr ? strlen(str) : 0) {}
template <>
inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str)
: mData(str), mLength(str != nullptr ? strlen16(str) : 0) {}
template <typename TChar>
inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len)
: mData(str), mLength(len) {}
template <typename TChar>
inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
const BasicStringPiece<TChar>& rhs) {
mData = rhs.mData;
mLength = rhs.mLength;
return *this;
}
template <typename TChar>
inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(
const TChar* str, size_t len) {
mData = str;
mLength = len;
return *this;
}
template <typename TChar>
inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
size_t start, size_t len) const {
if (len == npos) {
len = mLength - start;
}
if (start > mLength || start + len > mLength) {
return BasicStringPiece<TChar>();
}
return BasicStringPiece<TChar>(mData + start, len);
}
template <typename TChar>
inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
BasicStringPiece<TChar>::const_iterator begin,
BasicStringPiece<TChar>::const_iterator end) const {
return BasicStringPiece<TChar>(begin, end - begin);
}
template <typename TChar>
inline const TChar* BasicStringPiece<TChar>::data() const {
return mData;
}
template <typename TChar>
inline size_t BasicStringPiece<TChar>::length() const {
return mLength;
}
template <typename TChar>
inline size_t BasicStringPiece<TChar>::size() const {
return mLength;
}
template <typename TChar>
inline bool BasicStringPiece<TChar>::empty() const {
return mLength == 0;
}
template <typename TChar>
inline std::basic_string<TChar> BasicStringPiece<TChar>::toString() const {
return std::basic_string<TChar>(mData, mLength);
}
template <>
inline bool BasicStringPiece<char>::contains(
const BasicStringPiece<char>& rhs) const {
if (!mData || !rhs.mData) {
return false;
}
if (rhs.mLength > mLength) {
return false;
}
return strstr(mData, rhs.mData) != nullptr;
}
template <>
inline int BasicStringPiece<char>::compare(
const BasicStringPiece<char>& rhs) const {
const char nullStr = '\0';
const char* b1 = mData != nullptr ? mData : &nullStr;
const char* e1 = b1 + mLength;
const char* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
const char* e2 = b2 + rhs.mLength;
while (b1 < e1 && b2 < e2) {
const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
if (d) {
return d;
}
}
return static_cast<int>(mLength - rhs.mLength);
}
inline ::std::ostream& operator<<(::std::ostream& out,
const BasicStringPiece<char16_t>& str) {
android::String8 utf8(str.data(), str.size());
return out.write(utf8.string(), utf8.size());
}
template <>
inline bool BasicStringPiece<char16_t>::contains(
const BasicStringPiece<char16_t>& rhs) const {
if (!mData || !rhs.mData) {
return false;
}
if (rhs.mLength > mLength) {
return false;
}
return strstr16(mData, rhs.mData) != nullptr;
}
template <>
inline int BasicStringPiece<char16_t>::compare(
const BasicStringPiece<char16_t>& rhs) const {
const char16_t nullStr = u'\0';
const char16_t* b1 = mData != nullptr ? mData : &nullStr;
const char16_t* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
return strzcmp16(b1, mLength, b2, rhs.mLength);
}
template <typename TChar>
inline bool BasicStringPiece<TChar>::operator<(
const BasicStringPiece<TChar>& rhs) const {
return compare(rhs) < 0;
}
template <typename TChar>
inline bool BasicStringPiece<TChar>::operator>(
const BasicStringPiece<TChar>& rhs) const {
return compare(rhs) > 0;
}
template <typename TChar>
inline bool BasicStringPiece<TChar>::operator==(
const BasicStringPiece<TChar>& rhs) const {
return compare(rhs) == 0;
}
template <typename TChar>
inline bool BasicStringPiece<TChar>::operator!=(
const BasicStringPiece<TChar>& rhs) const {
return compare(rhs) != 0;
}
template <typename TChar>
inline typename BasicStringPiece<TChar>::const_iterator
BasicStringPiece<TChar>::begin() const {
return mData;
}
template <typename TChar>
inline typename BasicStringPiece<TChar>::const_iterator
BasicStringPiece<TChar>::end() const {
return mData + mLength;
}
inline ::std::ostream& operator<<(::std::ostream& out,
const BasicStringPiece<char>& str) {
return out.write(str.data(), str.size());
}
} // namespace aapt
inline ::std::ostream& operator<<(::std::ostream& out,
const std::u16string& str) {
android::String8 utf8(str.data(), str.size());
return out.write(utf8.string(), utf8.size());
}
namespace std {
template <typename TChar>
struct hash<aapt::BasicStringPiece<TChar>> {
size_t operator()(const aapt::BasicStringPiece<TChar>& str) const {
uint32_t hashCode = android::JenkinsHashMixBytes(
0, reinterpret_cast<const uint8_t*>(str.data()),
sizeof(TChar) * str.size());
return static_cast<size_t>(hashCode);
}
};
} // namespace std
#endif // AAPT_STRING_PIECE_H