flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:43:06 -05:00
commit 996151a56a
521 changed files with 46722 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <map>
#include <string>
#include <string_view>
#include "../threads/Lock.hpp"
#include "../ptr/Ptr.hpp"
namespace tjp {
namespace core {
namespace string_dictionary {
struct Instance;
struct Entry;
struct Dictionary;
struct Reference
{
StrongPtr<Entry> entry;
operator const std::string &() const;
operator const std::string_view () const;
} ;
struct Entry
{
StrongPtr<Dictionary> container;
const std::string value;
Entry(const StrongPtr<Dictionary> &container, std::string &&string);
~Entry ();
} ;
bool operator ==(const Reference &lhs, const Reference &rhs);
bool operator ==(const Reference &lhs, const std::string &r);
bool operator ==(const Reference &lhs, const std::string_view &r);
bool operator ==(const Reference &lhs, const char *r);
bool operator ==(const std::string &l, const Reference &rhs);
bool operator ==(const std::string_view &l, const Reference &rhs);
bool operator ==(const char *l, const Reference &rhs);
bool operator !=(const Reference &lhs, const Reference &rhs);
bool operator !=(const Reference &lhs, const std::string &r);
bool operator !=(const Reference &lhs, const std::string_view &r);
bool operator !=(const Reference &lhs, const char *r);
bool operator !=(const std::string &l, const Reference &rhs);
bool operator !=(const std::string_view &l, const Reference &rhs);
bool operator !=(const char *l, const Reference &rhs);
bool operator <(const Reference &lhs, const Reference &rhs);
bool operator <(const Reference &lhs, const std::string &r);
bool operator <(const Reference &lhs, const std::string_view &r);
bool operator <(const Reference &lhs, const char *r);
bool operator <(const std::string &l, const Reference &rhs);
bool operator <(const std::string_view &l, const Reference &rhs);
bool operator <(const char *l, const Reference &rhs);
// ----
struct Dictionary : StrongThis<Dictionary>
{
Mutex mutex;
std::map<std::string_view, WeakPtr<Entry>> entries;
void remove(Entry *entry);
Reference get(const std::string_view &value);
Reference get(const std::string &value);
Reference get(std::string &&value);
Reference get(const char *value);
} ;
} // namespace
using StringDictionary = string_dictionary::Dictionary;
using StringRef = string_dictionary::Reference;
} // namespace
} // namespace
#include "Dictionary.inl"

View File

@@ -0,0 +1,233 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
namespace tjp {
namespace core {
namespace string_dictionary {
// ----
inline
Entry::Entry(const StrongPtr<Dictionary> &container_, std::string &&value_) :
container(container_),
value(std::move(value_))
{
}
inline
Entry::~Entry ()
{
if (container)
container->remove(this);
}
// ----
inline
Reference::operator const std::string &() const
{
return entry->value;
}
inline
Reference::operator const std::string_view () const
{
return entry->value;
}
inline
bool operator ==(const Reference &lhs, const Reference &rhs)
{
return (const std::string &)lhs == (const std::string &)rhs;
}
inline
bool operator ==(const Reference &lhs, const std::string &r)
{
return (const std::string &)lhs == r;
}
inline
bool operator ==(const Reference &lhs, const std::string_view &r)
{
return (const std::string &)lhs == r;
}
inline
bool operator ==(const Reference &lhs, const char *r)
{
return (const std::string &)lhs == r;
}
inline
bool operator ==(const std::string &l, const Reference &rhs)
{
return l == (const std::string &)rhs;
}
inline
bool operator ==(const std::string_view &l, const Reference &rhs)
{
return l == (const std::string &)rhs;
}
inline
bool operator ==(const char *l, const Reference &rhs)
{
return l == (const std::string &)rhs;
}
inline
bool operator !=(const Reference &lhs, const Reference &rhs)
{
return (const std::string &)lhs != (const std::string &)rhs;
}
inline
bool operator !=(const Reference &lhs, const std::string &r)
{
return (const std::string &)lhs != r;
}
inline
bool operator !=(const Reference &lhs, const std::string_view &r)
{
return (const std::string &)lhs != r;
}
inline
bool operator !=(const Reference &lhs, const char *r)
{
return (const std::string &)lhs != r;
}
inline
bool operator !=(const std::string &l, const Reference &rhs)
{
return l != (const std::string &)rhs;
}
inline
bool operator !=(const std::string_view &l, const Reference &rhs)
{
return l != (const std::string &)rhs;
}
inline
bool operator !=(const char *l, const Reference &rhs)
{
return l != (const std::string &)rhs;
}
inline
bool operator <(const Reference &lhs, const Reference &rhs)
{
return (const std::string &)lhs < (const std::string &)rhs;
}
inline
bool operator <(const Reference &lhs, const std::string &r)
{
return (const std::string &)lhs < r;
}
inline
bool operator <(const Reference &lhs, const std::string_view &r)
{
return (const std::string &)lhs < r;
}
inline
bool operator <(const Reference &lhs, const char *r)
{
return (const std::string &)lhs < r;
}
inline
bool operator <(const std::string &l, const Reference &rhs)
{
return l < (const std::string &)rhs;
}
inline
bool operator <(const std::string_view &l, const Reference &rhs)
{
return l < (const std::string &)rhs;
}
inline
bool operator <(const char *l, const Reference &rhs)
{
return l < (const std::string &)rhs;
}
// ----
inline
void Dictionary::remove(Entry *entry)
{
auto i = entries.find(entry->value);
if (i != entries.end())
entries.erase(i);
}
inline
Reference Dictionary::get(const std::string_view &value)
{
auto i = entries.find(value);
if (i != entries.end())
return { strong(i->second) };
auto entry = strong<Entry>(Entry { strong_this(this), std::string(value) });
entries.emplace(entry->value, entry);
return { std::move(entry) };
}
inline
Reference Dictionary::get(const std::string &value)
{
auto i = entries.find(value);
if (i != entries.end())
return { strong(i->second) };
auto entry = strong<Entry>(strong_this(this), std::string(value));
entries.emplace(entry->value, entry);
return { std::move(entry) };
}
inline
Reference Dictionary::get(std::string &&value)
{
auto i = entries.find(value);
if (i != entries.end())
return { strong(i->second) };
auto entry = strong<Entry>(strong_this(this), std::move(value));
entries.emplace(entry->value, entry);
return { std::move(entry) };
}
inline
Reference Dictionary::get(const char *value)
{
auto i = entries.find(value);
if (i != entries.end())
return { strong(i->second) };
auto entry = strong<Entry>(strong_this(this), std::string(value));
entries.emplace(entry->value, entry);
return { std::move(entry) };
}
} // namespace
} // namespace
} // namespace

