blob: 85c1f89d4d77caae24004dd0177cf89278ba4c3f [file] [log] [blame]
// Copyright 2014 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#pragma once
#include "android/base/TypeTraits.h"
#include <string>
#include <string.h>
namespace android {
namespace base {
// A StringView is a simple (address, size) pair that points to an
// existing read-only string. It's a convenience class used to hidden
// creation of std::string() objects un-necessarily.
//
// Consider the two following functions:
//
// size_t count1(const std::string& str) {
// size_t result = 0;
// for (size_t n = 0; n < str.size(); ++n) {
// if (str[n] == '1') {
// count++;
// }
// }
// }
//
// size_t count2(const StringView& str) {
// size_t result = 0;
// for (size_t n = 0; n < str.size(); ++n) {
// if (str[n] == '2') {
// count++;
// }
// }
// }
//
// Then consider the following calls:
//
// size_t n1 = count1("There is 1 one in this string!");
// size_t n2 = count2("I can count 2 too");
//
// In the first case, the compiler will silently create a temporary
// std::string object, copy the input string into it (allocating memory in
// the heap), call count1() and destroy the std::string upon its return.
//
// In the second case, the compiler will create a temporary StringView,
// initialize it trivially before calling count2(), this results in
// much less generated code, as well as better performance.
//
// Generally speaking, always use a reference or pointer to StringView
// instead of a std::string if your function or method doesn't need to modify
// its input.
//
class StringView {
public:
constexpr StringView() : mString(""), mSize(0U) {}
constexpr StringView(const StringView& other) :
mString(other.data()), mSize(other.size()) {}
// IMPORTANT: all StringView constructors are intentionally not explict
// it is needed to allow seamless creation of StringView from all types
// of strings around - as it's intended to be a generic string wrapper
// A constexpr constructor from a constant buffer, initializing |mSize|
// as well. This allows one to declare a static const StringView instance
// and initialize it at compile time, with no runtime overhead:
//
// static constexpr StringView message = "blah";
//
template <size_t size>
constexpr StringView(const char (&buf)[size]) :
mString(buf), mSize(size - 1) {}
// Constructor from a const char pointer. It has to be templated to make
// sure the array-based one is chosen for an array - otherwise non-templated
// overload always wins
// Note: the parameter type is a const reference to a const pointer. This
// is to make this overload a poorer choice for the case of an array. For
// the 'const char[]' argument both 'reference to an array' and 'pointer'
// overloads are tied, so compiler can't choose without help
template <class Char, class = enable_if<std::is_same<Char, char>>>
constexpr StringView(const Char* const & string) :
mString(string ? string : ""), mSize(string ? strlen(string) : 0) {}
StringView(const std::string& str) :
mString(str.c_str()), mSize(str.size()) {}
constexpr StringView(const char* str, size_t len)
: mString(str ? str : ""), mSize(len) {}
constexpr StringView(const char* begin, const char* end)
: mString(begin ? begin : ""), mSize(begin ? end - begin : 0) {}
constexpr StringView(std::nullptr_t) :
mString(""), mSize(0) {}
constexpr const char* c_str() const { return mString; }
constexpr const char* str() const { return mString; }
constexpr const char* data() const { return mString; }
constexpr size_t size() const { return mSize; }
typedef const char* iterator;
typedef const char* const_iterator;
constexpr const_iterator begin() const { return mString; }
constexpr const_iterator end() const { return mString + mSize; }
constexpr bool empty() const { return !size(); }
void clear() {
mSize = 0;
mString = "";
}
constexpr char operator[](size_t index) const {
return mString[index];
}
void set(const char* data, size_t len) {
mString = data ? data : "";
mSize = len;
}
void set(const char* str) {
mString = str ? str : "";
mSize = ::strlen(mString);
}
void set(const StringView& other) {
mString = other.mString;
mSize = other.mSize;
}
// Compare with another StringView.
int compare(const StringView& other) const;
StringView& operator=(const StringView& other) {
set(other);
return *this;
}
// Convert to std::string when needed.
operator std::string() const { return std::string(mString, mSize); }
private:
const char* mString;
size_t mSize;
};
// Comparison operators. Defined as functions to allow automatic type
// conversions with C strings and std::string objects.
bool operator==(const StringView& x, const StringView& y);
inline bool operator!=(const StringView& x, const StringView& y) {
return !(x == y);
}
inline bool operator<(const StringView& x, const StringView& y) {
return x.compare(y) < 0;
}
inline bool operator>=(const StringView& x, const StringView& y) {
return !(x < y);
}
inline bool operator >(const StringView& x, const StringView& y) {
return x.compare(y) > 0;
}
inline bool operator<=(const StringView& x, const StringView& y) {
return !(x > y);
}
} // namespace base
} // namespace android