blob: aa31f15d97c66ee4efd076195ebb3184f721bc66 [file] [log] [blame]
//===-- Standalone implementation std::string_view --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H
#define LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H
#include "src/__support/common.h"
#include <stddef.h>
namespace __llvm_libc {
namespace cpp {
// This is very simple alternate of the std::string_view class. There is no
// bounds check performed in any of the methods. The callers are expected to
// do the checks before invoking the methods.
//
// This class will be extended as needed in future.
class string_view {
private:
const char *Data;
size_t Len;
static size_t min(size_t A, size_t B) { return A <= B ? A : B; }
LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs,
size_t Length) {
for (size_t I = 0; I < Length; ++I)
if (int Diff = (int)Lhs[I] - (int)Rhs[I])
return Diff;
return 0;
}
LIBC_INLINE static constexpr size_t length(const char *Str) {
for (const char *End = Str;; ++End)
if (*End == '\0')
return End - Str;
}
LIBC_INLINE bool equals(string_view Other) const {
return (Len == Other.Len &&
compareMemory(Data, Other.Data, Other.Len) == 0);
}
public:
using value_type = char;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = char *;
using const_pointer = const char *;
using reference = char &;
using const_reference = const char &;
using const_iterator = char *;
using iterator = const_iterator;
// special value equal to the maximum value representable by the type
// size_type.
inline static constexpr size_t npos = -1;
LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {}
// Assumes Str is a null-terminated string. The length of the string does
// not include the terminating null character.
// Preconditions: [Str, Str + ​length(Str)) is a valid range.
LIBC_INLINE constexpr string_view(const char *Str)
: Data(Str), Len(length(Str)) {}
// Preconditions: [Str, Str + N) is a valid range.
LIBC_INLINE constexpr string_view(const char *Str, size_t N)
: Data(Str), Len(N) {}
LIBC_INLINE constexpr const char *data() const { return Data; }
// Returns the size of the string_view.
LIBC_INLINE constexpr size_t size() const { return Len; }
// Returns whether the string_view is empty.
LIBC_INLINE constexpr bool empty() const { return Len == 0; }
// Returns an iterator to the first character of the view.
LIBC_INLINE const char *begin() const { return Data; }
// Returns an iterator to the character following the last character of the
// view.
LIBC_INLINE const char *end() const { return Data + Len; }
// Returns a const reference to the character at specified location pos.
// No bounds checking is performed: the behavior is undefined if pos >=
// size().
LIBC_INLINE constexpr const char &operator[](size_t Index) const {
return Data[Index];
}
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
/// is lexicographically less than, equal to, or greater than the \p Other.
LIBC_INLINE int compare(string_view Other) const {
// Check the prefix for a mismatch.
if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len)))
return Res < 0 ? -1 : 1;
// Otherwise the prefixes match, so we only need to check the lengths.
if (Len == Other.Len)
return 0;
return Len < Other.Len ? -1 : 1;
}
LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); }
LIBC_INLINE bool operator!=(string_view Other) const {
return !(*this == Other);
}
LIBC_INLINE bool operator<(string_view Other) const {
return compare(Other) == -1;
}
LIBC_INLINE bool operator<=(string_view Other) const {
return compare(Other) != 1;
}
LIBC_INLINE bool operator>(string_view Other) const {
return compare(Other) == 1;
}
LIBC_INLINE bool operator>=(string_view Other) const {
return compare(Other) != -1;
}
// Moves the start of the view forward by n characters.
// The behavior is undefined if n > size().
LIBC_INLINE void remove_prefix(size_t N) {
Len -= N;
Data += N;
}
// Moves the end of the view back by n characters.
// The behavior is undefined if n > size().
LIBC_INLINE void remove_suffix(size_t N) { Len -= N; }
// Check if this string starts with the given Prefix.
LIBC_INLINE bool starts_with(string_view Prefix) const {
return Len >= Prefix.Len &&
compareMemory(Data, Prefix.Data, Prefix.Len) == 0;
}
// Check if this string starts with the given Prefix.
LIBC_INLINE bool starts_with(const char Prefix) const {
return !empty() && front() == Prefix;
}
// Check if this string ends with the given Prefix.
LIBC_INLINE bool ends_with(const char Suffix) const {
return !empty() && back() == Suffix;
}
// Check if this string ends with the given Suffix.
LIBC_INLINE bool ends_with(string_view Suffix) const {
return Len >= Suffix.Len &&
compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
}
// Return a reference to the substring from [Start, Start + N).
//
// Start The index of the starting character in the substring; if the index is
// npos or greater than the length of the string then the empty substring will
// be returned.
//
// N The number of characters to included in the substring. If N exceeds the
// number of characters remaining in the string, the string suffix (starting
// with Start) will be returned.
LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const {
Start = min(Start, Len);
return string_view(Data + Start, min(N, Len - Start));
}
// front - Get the first character in the string.
LIBC_INLINE char front() const { return Data[0]; }
// back - Get the last character in the string.
LIBC_INLINE char back() const { return Data[Len - 1]; }
// Finds the first occurence of c in this view, starting at position From.
LIBC_INLINE size_t find_first_of(const char c, size_t From = 0) const {
for (size_t Pos = From; Pos < size(); ++Pos)
if ((*this)[Pos] == c)
return Pos;
return npos;
}
// Finds the last occurence of c in this view, ending at position End.
LIBC_INLINE size_t find_last_of(const char c, size_t End = npos) const {
End = End >= size() ? size() : End + 1;
for (; End > 0; --End)
if ((*this)[End - 1] == c)
return End - 1;
return npos;
}
};
} // namespace cpp
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H