Files
moslab-code/src/l4/pkg/l4re-core/cxx/lib/base/include/string
2025-09-12 15:55:45 +02:00

314 lines
6.7 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/**
* Strings.
*/
#pragma once
#include <l4/cxx/minmax>
#include <l4/cxx/basic_ostream>
namespace cxx {
/**
* Allocation free string class with explicit length field.
*
* This class is used to group characters of a string which belong
* to one syntactical token types number, identifier, string,
* whitespace or another single character.
*
* Stings in this class can contain null bytes and may denote parts of
* other strings.
*/
class String
{
public:
/// Character index type.
typedef char const *Index;
/// Initialize from a zero-terminated string.
String(char const *s) noexcept : _start(s), _len(__builtin_strlen(s)) {}
/// Initialize from a pointer to first character and a length.
String(char const *s, unsigned long len) noexcept : _start(s), _len(len) {}
/**
* Initialize with start and end pointer.
*
* \param s first character of the string
* \param e pointer to first byte behind the string
*/
String(char const *s, char const *e) noexcept : _start(s), _len(e - s) {}
/// Zero-initialize. Create an invalid string.
String() : _start(0), _len(0) {}
/// Pointer to first character.
Index start() const { return _start; }
/// Pointer to first byte behind the string.
Index end() const { return _start + _len; }
/// Length.
int len() const { return _len; }
/// Set start.
void start(char const *s) { _start = s; }
/// Set length.
void len(unsigned long len) { _len = len; }
/// Check if the string has length zero.
bool empty() const { return !_len; }
/// Return prefix up to index.
String head(Index end) const
{
if (end < _start)
return String();
if (eof(end))
return *this;
return String(_start, end - _start);
}
/// Prefix of length `end`.
String head(unsigned long end) const
{ return head(start() + end); }
/// Substring of length `len` starting at `idx`.
String substr(unsigned long idx, unsigned long len = ~0UL) const
{
if (idx >= _len)
return String(end(), 0UL);
return String(_start + idx, cxx::min(len, _len - idx));
}
/// Substring of length `len` starting at `start`.
String substr(char const *start, unsigned long len = 0) const
{
if (start >= _start && !eof(start))
{
unsigned long nlen = _start + _len - start;
if (len != 0)
nlen = cxx::min(nlen, len);
return String(start, nlen);
}
return String(end(), 0UL);
}
/// Find matching character. `match` should be a function such as `isspace`.
template< typename F >
char const *find_match(F &&match) const
{
String::Index s = _start;
while (1)
{
if (eof(s))
return s;
if (match(*s))
return s;
++s;
}
}
/// Find character. Return end() if not found.
char const *find(char const *c) const
{ return find(c, start()); }
/// Find character. Return end() if not found.
char const *find(int c) const
{ return find(c, start()); }
/// Find right-most character. Return end() if not found.
char const *rfind(char const *c) const
{
if (!_len)
return end();
char const *p = end();
--p;
while (p >= _start)
{
if (*p == *c)
return p;
--p;
}
return end();
}
/**
* Check if `c` is a prefix of string.
*
* \return 0 if `c` is not a prefix, if it is a prefix, return
* first position not in `c` (which might be end()).
*/
Index starts_with(cxx::String const &c) const
{
unsigned long i;
for (i = 0; i < c._len && i < _len; ++i)
if (_start[i] != c[i])
return 0;
return i == c._len ? start() + i : 0;
}
/// Find character `c` starting at position `s`. Return end() if not found.
char const *find(int c, char const *s) const
{
if (s < _start)
return end();
while (1)
{
if (eof(s))
return s;
if (*s == c)
return s;
++s;
}
}
/**
* Find character set at position.
*
* \param c zero-terminated string of characters to search for
* \param s start position of search in string
*
* \retval end() if no char in `c` is contained in string at or behind `s`.
* \retval position in string of some character in `c`.
*/
char const *find(char const *c, char const *s) const
{
if (s < _start)
return end();
while (1)
{
if (eof(s))
return s;
for (char const *x = c; *x; ++x)
if (*s == *x)
return s;
++s;
}
}
/// Get character at `idx`.
char const &operator [] (unsigned long idx) const { return _start[idx]; }
/// Get character at `idx`.
char const &operator [] (int idx) const { return _start[idx]; }
/// Get character at `idx`.
char const &operator [] (Index idx) const { return *idx; }
/// Check if pointer `s` points behind string.
bool eof(char const *s) const { return s >= _start + _len || !*s; }
/**
* Convert decimal string to integer.
*
* \tparam INT result integer type
* \param[out] v conversion result
*
* \return position of first character not converted.
*/
template<typename INT>
int from_dec(INT *v) const
{
*v = 0;
Index c;
for (c = start(); !eof(c); ++c)
{
unsigned char n;
if (*c >= '0' && *c <= '9')
n = *c - '0';
else
return c - start();
*v *= 10;
*v += n;
}
return c - start();
}
/**
* Convert hex string to integer.
*
* \tparam INT result integer type
* \param[out] v conversion result
*
* \retval -1 if the maximal amount of digits fitting into `INT` have
* been read,
* \retval position of first character not converted otherwise.
*/
template<typename INT>
int from_hex(INT *v) const
{
*v = 0;
unsigned shift = 0;
Index c;
for (c = start(); !eof(c); ++c)
{
shift += 4;
if (shift > sizeof(INT) * 8)
return -1;
unsigned char n;
if (*c >= '0' && *c <= '9')
n = *c - '0';
else if (*c >= 'A' && *c <= 'F')
n = *c - 'A' + 10;
else if (*c >= 'a' && *c <= 'f')
n = *c - 'a' + 10;
else
return c - start();
*v <<= 4;
*v |= n;
}
return c - start();
}
/// Equality.
bool operator == (String const &o) const
{
if (len() != o.len())
return false;
for (unsigned long i = 0; i < _len; ++i)
if (_start[i] != o._start[i])
return false;
return true;
}
/// Inequality.
bool operator != (String const &o) const
{ return ! (operator == (o)); }
private:
char const *_start;
unsigned long _len;
};
}
/// Write `str` on `s`.
inline
L4::BasicOStream &operator << (L4::BasicOStream &s, cxx::String const &str)
{
s.write(str.start(), str.len());
return s;
}