40
tjp/core/string/Str+IO.h Executable file
View File

@@ -0,0 +1,40 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Str.h"
#include <iosfwd>
#include "from_string.h"
namespace tjp::core::str {
#ifdef TJP_STR_USE_TEMPLATES
template<typename IO, int N1>
void io_(IO &io, TJP_STR &v)
{
io.intrinsic_string(v);
}
#else
template<typename IO>
void io_(IO &io, TJP_STR &v)
{
io.intrinsic_string(v);
}
#endif
TJP_STR_TEMPLATE
TJP_STR_INLINE
std::ostream &operator <<(std::ostream &o, const TJP_STR &v);
TJP_STR_TEMPLATE
TJP_STR_INLINE
void from_string(str::TJP_STR &v, const std::string_view &s);
} // namespace
#include "Str+IO.inl"

26
tjp/core/string/Str+IO.inl Executable file
View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "Str+IO.h"
#include "Str.hpp"
#include "from_string.h"
namespace tjp::core::str {
TJP_STR_TEMPLATE
TJP_STR_INLINE
std::ostream &operator <<(std::ostream &o, const TJP_STR &v)
{
return o << (std::string_view)v;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
void from_string(str::TJP_STR &v, const std::string_view &s)
{
v = s;
}
} // namespace

10
tjp/core/string/Str.cpp Normal file
View File

@@ -0,0 +1,10 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "Str.hpp"
#ifndef TJP_STR_INLINE
#define TJP_STR_INLINE
#include "Str.inl"
#endif

150
tjp/core/string/Str.h Executable file
View File

@@ -0,0 +1,150 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
#include "../rtti/TypeName+custom.hpp"
namespace tjp::core {
namespace str {
#define TJP_STR_INLINE inline
#define TJP_STR_USE_TEMPLATES
#ifdef TJP_STR_USE_TEMPLATES
constexpr int Str_DefaultN = 48;
template<int N=Str_DefaultN>
struct Str;
#define TJP_STR_TEMPLATE template<int N1>
#define TJP_STR_TEMPLATE2 template<int N2>
#define TJP_STR_TEMPLATE12 template<int N1, int N2>
#define CONST_TEMPLATE_N1 N1
#define TJP_STR Str<N1>
#define TJP_STR2 Str<N2>
#define TJP_STR_TYPENAME typename TJP_STR
#define TJP_STR_DEFAULT Str<Str_DefaultN>
#else
struct Str;
#define TJP_STR_TEMPLATE
#define TJP_STR_TEMPLATE12
#define TJP_STR_TEMPLATE2
#define CONST_TEMPLATE_N1 48
#define TJP_STR Str
#define TJP_STR2 Str
#define TJP_STR_TYPENAME TJP_STR
#define TJP_STR_DEFAULT Str
#endif
TJP_STR_TEMPLATE12
bool operator ==(const TJP_STR &lhs, const TJP_STR2 &rhs);
TJP_STR_TEMPLATE
bool operator ==(const TJP_STR &lhs, const String &r);
TJP_STR_TEMPLATE
bool operator ==(const TJP_STR &lhs, const StringView &r);
TJP_STR_TEMPLATE
bool operator ==(const TJP_STR &lhs, const char *r);
TJP_STR_TEMPLATE
bool operator ==(const String &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator ==(const StringView &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator ==(const char *l, const TJP_STR &rhs);
TJP_STR_TEMPLATE12
bool operator !=(const TJP_STR &lhs, const TJP_STR2 &rhs);
TJP_STR_TEMPLATE
bool operator !=(const TJP_STR &lhs, const String &r);
TJP_STR_TEMPLATE
bool operator !=(const TJP_STR &lhs, const StringView &r);
TJP_STR_TEMPLATE
bool operator !=(const TJP_STR &lhs, const char *r);
TJP_STR_TEMPLATE
bool operator !=(const String &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator !=(const StringView &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator !=(const char *l, const TJP_STR &rhs);
TJP_STR_TEMPLATE12
bool operator <(const TJP_STR &lhs, const TJP_STR2 &rhs);
TJP_STR_TEMPLATE
bool operator <(const TJP_STR &lhs, const String &r);
TJP_STR_TEMPLATE
bool operator <(const TJP_STR &lhs, const StringView &r);
TJP_STR_TEMPLATE
bool operator <(const TJP_STR &lhs, const char *r);
TJP_STR_TEMPLATE
bool operator <(const String &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator <(const StringView &l, const TJP_STR &rhs);
TJP_STR_TEMPLATE
bool operator <(const char *l, const TJP_STR &rhs);
TJP_STR_TEMPLATE12
TJP_STR operator+(const TJP_STR &lhs, const TJP_STR2 &rhs);
TJP_STR_TEMPLATE
TJP_STR operator+(const String &lhs, const TJP_STR &rhs);
TJP_STR_TEMPLATE
TJP_STR operator+(const StringView &lhs, const TJP_STR &rhs);
TJP_STR_TEMPLATE
TJP_STR operator+(const char *lhs, const TJP_STR &rhs);
TJP_STR_TEMPLATE
TJP_STR operator+(const TJP_STR &lhs, const String &rhs);
TJP_STR_TEMPLATE
TJP_STR operator+(const TJP_STR &lhs, const StringView &rhs);
TJP_STR_DEFAULT operator+(const char *lhs, const StringView &rhs);
} // namespace
#ifdef TJP_STR_USE_TEMPLATES
template<int N1=str::Str_DefaultN>
using StrN = str::TJP_STR;
using Str = StrN<str::Str_DefaultN>;
using Str = Str;
#else
using Str = str::TJP_STR;
using Str = Str;
#endif
} // namespace
TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(tjp::core::Str);

58
tjp/core/string/Str.hpp Executable file
View File

@@ -0,0 +1,58 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Str.h"
#include "../containers/StackArray.hpp"
namespace tjp::core::str {
TJP_STR_TEMPLATE
struct Str
{
static constexpr int N = CONST_TEMPLATE_N1;
using Internal = StackArray<char, N>;
using value_type = typename Internal::value_type;
using const_iterator_ = typename Internal::const_iterator;
Internal string;
Str();
Str(size_t size, char initializer);
Str(const String &rhs);
Str(const StringView &rhs);
Str(const char *rhs);
Str(const char *begin, const char *end);
Str(const StringView &v0, const StringView &v1);
TJP_STR_TEMPLATE2
Str(const TJP_STR2 &rhs);
explicit Str(const Vector<char> &v);
operator const StringView () const;
bool empty() const;
void clear();
const value_type *data() const;
const_iterator_ begin() const;
const_iterator_ end() const;
size_t size () const;
char front() const;
char back() const;
const char *c_str() const;
const char *c_str();
String toString() const;
} ;
} // namespace
#ifdef TJP_STR_INLINE
#include "Str.inl"
#endif

464
tjp/core/string/Str.inl Normal file
View File

@@ -0,0 +1,464 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Str.hpp"
#include "../algorithm/small_cmp.hpp"
#include <cstring>
namespace tjp {
namespace core {
namespace str {
typedef StringView compare_type;
TJP_STR_INLINE
auto cmp (const compare_type &l, const compare_type &r)
{
return small_cmp(l.data(), l.size(), r.data(), r.size());
}
TJP_STR_INLINE
auto cmp (const compare_type &l, const char *r)
{
return small_cmp(l.data(), l.size(), r);
}
TJP_STR_INLINE
auto cmp (const char *l, const compare_type &r)
{
return -cmp(r, l);
}
TJP_STR_TEMPLATE12
TJP_STR_INLINE
auto cmp(const TJP_STR &lhs, const TJP_STR2 &rhs)
{
return small_cmp(lhs.data(), lhs.size(), rhs.data(), rhs.size());
}
TJP_STR_INLINE
auto add(const compare_type &l, const compare_type &r)
{
return Str(l, r);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str()
{
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(size_t size, char c)
{
for (auto i=0; i<size; ++i)
string.push_back(c);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const String &rhs) :
string(rhs.data(), rhs.data() + rhs.size())
{
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const Vector<char> &rhs) :
string(rhs.data(), rhs.data() + rhs.size())
{
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const StringView &rhs) :
string(rhs.data(), rhs.data() + rhs.size())
{
}
TJP_STR_TEMPLATE
TJP_STR_TEMPLATE2
TJP_STR_INLINE
TJP_STR::Str(const TJP_STR2 &rhs) :
string(rhs.string)
{
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const char *begin, const char *end) :
string(begin, end)
{
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const char *rhs)
{
debug_assert(rhs);
if (!rhs)
return;
auto MAX = 16384;
for (auto i=0; i<MAX; ++i)
{
if (*rhs == 0)
break;
string.push_back(*rhs++);
}
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::Str(const StringView &v0, const StringView &v1)
{
string.size_to(v0.size() + v1.size());
string.append(v0.data(), v0.data() + v0.size());
string.append(v1.data(), v1.data() + v1.size());
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
String TJP_STR::toString() const
{
return String(string.begin(), string.size());
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR::operator const StringView () const
{
return StringView(string.begin(), string.size());
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool TJP_STR::empty() const
{
return string.empty();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
void TJP_STR::clear()
{
return string.clear();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
char TJP_STR::front() const
{
return string.front();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
char TJP_STR::back() const
{
return string.back();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
const TJP_STR_TYPENAME::value_type *TJP_STR::data() const
{
return string.data();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR_TYPENAME::const_iterator_ TJP_STR::begin() const
{
return string.begin();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR_TYPENAME::const_iterator_ TJP_STR::end() const
{
return string.end();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
size_t TJP_STR::size() const
{
return string.size();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
const char *TJP_STR::c_str()
{
string.push_back(0);
string.pop_back();
return string.data();
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
const char *TJP_STR::c_str() const
{
return const_cast<TJP_STR *>(this)->c_str();
}
TJP_STR_INLINE
bool operator ==(const compare_type &lhs, const char *rhs)
{
return cmp(lhs, rhs) == 0;
}
TJP_STR_INLINE
bool operator ==(const char *lhs, const compare_type &rhs)
{
return rhs == lhs;
}
TJP_STR_INLINE
bool operator !=(const compare_type &lhs, const char *rhs)
{
return !(lhs == rhs);
}
TJP_STR_INLINE
bool operator !=(const char *lhs, const compare_type &rhs)
{
return !(lhs == rhs);
}
TJP_STR_INLINE
bool operator <(const compare_type &lhs, const char *rhs)
{
return cmp(lhs, rhs) < 0;
}
TJP_STR_INLINE
bool operator <(const char *lhs, const compare_type &rhs)
{
return cmp(lhs, rhs) < 0;
}
TJP_STR_TEMPLATE12
TJP_STR_INLINE
bool operator ==(const TJP_STR &lhs, const TJP_STR2 &rhs)
{
return cmp(lhs, rhs) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const TJP_STR &lhs, const String &r)
{
return cmp((const compare_type &)lhs, compare_type(r)) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const TJP_STR &lhs, const StringView &r)
{
return cmp((const compare_type &)lhs, r) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const TJP_STR &lhs, const char *r)
{
return cmp((const compare_type &)lhs, r) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const String &l, const TJP_STR &rhs)
{
return cmp(compare_type(l), (const compare_type &)rhs) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const StringView &l, const TJP_STR &rhs)
{
return cmp(l, (const compare_type &)rhs) == 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator ==(const char *l, const TJP_STR &rhs)
{
return cmp(l, (const compare_type &)rhs) == 0;
}
TJP_STR_TEMPLATE12
TJP_STR_INLINE
bool operator !=(const TJP_STR &lhs, const TJP_STR2 &rhs)
{
return cmp(lhs, rhs) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const TJP_STR &lhs, const String &r)
{
return cmp((const compare_type &)lhs, compare_type(r)) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const TJP_STR &lhs, const StringView &r)
{
return cmp((const compare_type &)lhs, r) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const TJP_STR &lhs, const char *r)
{
return cmp((const compare_type &)lhs, r) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const String &l, const TJP_STR &rhs)
{
return cmp(compare_type(l), (const compare_type &)rhs) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const StringView &l, const TJP_STR &rhs)
{
return cmp(compare_type(l), (const compare_type &)rhs) != 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator !=(const char *l, const TJP_STR &rhs)
{
return cmp(l, (const compare_type &)rhs) != 0;
}
TJP_STR_TEMPLATE12
TJP_STR_INLINE
bool operator <(const TJP_STR &lhs, const TJP_STR2 &rhs)
{
return cmp(lhs, rhs) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const TJP_STR &lhs, const String &r)
{
return cmp((const compare_type &)lhs, compare_type(r)) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const TJP_STR &lhs, const StringView &r)
{
return cmp((const compare_type &)lhs, r) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const TJP_STR &lhs, const char *r)
{
return cmp((const compare_type &)lhs, r) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const String &l, const TJP_STR &rhs)
{
return cmp(compare_type(l), (const compare_type &)rhs) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const StringView &l, const TJP_STR &rhs)
{
return cmp(l, (const compare_type &)rhs) < 0;
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
bool operator <(const char *l, const TJP_STR &rhs)
{
return cmp(l, (const compare_type &)rhs) < 0;
}
TJP_STR_TEMPLATE12
TJP_STR_INLINE
TJP_STR operator+(const TJP_STR &lhs, const TJP_STR2 &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const String &lhs, const TJP_STR &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const StringView &lhs, const TJP_STR &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const char *lhs, const TJP_STR &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const TJP_STR &lhs, const String &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const TJP_STR &lhs, const StringView &rhs)
{
return add(lhs, rhs);
}
TJP_STR_TEMPLATE
TJP_STR_INLINE
TJP_STR operator+(const TJP_STR &lhs, const char *rhs)
{
return add(lhs, rhs);
}
} // namespace
} // namespace
} // namespace

13
tjp/core/string/String.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
// TODO: this header should be String+RTTI.hpp, and String_.h should be String.h
#include "String_.h"
#include "../rtti/TypeName.hpp"
TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(tjp::core::String);

7
tjp/core/string/String.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"

View File

@@ -0,0 +1,81 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
namespace tjp::core {
template<typename ... Args>
size_t concat_size(const StringView &s)
{
return s.size();
}
template<typename ... Args>
size_t concat_size(const StringView &s, Args && ...args)
{
return concat_size(s) + concat_size(args...);
}
template<typename ... Args>
void concat_ (String &s, const StringView &v)
{
s.insert(s.end(), v.begin(), v.end());
}
template<typename ... Args>
void concat_ (String &s, const StringView &v, Args && ...args)
{
s.insert(s.end(), v.begin(), v.end());
concat_(s, std::forward<Args>(args)...);
}
template<typename ... Args>
String concat (Args && ...args)
{
String s;
s.reserve(concat_size(args...));
concat_(s, std::forward<Args>(args)...);
return s;
}
} // namespace
namespace std {
inline
std::string operator +(const std::string &lhs, const std::string_view &rhs)
{
return tjp::core::concat(lhs, rhs);
}
inline
std::string operator +(const std::string_view &lhs, const std::string &rhs)
{
return tjp::core::concat(lhs, rhs);
}
inline
std::string operator +(const std::string_view &lhs, const std::string_view &rhs)
{
return tjp::core::concat(lhs, rhs);
}
inline
std::string operator +(const char *lhs, const std::string_view &rhs)
{
return tjp::core::concat(lhs, rhs);
}
inline
std::string operator +(const std::string_view &lhs, const char *rhs)
{
return tjp::core::concat(lhs, rhs);
}
} // namespace

View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
namespace tjp::core {
inline
bool operator <(const String &lhs, const StringView &rhs)
{
return (StringView)lhs < rhs;
}
inline
bool operator <(const StringView &lhs, const String &rhs)
{
return lhs < (StringView)rhs;
}
} // namespace

13
tjp/core/string/StringView.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string_view>
namespace tjp::core {
using StringView = std::string_view;
} // namespace

7
tjp/core/string/StringView.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "StringView.h"

13
tjp/core/string/String_.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string>
namespace tjp::core {
using String = std::string;
} // namespace

View File

@@ -0,0 +1,40 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.hpp"
#include "StringView.hpp"
#include <sstream>
namespace tjp::core {
struct ToString
{
struct End_ {};
static constexpr End_ End{};
std::stringstream o;
template<typename T>
ToString &operator <<(T &&t)
{
o << t;
return *this;
}
operator String()
{
return o.str();
}
} ;
inline
String operator <<(std::stringstream &o, ToString::End_)
{
return o.str();
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
namespace tjp {
namespace core {
struct TokenVector;
struct TokenStringView;
template<typename string, typename token_type>
class Tokenizer;
} // namespace
} // namespace

View File

@@ -0,0 +1,132 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "Tokenizer.h"
#include <string>
#include <vector>
#include "str_find.h"
namespace tjp {
namespace core {
struct TokenVector
{
typedef std::vector<unsigned char> Tokens;
Tokens tokens;
TokenVector(const std::string &_del) :
tokens(255, false)
{
const unsigned char *begin = (const unsigned char *)_del.c_str();
const unsigned char *end = begin + _del.size();
for (const unsigned char *c=begin; c!=end;++c)
tokens[*c] = true;
}
size_t find(const unsigned char *s, size_t left, char &t, size_t size) const
{
return str_find(s, tokens.data(), left, t, size);
}
} ;
struct TokenStringView
{
typedef std::string_view Tokens;
Tokens tokens;
TokenStringView(const std::string_view &_del) :
tokens(_del)
{
}
size_t find(const unsigned char *s, size_t left, char &t, size_t size) const
{
return str_find(s, tokens, left, t, size);
}
} ;
template<typename string, typename token_type>
class Tokenizer
{
public:
typedef token_type Tokens;
typedef size_t index;
protected:
const unsigned char *s;
const Tokens *tokens;
index size;
index left;
index right;
char t;
public:
Tokenizer (const char *_s, index _size, const token_type &tokens_) :
s((const unsigned char *)_s),
left(0),
tokens(&tokens_),
size(_size)
{
right = tokens->find(s, left, t, size);
}
Tokenizer () :
s(nullptr),
tokens(nullptr),
left(0),
right(0),
size(0)
{
}
bool next (string &_s, char &_t)
{
index _left,_size;
bool result = next(_left, _size, _t);
if (result)
_s = string((const char *)s+_left, _size);
return result;
}
bool next (index &_left, index &_size, char &_t)
{
if (left != -1)
{
_t = t;
if (right == -1)
{
_left = left;
_size = size - left;
left = right;
}
else
{
_left = left;
_size = right-left;
left = right + 1;
if (left < size)
right = tokens->find(s, left, t, size);
else
left = -1;
}
return true;
}
return false;
}
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,41 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/Dictionary.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::string_dictionary {
namespace {
SCENARIO("core::string::string_dictionary")
{
GIVEN("a dictionary")
{
auto dictionary = strong<Dictionary>();
auto hi_cstr = "hi";
auto hi_str = std::string("hi");
auto hi_str_view = std::string_view(hi_str);
auto hi0 = dictionary->get(hi_cstr);
auto hi1 = dictionary->get(hi_str);
auto hi2 = dictionary->get(hi_str_view);
REQUIRE(hi2 == hi1);
REQUIRE(hi0 == hi1);
REQUIRE(hi0 == hi_cstr);
REQUIRE(hi0 == hi_str);
REQUIRE(hi0 == hi_str_view);
REQUIRE(hi0.entry == hi1.entry);
REQUIRE(hi1.entry == hi2.entry);
auto bye = dictionary->get("bye");
REQUIRE(hi0 != "bye");
REQUIRE(hi0 != bye);
}
}
} // namespace
} // namespace

54
tjp/core/string/_tests/Str.cpp Executable file
View File

@@ -0,0 +1,54 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/Str.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
struct AB {
Str a, b;
};
SCENARIO("core::string::str")
{
GIVEN("sizeof")
{
Str a;
sLogTest("testing", logVar(sizeof(Str)) << logVar(sizeof(Str::Internal)) << logVar(sizeof(a)) << logVar(sizeof(AB)));
}
GIVEN("a const string")
{
Str one("1");
Str one_again("1");
Str two("2");
StrN<12> small("S");
Str bigger = small;
std::string v;
for (auto i=0;i<256;++i)
v += "a";
Str longString(v);
REQUIRE(one == one);
REQUIRE(one == "1");
REQUIRE(one != "2");
REQUIRE(one != two);
REQUIRE(one == one_again);
REQUIRE(longString == longString);
REQUIRE(longString != one);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,59 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/cmp_case.hpp>
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/strncasecmp.h>
#include <tjp/core/string/String.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <cstring>
namespace tjp::core {
namespace {
int positivenegativeone(int v)
{
return v > 0 ? 1 : (v<0) ? -1 : 0;
}
SCENARIO("core::string::cmp_case")
{
GIVEN("a const string")
{
Vector<String> strings {
"one",
"two",
"onewithmore",
"three",
"thre",
""
} ;
for (auto &l: strings)
{
for (auto &r: strings)
{
auto a = positivenegativeone(strcasecmp(l.c_str(), r.c_str()));
auto b = positivenegativeone(strncasecmp(l.c_str(), l.size(), r.c_str(), r.size()));
auto c = positivenegativeone(cmp_case(l, r));
REQUIRE(a == b);
REQUIRE(b == c);
}
}
}
}
} // namespace
} // namespace

53
tjp/core/string/_tests/join.cpp Executable file
View File

@@ -0,0 +1,53 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/join.hpp>
#include <tjp/core/string/String.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
SCENARIO("core::string::join")
{
GIVEN("string")
{
String s = join_values(
',',
Vector<String>{"a", "b", "c", "d"}
);
REQUIRE(s == "a,b,c,d");
}
GIVEN("strings")
{
String s = join_values(
',',
Vector<String>{"a", "b", "c", "d"},
Vector<String>{"e", "f", "g", "h"}
);
REQUIRE(s == "a,b,c,d,e,f,g,h");
}
GIVEN("string and integers")
{
String s = join_values(
',',
Vector<String>{"a", "b", "c", "d"},
Vector<int>{0, 1, 2, 3}
);
REQUIRE(s == "a,b,c,d,0,1,2,3");
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,58 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/replace.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
SCENARIO("core::string::replace")
{
GIVEN("string")
{
String s = "abc";
WHEN("begin")
{
auto replaced = replace(s, "a", "xyz");
REQUIRE(replaced == true);
REQUIRE(s == "xyzbc");
}
WHEN("end")
{
bool replaced = replace(s, "c", "xyz");
REQUIRE(replaced == true);
REQUIRE(s == "abxyz");
}
WHEN("middle")
{
bool replaced = replace(s, "b", "xyz");
REQUIRE(replaced == true);
REQUIRE(s == "axyzc");
}
WHEN("missing")
{
bool replaced = replace(s, "d", "xyz");
REQUIRE(replaced == false);
REQUIRE(s == "abc");
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,48 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/split_once.hpp>
#include <tjp/core/string/String.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
SCENARIO("core::string::split_once")
{
GIVEN("strings")
{
Vector<Tuple<String, String, bool, String, String>> strings {
{ "asdf:1234", ":", true, "asdf", "1234" },
{ ":asdf1234", ":", true, "", "asdf1234" },
{ "asdf1234:", ":", true, "asdf1234", "" },
{ "asdf1234", ":", false, "", "" },
{ ":asdf:1234", ":", true, "", "asdf:1234" },
{ "asdf::1234", ":", true, "asdf", ":1234" },
} ;
for (auto &ss : strings)
{
auto &[s, c, has_value, l, r] = ss;
auto split = split_once(s, c);
REQUIRE(split.has_value() == has_value);
if (has_value)
{
auto &[lv, rv] = *split;
REQUIRE(lv == l);
REQUIRE(rv == r);
}
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,50 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/strncasecmp.h>
#include <tjp/core/string/String.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <cstring>
namespace tjp::core {
namespace {
int positivenegativeone(int v)
{
return v > 0 ? 1 : (v<0) ? -1 : 0;
}
SCENARIO("core::string::strncasecmp")
{
GIVEN("a const string")
{
Vector<String> strings {
"one",
"two",
"three",
""
} ;
for (auto &l: strings)
{
for (auto &r: strings)
{
auto a = positivenegativeone(strcasecmp(l.c_str(), r.c_str()));
auto b = positivenegativeone(strncasecmp(l.c_str(), l.size(), r.c_str(), r.size()));
REQUIRE(a == b);
}
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,50 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/strncmp.h>
#include <tjp/core/string/String.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <cstring>
namespace tjp::core {
namespace {
int positivenegativeone(int v)
{
return v > 0 ? 1 : (v<0) ? -1 : 0;
}
SCENARIO("core::string::strncmp")
{
GIVEN("a const string")
{
Vector<String> strings {
"one",
"two",
"three",
""
} ;
for (auto &l: strings)
{
for (auto &r: strings)
{
auto a = positivenegativeone(strcmp(l.c_str(), r.c_str()));
auto b = positivenegativeone(strncmp(l.c_str(), l.size(), r.c_str(), r.size()));
REQUIRE(a == b);
}
}
}
}
} // namespace
} // namespace

57
tjp/core/string/_tests/trim.cpp Executable file
View File

@@ -0,0 +1,57 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/trim.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace {
SCENARIO("core::string::trim")
{
GIVEN("string")
{
String s = "abc";
auto trimmed_left = trim_left_copy(s, "a");
auto trimmed_right = trim_right_copy(s, "c");
auto trimmed = trim_copy(s, "ac");
REQUIRE(trimmed_left == "bc");
REQUIRE(trimmed_right == "ab");
REQUIRE(trimmed == "b");
}
GIVEN("string view")
{
String s_ = "abc";
StringView s = s_;
auto trimmed_left = trim_left_copy(s, "a");
auto trimmed_right = trim_right_copy(s, "c");
auto trimmed = trim_copy(s, "ac");
REQUIRE(trimmed_left == "bc");
REQUIRE(trimmed_right == "ab");
REQUIRE(trimmed == "b");
}
GIVEN("string view from string on stack")
{
auto trimmed_left = trim_left_copy<StringView>(String("abc"), "a");
auto trimmed_right = trim_right_copy<StringView>(String("abc"), "c");
auto trimmed = trim_copy<StringView>(String("abc"), "ac");
REQUIRE(trimmed_left == "bc");
REQUIRE(trimmed_right == "ab");
REQUIRE(trimmed == "b");
}
}
} // namespace
} // namespace

25
tjp/core/string/as_string.hpp Executable file
View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
namespace tjp::core {
template<typename T>
String as_string(const T &s)
{
return String((char *)s.data(), s.size() * sizeof(s.front()));
}
template<>
inline
String as_string(const String &s)
{
return s;
}
} // namespace

View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
namespace tjp::core {
template<typename T>
StringView as_string_view(const T &s)
{
return StringView((char *)s.data(), s.size() * sizeof(s.front()));
}
} // namespace

37
tjp/core/string/as_vector.hpp Executable file
View File

@@ -0,0 +1,37 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
#include "../containers/Vector.h"
namespace tjp::core {
template<typename T=char, typename U>
Vector<T> as_vector(const U &s)
{
return Vector<T>((T *)s.data(), (T *)(s.data() + s.size()));
}
template<typename T=char>
Vector<T> as_vector(const String &s)
{
return Vector<T>((T *)s.data(), (T *)(s.data() + s.size()));
}
template<typename T=char>
Vector<T> as_vector(const StringView &s)
{
return Vector<T>((T *)s.data(), (T *)(s.data() + s.size()));
}
template<typename T=char>
Vector<T> as_vector(const char *s)
{
return as_vector(StringView(s));
}
} // namespace

View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "ToString.hpp"
// this is questionable
namespace std {
template<typename T>
auto operator <<(const std::string &s, T &&t)
{
return tjp::core::ToString() << s << std::forward<T>(t);
}
template<typename T>
auto operator <<(const std::string_view &s, T &&t)
{
return tjp::core::ToString() << s << std::forward<T>(t);
}
} // namespace

50
tjp/core/string/cmp.cpp Executable file
View File

@@ -0,0 +1,50 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../header_only/compile.h"
#include "cmp.hpp"
#include "strncmp.h"
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
int cmp(const String &l, const String &r)
{
return strncmp(l.c_str(), l.size(), r.c_str(), r.size());
}
TJP_CORE_HEADER_ONLY_INLINE
bool less(const String &l, const String &r)
{
return l < r;
}
TJP_CORE_HEADER_ONLY_INLINE
bool equal(const String &l, String &r)
{
return l == r;
}
TJP_CORE_HEADER_ONLY_INLINE
int cmp(const StringView &l, const StringView &r)
{
return strncmp(l.data(), l.size(), r.data(), r.size());
}
TJP_CORE_HEADER_ONLY_INLINE
bool less(const StringView &l, const StringView &r)
{
return l < r;
}
TJP_CORE_HEADER_ONLY_INLINE
bool equal(const StringView &l, const StringView &r)
{
return l == r;
}
} // namespace

20
tjp/core/string/cmp.hpp Executable file
View File

@@ -0,0 +1,20 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
namespace tjp::core {
int cmp(const String &l, const String &r);
bool less(const String &l, const String &r);
bool equal(const String &l, const String &r);
int cmp(const StringView &l, const StringView &r);
bool less(const StringView &l, const StringView &r);
bool equal(const StringView &l, const StringView &r);
} // namespace

52
tjp/core/string/cmp_case.cpp Executable file
View File

@@ -0,0 +1,52 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../header_only/compile.h"
#include "cmp_case.hpp"
#include "strncasecmp.h"
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
int cmp_case(const String &l, const String &r)
{
return strncasecmp(l.c_str(), l.size(), r.c_str(), r.size());
}
TJP_CORE_HEADER_ONLY_INLINE
bool less_case(const String &l, const String &r)
{
return cmp_case(l,r) < 0;
}
TJP_CORE_HEADER_ONLY_INLINE
bool equal_case(const String &l, const String &r)
{
return cmp_case(l,r) == 0;
}
TJP_CORE_HEADER_ONLY_INLINE
int cmp_case(const StringView &l, const StringView &r)
{
return strncasecmp(l.data(), l.size(), r.data(), r.size());
}
TJP_CORE_HEADER_ONLY_INLINE
bool less_case(const StringView &l, const StringView &r)
{
return cmp_case(l, r) < 0;
}
TJP_CORE_HEADER_ONLY_INLINE
bool equal_case(const StringView &l, const StringView &r)
{
return cmp_case(l,r) == 0;
}
} // namespace

25
tjp/core/string/cmp_case.hpp Executable file
View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
namespace tjp::core {
int cmp_case(const String &l, const String &r);
int cmp_case(const StringView &l, const StringView &r);
bool less_case(const String &l, const String &r);
bool less_case(const StringView &l, const StringView &r);
bool equal_case(const String &l, const String &r);
bool equal_case(const StringView &l, const StringView &r);
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "cmp_case.cpp"
#endif

7
tjp/core/string/ends_with.hpp Executable file
View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../algorithm/ends_with.hpp"

26
tjp/core/string/find_after.hpp Executable file
View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Optional.hpp"
#include "StringView.hpp"
namespace tjp::core::string {
inline
Optional<StringView::pos> find_after(const StringView &s, const StringView &find, StringView::pos pos=0)
{
if (pos + find.size() > s.size())
return {};
auto f = s.find(find, pos);
if (f == s.npos)
return {};
return f + find.size();
}
} // namespace

23
tjp/core/string/find_if.hpp Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Optional.hpp"
#include "StringView.hpp"
namespace tjp::core::string {
inline
Optional<size_t> find_if(const StringView &s, const StringView &find, size_t pos=0)
{
auto f = s.find(find, pos);
if (f == s.npos)
return {};
return f;
}
} // namespace

69
tjp/core/string/from_string.cpp Executable file
View File

@@ -0,0 +1,69 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../header_only/compile.h"
#include "from_string.hpp"
#include <string>
#include <algorithm>
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
void from_string(std::string_view &v, const std::string_view &s)
{
v = s;
}
TJP_CORE_HEADER_ONLY_INLINE
void from_string(std::string &v, const std::string_view &s)
{
v = s;
}
TJP_CORE_HEADER_ONLY_INLINE
void from_string(bool &v, const std::string_view &s)
{
v = (s == "true");
}
TJP_CORE_HEADER_ONLY_INLINE
int naive_atoi(const std::string_view &s)
{
// Taken from http://tinodidriksen.com/uploads/code/cpp/speed-string-to-int.cpp
int x = 0;
bool neg = false;
auto *p = s.data();
auto *e = p + s.size();
if (p < e && *p == '-') {
neg = true;
++p;
}
while (p < e && *p >= '0' && *p <= '9') {
x = (x*10) + (*p - '0');
++p;
}
if (neg) {
x = -x;
}
return x;
}
TJP_CORE_HEADER_ONLY_INLINE
void from_string(int &v, const std::string_view &s)
{
v = naive_atoi(s);
}
} // namespace

25
tjp/core/string/from_string.h Executable file
View File

@@ -0,0 +1,25 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string>
namespace tjp::core {
template<typename T>
void from_string(T &t, const std::string_view &s);
template<typename T>
T from_string(const std::string_view &s);
template<typename T>
T from_string(const std::string_view &s, const T &defaultValue);
void from_string(std::string_view &v, const std::string_view &s);
void from_string(std::string &, const std::string_view &s);
void from_string(bool &v, const std::string_view &s);
void from_string(int &v, const std::string_view &s);
} // namespace

14
tjp/core/string/from_string.hpp Executable file
View File

@@ -0,0 +1,14 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../header_only/compile.h"
#include "from_string.h"
#include "from_string.inl"
#ifdef TJP_CORE_HEADER_ONLY
#include "from_string.cpp"
#endif

44
tjp/core/string/from_string.inl Executable file
View File

@@ -0,0 +1,44 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "from_string.h"
#include "../io/memstream.hpp"
namespace tjp::core {
template<typename T>
void from_string(T &t, const std::string_view &s)
{
io::imemstream in(s.data(), s.size());
in >> t;
}
template<typename T>
T from_string(const std::string_view &s, const T &defaultValue)
{
T t = defaultValue;
from_string(t, s);
return t;
}
template<typename T>
T from_string(const std::string_view &s)
{
T t;
from_string(t, s);
return t;
}
template<typename T, typename U>
T from_string_using(const U &s)
{
T t;
io::imemstream in(s.data(), s.size());
in >> t;
return t;
}
} // namespace

17
tjp/core/string/has.hpp Executable file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../algorithm/has_sequence.hpp"
#include "StringView.hpp"
namespace tjp::core {
bool has(const StringView &lhs, const StringView &rhs)
{
return has_sequence(lhs, rhs);
}
} // namespace

17
tjp/core/string/has_prefix.hpp Executable file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "starts_with.hpp"
namespace tjp::core {
inline
bool has_prefix(const std::string_view &s, const std::string_view &prefix)
{
return starts_with(s, prefix);
}
} // namespace

72
tjp/core/string/join.hpp Executable file
View File

@@ -0,0 +1,72 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../iterators/is_first.hpp"
#include "to_string.hpp"
#include <string>
namespace tjp::core {
template <typename V, typename T>
void join_(std::string &result, is_first &first, const V &delimiter, const T & sv)
{
for (auto &s : sv)
{
if (!first.check())
result += delimiter;
result.insert(result.end(), s.begin(), s.end());
}
}
template <typename V, typename U, typename T>
void join_(std::string &result, is_first &first, const V &delimiter, const U &u, const T & sv)
{
for (auto &s_ : sv)
{
auto s = u(s_);
if (!first.check())
result += delimiter;
result.insert(result.end(), s.begin(), s.end());
}
}
template <typename V, typename ... T>
std::string join(const V &delimiter, T&& ... t)
{
std::string result;
is_first first;
((join_(result, first, delimiter, t)),...) ;
return result;
}
template <typename V, typename ... T>
std::string join_values(const V &delimiter, T&& ... t)
{
std::string result;
is_first first;
auto u = [](auto &v) { return to_string(v); };
((join_(result, first, delimiter, u, t)),...) ;
return result;
}
template <typename V, typename U, typename ... T>
std::string join_with(const V &delimiter, U &&u, T&& ... t)
{
std::string result;
is_first first;
((join_(result, first, delimiter, u, t)),...) ;
return result;
}
} // namespace

37
tjp/core/string/replace.cpp Executable file
View File

@@ -0,0 +1,37 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#if defined(TJP_CORE_HEADER_ONLY)
#pragma once
#endif
#include "../header_only/compile.h"
#include "replace.h"
#include <string>
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
bool replace(String& str, const StringView& from, const StringView& to)
{
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
TJP_CORE_HEADER_ONLY_INLINE
void replaceAll(String& str, const StringView& from, const StringView& to)
{
if(from.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
} // namespace

19
tjp/core/string/replace.h Executable file
View File

@@ -0,0 +1,19 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.hpp"
#include "StringView.hpp"
namespace tjp::core {
bool replace(String & str, const StringView& from, const StringView& to);
void replaceAll(String& str, const StringView& from, const StringView& to);
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "replace.cpp"
#endif

23
tjp/core/string/replaced.cpp Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "replace.h"
#include "replaced.h"
#include <string>
namespace tjp::core {
String replacedFirst(const StringView & str, const StringView& from, const StringView& to) {
auto s = String(str);
replace(s, from, to);
return s;
}
String replaced(const StringView & str, const StringView& from, const StringView& to) {
auto s = String(str);
replaceAll(s, from, to);
return s;
}
} // namespace

15
tjp/core/string/replaced.h Executable file
View File

@@ -0,0 +1,15 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.hpp"
#include "StringView.hpp"
namespace tjp::core {
String replaceFirst(const StringView & str, const StringView& from, const StringView& to);
String replaced(const StringView & str, const StringView& from, const StringView& to);
} // namespace

16
tjp/core/string/split.hpp Executable file
View File

@@ -0,0 +1,16 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <vector>
namespace tjp::core {
template <typename T>
std::vector<T> split(const T &s, const T &delimiter);
} // namespace
#include "split.inl"

49
tjp/core/string/split.inl Executable file
View File

@@ -0,0 +1,49 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
namespace tjp::core {
template <typename T>
std::vector<T> split(const T &s, const T &delimiter)
{
std::vector<T> result;
size_t last = 0; size_t next = 0;
while ((next = s.find(delimiter, last)) != T::npos)
{
if (last < next)
result.push_back(s.substr(last, next-last));
last = next + std::max(delimiter.size(), (size_t)1);
}
if (last < s.size())
result.push_back(s.substr(last));
return result;
}
template <typename T>
std::vector<T> split(const T &s, char delimiter)
{
std::vector<T> result;
size_t last = 0; size_t next = 0;
while ((next = s.find(delimiter, last)) != T::npos)
{
if (last < next)
result.push_back(s.substr(last, next-last));
last = next + 1;
}
if (last < s.size())
result.push_back(s.substr(last));
return result;
}
} // namespace

26
tjp/core/string/split_once.hpp Executable file
View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Tuple.hpp"
#include "../containers/Optional.hpp"
#include "StringView.hpp"
namespace tjp::core {
template <typename T>
Optional<Tuple<T, T>> split_once(const T &s, const StringView &delimiter)
{
auto v = s.find(delimiter);
if (v == s.npos)
return {};
return Tuple<T, T> {
s.substr(0, v),
s.substr(v+delimiter.size())
};
}
} // namespace

View File

@@ -0,0 +1,7 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../algorithm/starts_with.hpp"

62
tjp/core/string/str_find.cpp Executable file
View File

@@ -0,0 +1,62 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "str_find.h"
#include <cstring>
namespace tjp::core {
size_t str_find(const char *s, char del, size_t offset)
{
const char *result = strchr(s+offset, del);
if (result == NULL)
return -1;
return (size_t)(result - s);
}
size_t str_find(const unsigned char *s, const unsigned char *tokens, size_t offset, char &t, size_t size)
{
t = 0;
bool found = false;
const unsigned char *r = (const unsigned char *)s+offset;
const unsigned char *e = s + size;
for (;r < e && *r!=0; r++)
{
if (*(tokens + *r))
{
t = *r;
found = true;
break;
}
}
if (!found)
return -1;
return (int)(r - s);
}
size_t str_find(const unsigned char *s, const std::string_view &tokens, size_t offset, char &t, size_t size)
{
t = 0;
const unsigned char *r = (const unsigned char *)s+offset;
const unsigned char *e = s + size;
for (;r < e && *r!=0; r++)
{
for (auto &t_ : tokens)
{
if (t_ == *r)
{
t = t_;
return (int)(r - s);
}
}
}
return -1;
}
} // namespace

16
tjp/core/string/str_find.h Executable file
View File

@@ -0,0 +1,16 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string>
namespace tjp::core {
size_t str_find(const char *s, char del, size_t offset=0);
size_t str_find(const unsigned char *s, const unsigned char *tokens, size_t offset, char &t, size_t size);
size_t str_find(const unsigned char *s, const std::string_view &tokens, size_t offset, char &t, size_t size);
} // namespace

32
tjp/core/string/strncasecmp.cpp Executable file
View File

@@ -0,0 +1,32 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "../header_only/compile.h"
#include "strncasecmp.h"
#include <strings.h>
#include <algorithm>
namespace tjp::core {
TJP_CORE_HEADER_ONLY_INLINE
int strncasecmp(const char *l, size_t ls, const char *r, size_t rs)
{
auto v = ::strncasecmp(l, r, std::min(ls, rs));
if (v != 0)
return v;
if (ls > rs)
return 1;
if (ls < rs)
return -1;
return 0;
}
} // namespace

17
tjp/core/string/strncasecmp.h Executable file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <stdlib.h>
namespace tjp::core {
int strncasecmp(const char *l, size_t ls, const char *r, size_t rs);
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "strncasecmp.cpp"
#endif

28
tjp/core/string/strncmp.cpp Executable file
View File

@@ -0,0 +1,28 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include "strncmp.h"
#include <strings.h>
#include <algorithm>
#include <cstring>
namespace tjp::core {
int strncmp(const char *l, size_t ls, const char *r, size_t rs)
{
auto v = ::strncmp(l, r, std::min(ls, rs));
if (v != 0)
return v;
if (ls > rs)
return 1;
if (ls < rs)
return -1;
return 0;
}
} // namespace

13
tjp/core/string/strncmp.h Executable file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <stdlib.h>
namespace tjp::core {
int strncmp(const char *l, size_t ls, const char *r, size_t rs);
} // namespace

21
tjp/core/string/sxprintf.h Executable file
View File

@@ -0,0 +1,21 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <cstdio>
#include <type_traits>
namespace tjp::core {
template<typename T, typename ... Args>
void sxprintf(T &t, const char *format, Args &&... args)
{
static_assert(std::is_array<T>::value, "T must be an array");
static_assert(std::is_same<typename std::remove_all_extents<T>::type, char>::value, "T must be an array of char");
snprintf(t, std::size(t), format, std::forward<Args>(args)...);
}
} // namespace

27
tjp/core/string/to_lower.hpp Executable file
View File

@@ -0,0 +1,27 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.h"
#include "StringView.h"
#include <cctype>
namespace tjp::core {
inline
String to_lower(const StringView &s_)
{
String s(s_);
std::transform(
s.begin(), s.end(), s.begin(),
[](unsigned char c){ return std::tolower(c); }
);
return s;
}
} // namespace

23
tjp/core/string/to_string.h Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string>
namespace std {
inline
std::string to_string(const std::string_view &s);
}
namespace tjp {
namespace core {
template<typename T>
std::string to_string(const T &t);
} // namespace
} // namespace

40
tjp/core/string/to_string.hpp Executable file
View File

@@ -0,0 +1,40 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "to_string.h"
#include <string>
#include <sstream>
namespace std {
inline
std::string to_string(const std::string_view &s)
{
return std::string(s.data(), s.size());
}
} // namespace
namespace tjp {
namespace core {
template<typename T>
std::string to_string(const T &t)
{
std::ostringstream s;
s << t;
return s.str();
}
inline
std::string to_string(const std::string_view &s)
{
return std::to_string(s);
}
} // namespace
} // namespace

32
tjp/core/string/trim.h Executable file
View File

@@ -0,0 +1,32 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "String.hpp"
#include "StringView.hpp"
namespace tjp::core {
template<typename T>
T trim_right_copy(
const T &s,
const StringView &delimiters = " \f\n\r\t\v"
);
template<typename T>
T trim_left_copy(
const T &s,
const StringView &delimiters = " \f\n\r\t\v"
);
template<typename T>
T trim_copy(
const T &s,
const StringView & delimiters = " \f\n\r\t\v"
);
} // namespace
#include "trim.inl"

49
tjp/core/string/trim.inl Executable file
View File

@@ -0,0 +1,49 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "trim.h"
namespace tjp::core {
template<typename T>
T trim_right_copy(
const T &s,
const StringView &delimiters)
{
if (s.empty())
return {};
return s.substr( 0, s.find_last_not_of( delimiters ) + 1 );
}
template<typename T>
T trim_left_copy(
const T &s,
const StringView &delimiters)
{
if (s.empty())
return {};
return s.substr( s.find_first_not_of( delimiters ) );
}
template<typename T>
T trim_copy(
const T &s,
const StringView &delimiters)
{
if (s.empty())
return {};
return
trim_left_copy(
trim_right_copy(s, delimiters),
delimiters
);
}
} // namespace

21
tjp/core/string/unprefix.hpp Executable file
View File

@@ -0,0 +1,21 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../containers/Optional.hpp"
#include "starts_with.hpp"
namespace tjp::core {
inline
Optional<std::string_view> unprefix(const std::string_view &s, const std::string_view &prefix)
{
if (starts_with(s, prefix))
return s.substr(prefix.size());
return {};
}
} // namespace