Move userspace to a templated StrFormat.

This commit is contained in:
Drew Galbraith 2023-11-03 02:48:21 -07:00
parent d9df1212b7
commit 26b61db021
25 changed files with 263 additions and 217 deletions

View file

@ -1,6 +1,8 @@
add_library(glacier STATIC
string/string.cpp
string/string_builder.cpp
string/string_view.cpp
string/str_format.cpp
string/str_split.cpp
)

View file

@ -57,6 +57,8 @@ class Vector {
uint64_t size() const { return size_; }
uint64_t capacity() const { return capacity_; }
const T* RawPtr() const { return data_; }
private:
T* data_;
uint64_t size_;

View file

@ -0,0 +1,73 @@
#include "glacier/string/str_format.h"
namespace glcr {
namespace {
void StrFormatNumber(StringBuilder& builder, uint64_t value, uint64_t base) {
const char* kHexCharacters = "0123456789ABCDEF";
if (value < base) {
builder.PushBack(kHexCharacters[value]);
return;
}
StrFormatNumber(builder, value / base, base);
builder.PushBack(kHexCharacters[value % base]);
}
} // namespace
template <>
void StrFormatValue(StringBuilder& builder, uint8_t value, StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, uint16_t value, StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, int32_t value, StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, uint32_t value, StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, uint64_t value, StringView opts) {
if (opts.find('x') != opts.npos) {
builder.PushBack("0x");
StrFormatNumber(builder, value, 16);
} else {
StrFormatNumber(builder, value, 10);
}
}
template <>
void StrFormatValue(StringBuilder& builder, ErrorCode value, StringView opts) {
StrFormatValue(builder, static_cast<uint64_t>(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, const char* value,
StringView opts) {
StrFormatValue(builder, StringView(value), opts);
}
template <>
void StrFormatValue(StringBuilder& builder, StringView value, StringView opts) {
StrFormatInternal(builder, value);
}
void StrFormatInternal(StringBuilder& builder, StringView format) {
// TODO: Consider throwing an error if there are unhandled format
builder.PushBack(format);
}
} // namespace glcr

View file

@ -0,0 +1,62 @@
#pragma once
#include "glacier/memory/move.h"
#include "glacier/status/error.h"
#include "glacier/string/string_builder.h"
#include "glacier/string/string_view.h"
namespace glcr {
template <typename T>
void StrFormatValue(StringBuilder& builder, T value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, uint8_t value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, uint16_t value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, int32_t value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, uint32_t value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, uint64_t value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, ErrorCode value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, const char* value, StringView opts);
template <>
void StrFormatValue(StringBuilder& builder, StringView value, StringView opts);
void StrFormatInternal(StringBuilder& builder, StringView format);
template <typename T, typename... Args>
void StrFormatInternal(StringBuilder& builder, StringView format, T value,
Args... args) {
uint64_t posl = format.find('{');
uint64_t posr = format.find('}', posl);
if (posl == format.npos || posr == format.npos) {
// TODO: Consider throwing an error since we still have values to consume.
return StrFormatInternal(builder, format);
}
builder.PushBack(format.substr(0, posl));
StrFormatValue(builder, value, format.substr(posl + 1, posr - posl - 1));
StrFormatInternal(builder, format.substr(posr + 1, format.size() - posr - 1),
args...);
}
template <typename... Args>
StringBuilder StrFormat(StringView format, Args... args) {
StringBuilder builder;
StrFormatInternal(builder, format, args...);
return glcr::Move(builder);
}
} // namespace glcr

View file

@ -0,0 +1,24 @@
#include "glacier/string/string_builder.h"
namespace glcr {
void StringBuilder::PushBack(const StringView& str) {
if (capacity() < size() + str.size()) {
uint64_t new_capacity = capacity() == 0 ? 1 : capacity() * 2;
while (new_capacity < size() + str.size()) {
new_capacity *= 2;
}
Resize(new_capacity);
}
for (uint64_t i = 0; i < str.size(); i++) {
Vector<char>::PushBack(str[i]);
}
}
String StringBuilder::ToString() const { return String(RawPtr(), size()); }
StringBuilder::operator StringView() const {
return StringView(RawPtr(), size());
}
} // namespace glcr

View file

@ -0,0 +1,26 @@
#pragma once
#include "glacier/container/vector.h"
#include "glacier/string/string.h"
#include "glacier/string/string_view.h"
namespace glcr {
class StringBuilder : public Vector<char> {
public:
StringBuilder() : Vector<char>() {}
StringBuilder(const StringBuilder&) = delete;
StringBuilder(StringBuilder&& str) : Vector<char>(Move(str)) {}
void PushBack(const StringView& str);
using Vector<char>::PushBack;
String ToString() const;
// Note that this could become invalidated
// at any time if more characters are pushed
// onto the builder.
operator StringView() const;
};
} // namespace glcr

View file

@ -25,6 +25,7 @@ uint64_t StringView::size() const { return size_; }
bool StringView::empty() const { return size_ == 0; }
char StringView::at(uint64_t pos) const { return value_[pos]; }
char StringView::operator[](uint64_t pos) const { return at(pos); };
uint64_t StringView::find(char c, uint64_t pos) const {
for (uint64_t i = pos; i < size_; i++) {

View file

@ -19,6 +19,7 @@ class StringView {
bool empty() const;
char at(uint64_t pos) const;
char operator[](uint64_t pos) const;
uint64_t find(char c, uint64_t pos = 0) const;