[nostalgia/std] Add String as alternative to BString, which uses heap allocations

This commit is contained in:
Gary Talent 2020-03-14 16:30:14 -05:00
parent 317cfabc72
commit 38acb5dfc3
8 changed files with 368 additions and 157 deletions

View File

@ -15,9 +15,9 @@
namespace ox { namespace ox {
using String = BString<100>; using ModelString = BString<100>;
using FieldName = String; using FieldName = ModelString;
using TypeName = String; using TypeName = ModelString;
enum class PrimitiveType: uint8_t { enum class PrimitiveType: uint8_t {
UnsignedInteger = 0, UnsignedInteger = 0,
@ -170,6 +170,6 @@ Error modelRead(T *io, DescriptorField *field) {
return err; return err;
} }
using TypeStore = ox::HashMap<String, DescriptorType*>; using TypeStore = ox::HashMap<ModelString, DescriptorType*>;
} }

View File

@ -8,6 +8,7 @@ add_library(
random.cpp random.cpp
substitutes.cpp substitutes.cpp
stacktrace.cpp stacktrace.cpp
string.cpp
strops.cpp strops.cpp
trace.cpp trace.cpp
) )

197
deps/ox/src/ox/std/bstring.hpp vendored Normal file
View File

@ -0,0 +1,197 @@
/*
* Copyright 2015 - 2018 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "memops.hpp"
#include "strops.hpp"
#include "typetraits.hpp"
namespace ox {
// Bounded String
template<std::size_t buffLen>
class BString {
private:
char m_buff[buffLen + 1];
public:
constexpr BString() noexcept;
constexpr BString(const char *str) noexcept;
constexpr const BString &operator=(const char *str) noexcept;
constexpr const BString &operator=(char *str) noexcept;
constexpr const BString &operator=(int64_t i) noexcept;
constexpr const BString &operator+=(const char *str) noexcept;
constexpr const BString &operator+=(char *str) noexcept;
constexpr const BString &operator+=(int64_t i) noexcept;
constexpr bool operator==(const BString &other) noexcept;
constexpr bool operator!=(const BString &other) noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr char *data() noexcept;
constexpr const char *c_str() const noexcept;
/**
* Returns the number of characters in this string.
*/
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
*/
constexpr std::size_t bytes() const noexcept;
/**
* Returns the capacity of bytes for this string.
*/
constexpr std::size_t cap() const noexcept;
};
template<std::size_t size>
constexpr BString<size>::BString() noexcept {
m_buff[0] = 0;
}
template<std::size_t size>
constexpr BString<size>::BString(const char *str) noexcept {
*this = str;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator=(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
if (cap() < strLen) {
strLen = cap();
}
ox_memcpy(m_buff, str, strLen);
// make sure last element is a null terminator
m_buff[cap() - 1] = 0;
return *this;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(char *str) noexcept {
return *this = static_cast<const char*>(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
auto currentLen = len();
if (cap() < currentLen + strLen) {
strLen = cap() - currentLen;
}
ox_memcpy(m_buff + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
return *this;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator==(const BString<buffLen> &other) noexcept {
bool retval = true;
std::size_t i = 0;
while (i < buffLen && (m_buff[i] || other.m_buff[i])) {
if (m_buff[i] != other.m_buff[i]) {
retval = false;
break;
}
i++;
}
return retval;
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const BString<buffLen> &other) noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char *BString<buffLen>::data() noexcept {
return static_cast<char*>(m_buff);
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::c_str() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::len() const noexcept {
std::size_t length = 0;
for (std::size_t i = 0; i < buffLen; i++) {
uint8_t b = static_cast<uint8_t>(m_buff[i]);
if (b) {
if ((b & 128) == 0) { // normal ASCII character
length++;
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
length++;
}
} else {
break;
}
}
return length;
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
std::size_t i = 0;
for (i = 0; i < buffLen && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::cap() const noexcept {
return buffLen;
}
}

118
deps/ox/src/ox/std/string.cpp vendored Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright 2015 - 2018 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "string.hpp"
namespace ox {
String::String() noexcept {
m_buff.push_back(0);
}
String::String(const char *str) noexcept {
m_buff.push_back(0);
*this = str;
}
const String &String::operator=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator=(str);
}
const String &String::operator=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
m_buff.resize(strLen + 1);
memcpy(m_buff.data(), str, strLen);
// make sure last element is a null terminator
m_buff[m_buff.size() - 1] = 0;
return *this;
}
const String &String::operator=(char *str) noexcept {
return *this = static_cast<const char*>(str);
}
const String &String::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str);
auto currentLen = len();
m_buff.resize(m_buff.size() + strLen);
memcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
return *this;
}
const String &String::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
const String &String::operator+=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
bool String::operator==(const String &other) noexcept {
bool retval = true;
std::size_t i = 0;
while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) {
if (m_buff[i] != other.m_buff[i]) {
retval = false;
break;
}
i++;
}
return retval;
}
bool String::operator!=(const String &other) noexcept {
return !operator==(other);
}
char String::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
char &String::operator[](std::size_t i) noexcept {
return m_buff[i];
}
char *String::data() noexcept {
return m_buff.data();
}
const char *String::c_str() const noexcept {
return static_cast<const char*>(m_buff.data());
}
std::size_t String::len() const noexcept {
std::size_t length = 0;
for (std::size_t i = 0; i < m_buff.size(); i++) {
uint8_t b = static_cast<uint8_t>(m_buff[i]);
if (b) {
if ((b & 128) == 0) { // normal ASCII character
length++;
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
length++;
}
} else {
break;
}
}
return length;
}
std::size_t String::bytes() const noexcept {
std::size_t i = 0;
for (i = 0; i < m_buff.size() && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
}

View File

@ -8,190 +8,58 @@
#pragma once #pragma once
#include "bstring.hpp"
#include "memops.hpp" #include "memops.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "typetraits.hpp" #include "typetraits.hpp"
#include "vector.hpp"
namespace ox { namespace ox {
// Bounded String // Bounded String
template<std::size_t buffLen> class String {
class BString {
private: private:
char m_buff[buffLen + 1]; Vector<char> m_buff;
public: public:
constexpr BString() noexcept; String() noexcept;
constexpr BString(const char *str) noexcept; String(const char *str) noexcept;
constexpr const BString &operator=(const char *str) noexcept; const String &operator=(const char *str) noexcept;
constexpr const BString &operator=(char *str) noexcept; const String &operator=(char *str) noexcept;
constexpr const BString &operator=(int64_t i) noexcept; const String &operator=(int64_t i) noexcept;
constexpr const BString &operator+=(const char *str) noexcept; const String &operator+=(const char *str) noexcept;
constexpr const BString &operator+=(char *str) noexcept; const String &operator+=(char *str) noexcept;
constexpr const BString &operator+=(int64_t i) noexcept; const String &operator+=(int64_t i) noexcept;
constexpr bool operator==(const BString &other) noexcept; bool operator==(const String &other) noexcept;
constexpr bool operator!=(const BString &other) noexcept; bool operator!=(const String &other) noexcept;
constexpr char operator[](std::size_t i) const noexcept; char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept; char &operator[](std::size_t i) noexcept;
constexpr char *data() noexcept; char *data() noexcept;
constexpr const char *c_str() const noexcept; const char *c_str() const noexcept;
/** /**
* Returns the number of characters in this string. * Returns the number of characters in this string.
*/ */
constexpr std::size_t len() const noexcept; std::size_t len() const noexcept;
/** /**
* Returns the number of bytes used for this string. * Returns the number of bytes used for this string.
*/ */
constexpr std::size_t bytes() const noexcept; std::size_t bytes() const noexcept;
/**
* Returns the capacity of bytes for this string.
*/
constexpr std::size_t cap() const noexcept;
}; };
template<std::size_t size>
constexpr BString<size>::BString() noexcept {
m_buff[0] = 0;
}
template<std::size_t size>
constexpr BString<size>::BString(const char *str) noexcept {
*this = str;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator=(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
if (cap() < strLen) {
strLen = cap();
}
ox_memcpy(m_buff, str, strLen);
// make sure last element is a null terminator
m_buff[cap() - 1] = 0;
return *this;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator=(char *str) noexcept {
return *this = static_cast<const char*>(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str) + 1;
auto currentLen = len();
if (cap() < currentLen + strLen) {
strLen = cap() - currentLen;
}
ox_memcpy(m_buff + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
return *this;
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t size>
constexpr const BString<size> &BString<size>::operator+=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator==(const BString<buffLen> &other) noexcept {
bool retval = true;
std::size_t i = 0;
while (i < buffLen && (m_buff[i] || other.m_buff[i])) {
if (m_buff[i] != other.m_buff[i]) {
retval = false;
break;
}
i++;
}
return retval;
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const BString<buffLen> &other) noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char *BString<buffLen>::data() noexcept {
return static_cast<char*>(m_buff);
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::c_str() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::len() const noexcept {
std::size_t length = 0;
for (std::size_t i = 0; i < buffLen; i++) {
uint8_t b = static_cast<uint8_t>(m_buff[i]);
if (b) {
if ((b & 128) == 0) { // normal ASCII character
length++;
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
length++;
}
} else {
break;
}
}
return length;
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
std::size_t i = 0;
for (i = 0; i < buffLen && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::cap() const noexcept {
return buffLen;
}
} }

View File

@ -12,5 +12,6 @@ add_test("Test\\ ox_memcmp\\ HIJKLMN\\ !=\\ ABCDEFG" StdTest "HIJKLMN != ABCDEFG
add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG") add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG")
add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG") add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG")
add_test("Test\\ BString" StdTest "BString") add_test("Test\\ BString" StdTest "BString")
add_test("Test\\ String" StdTest "String")
add_test("Test\\ Vector" StdTest "Vector") add_test("Test\\ Vector" StdTest "Vector")
add_test("Test\\ HashMap" StdTest "HashMap") add_test("Test\\ HashMap" StdTest "HashMap")

View File

@ -40,12 +40,30 @@ map<string, function<int()>> tests = {
{ {
"BString", "BString",
[]() { []() {
ox::BString<100> s; ox::BString<5> s;
s += "A"; s += "A";
s += "B"; s += "B";
s += 9; s += 9;
s += "C"; s += "C";
oxAssert(s == "AB9C", "BString append broken"); oxAssert(s == "AB9C", "BString append broken");
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
return OxError(0);
}
},
{
"String",
[]() {
ox::String s;
s += "A";
s += "B";
s += 9;
s += "C";
oxAssert(s == "AB9C", "String append broken");
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
s += "aoeu";
oxAssert(s == "asdfaoeu", "String append broken");
return OxError(0); return OxError(0);
} }
}, },

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "new.hpp"
#include "types.hpp" #include "types.hpp"
#include "utility.hpp" #include "utility.hpp"
@ -54,6 +55,8 @@ class Vector {
T *data(); T *data();
const T *data() const;
bool contains(T) const noexcept; bool contains(T) const noexcept;
template<typename... Args> template<typename... Args>
@ -197,6 +200,11 @@ T *Vector<T>::data() {
return m_items; return m_items;
} }
template<typename T>
const T *Vector<T>::data() const {
return m_items;
}
template<typename T> template<typename T>
bool Vector<T>::contains(T v) const noexcept { bool Vector<T>::contains(T v) const noexcept {
for (std::size_t i = 0; i < m_size; i++) { for (std::size_t i = 0; i < m_size; i++) {