Last active
September 10, 2018 07:38
-
-
Save Justasic/e3094683aeab2325b955aabd58068d99 to your computer and use it in GitHub Desktop.
kstring -- The C++ string class with extra features std::string does not include
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************* | |
* BSD 2-Clause License | |
* | |
* Copyright (c) 2017-2018, Justin Crawford | |
* Copyright (c) 2017, William Haugen | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* * Redistributions of source code must retain the above copyright notice, this | |
* list of conditions and the following disclaimer. | |
* | |
* * Redistributions in binary form must reproduce the above copyright notice, | |
* this list of conditions and the following disclaimer in the documentation | |
* and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
// William Haugen | |
// | |
// The purpose of this class, kstring, is to overload the standard | |
// cstring library's operators to preform deep copies and have | |
// it act like it is part of the standard library. | |
// Allow for custom allocators - Justasic | |
#ifndef CUSTOM_REALLOC | |
# define CUSTOM_REALLOC realloc | |
#endif | |
#ifndef CUSTOM_FREE | |
# define CUSTOM_FREE free | |
#endif | |
// Allow different include locations in case the include | |
// is elsewhere in the system instead of these default spots. | |
#ifdef USE_LIBFMT | |
# ifdef CUSTOM_LIBFMT_INCLUDE | |
# include CUSTOM_LIBFMT_INCLUDE | |
# else | |
# include <fmt/fmt.h> | |
# endif | |
#endif | |
// CAUTION: Do not move this line above the libfmt line. spdlog uses a different location. | |
#ifdef USE_SPDLOG | |
# ifdef CUSTOM_SPDLOG_INCLUDE | |
# include CUSTOM_SPDLOG_INCLUDE | |
# else | |
# include <spdlog/fmt/fmt.h> | |
# endif | |
# define USE_LIBFMT 1 | |
#endif | |
#include <cctype> | |
#include <cstring> | |
#include <iostream> | |
#include <map> | |
#include <strings.h> | |
#include <vector> | |
// TO DO: | |
// Length to spit out len | |
// Change char at a given index | |
class kstring | |
{ | |
public: | |
// Define npos. | |
static const size_t npos = -1; | |
// Standard constructors | |
kstring() { this->ResizeString(1); } | |
kstring(const kstring &other) { memcpy(this->ResizeString(other.str->allocatedsz), other.str, other.str->allocatedsz); } | |
kstring(const char *cstr, size_t len) { memcpy(this->ResizeString(len)->str, cstr, len); } | |
kstring(const char *cstr) { size_t tmplen = strlen(cstr); memcpy(this->ResizeString(tmplen)->str, cstr, tmplen); } | |
kstring(const char ch) { this->ResizeString(2); this->str->str[0] = ch; this->str->str[1] = '\0'; } | |
kstring(const std::string &str) { memcpy(this->ResizeString(str.capacity())->str, str.c_str(), str.size()); } | |
// Strange constructors | |
template <typename... Args> | |
kstring(const std::string &str, const Args&&... args) | |
{ | |
#ifdef USE_LIBFMT | |
*this = fmt::format(str, args...); | |
#endif | |
} | |
// Numerical conversions | |
explicit kstring(int i) { *this = std::to_string(i); } | |
explicit kstring(long int i) { *this = std::to_string(i); } | |
explicit kstring(long long int i) { *this = std::to_string(i); } | |
explicit kstring(unsigned int i) { *this = std::to_string(i); } | |
explicit kstring(unsigned long int i) { *this = std::to_string(i); } | |
explicit kstring(unsigned long long int i) { *this = std::to_string(i); } | |
explicit kstring(float i) { *this = std::to_string(i); } | |
explicit kstring(double i) { *this = std::to_string(i); } | |
explicit kstring(long double i) { *this = std::to_string(i); } | |
// Destructor | |
~kstring() | |
{ | |
this->FreeString(); | |
} | |
inline kstring &insert(size_t index, size_t count, char ch) {} | |
inline kstring &insert(size_t index, const char *s) {} | |
inline kstring &insert(size_t index, const char *s, size_t count) {} | |
inline kstring &insert(size_t index, const kstring &s) {} | |
inline kstring &insert(size_t index, const kstring &s, size_t index_str, size_t count = npos) {} | |
inline kstring &insert(size_t index, const std::string &s) {} | |
inline kstring &insert(size_t index, const std::string &s, size_t index_str, size_t count = npos) {} | |
inline kstring &erase(size_t index = 0, size_t count = kstring::npos) {} | |
inline void push_back(char ch) {} | |
inline void pop_back() { this->erase(this->size() - 1, 1); } | |
// TODO: all append() functions. | |
inline kstring &append(size_t count, char ch) {} | |
inline kstring &append(const kstring &str) {} | |
inline kstring &append(const kstring &str, size_t pos, size_t count = npos) {} | |
inline kstring &append(const char *s, size_t count) {} | |
inline kstring &append(const char *s) {} | |
inline kstring &append(const std::string &str) {} | |
inline kstring &append(const std::string &str, size_t pos, size_t count = npos) {} | |
// TODO: all compare() functions. | |
inline int compare(const kstring &str) const {} | |
inline int compare(size_t pos1, size_t count1, const kstring &str) const {} | |
inline int compare(size_t pos1, size_t count1, const kstring &str, size_t pos2, size_t count2 = npos) const {} | |
inline int compare(const std::string &str) const {} | |
inline int compare(size_t pos1, size_t count1, const std::string &str) const {} | |
inline int compare(size_t pos1, size_t count1, const std::string &str, size_t pos2, size_t count2 = npos) const {} | |
inline int compare(const char *s) const {} | |
inline int compare(size_t pos1, size_t count1, const char *s) const {} | |
inline int compare(size_t pos1, size_t count1, const char *s, size_t count2) const {} | |
inline bool starts_with(kstring x) const noexcept {} | |
inline bool starts_with(char x) const noexcept {} | |
inline bool starts_with(const char *x) const {} | |
inline bool ends_with(kstring x) const noexcept {} | |
inline bool ends_with(char x) const noexcept {} | |
inline bool ends_with(const char *x) const {} | |
// TODO: all replace() functions. | |
inline kstring &replace(size_t pos, size_t count, const kstring &str) {} | |
inline kstring &replace(size_t pos, size_t count, const kstring &str, size_t pos2, size_t count2 = npos) {} | |
inline kstring &replace(size_t pos, size_t count, const std::string &str) {} | |
inline kstring &replace(size_t pos, size_t count, const std::string &str, size_t pos2, size_t count2 = npos) {} | |
inline kstring &replace(size_t pos, size_t count, const char *str, size_t count2) {} | |
inline kstring &replace(size_t pos, size_t count, const char *cstr) {} | |
inline kstring &replace(size_t pos, size_t count, size_t count2, char ch) {} | |
kstring substr(size_t = 0, size_t = npos) const; | |
inline void resize(size_t count) {} | |
inline void resize(size_t count, char ch) {} | |
inline void swap(kstring &other) {} | |
size_t copy(char *dest, size_t count, size_t pos = 0) const; | |
// a timing-safe compaison of strings (used for passwords) | |
inline bool securecmp(const kstring &); | |
// Vector functions (useful for tokenization) | |
std::vector<kstring> expand(const kstring &delim) const; | |
kstring contract(const std::vector<kstring> &_vec, const kstring &delim); | |
// Make use of tinyformat here. | |
template<typename... Args> | |
kstring fmt(const Args &... args) | |
{ | |
#ifdef USE_LIBFMT | |
return fmt::format(this->c_str(), args...); | |
#endif | |
} | |
// Search functions | |
size_t find(const kstring &, size_t = 0) const; | |
inline size_t find(const char *s, size_t pos, size_t count) const {} | |
inline size_t find(const char *s, size_t pos = 0) const {} | |
inline size_t find(char ch, size_t pos = 0) const {} | |
// Reverse find | |
inline size_t rfind(const kstring &, size_t = 0) const {} | |
inline size_t rfind(const char *s, size_t pos, size_t count) const {} | |
inline size_t rfind(const char *s, size_t pos = 0) const {} | |
inline size_t rfind(char ch, size_t pos = 0) const {} | |
inline size_t find_first_of(const kstring &str, size_t pos = 0) const {} | |
inline size_t find_first_of(const char *s, size_t pos, size_t count) const {} | |
inline size_t find_first_of(const char *s, size_t pos = 0) const {} | |
inline size_t find_first_of(char ch, size_t pos = 0) const {} | |
inline size_t find_first_not_of(const kstring &str, size_t pos = 0) const {} | |
inline size_t find_first_not_of(const char *s, size_t pos, size_t count) const {} | |
inline size_t find_first_not_of(const char *s, size_t pos = 0) const {} | |
inline size_t find_first_not_of(char ch, size_t pos = 0) const {} | |
inline size_t find_last_of(const kstring &str, size_t pos = 0) const {} | |
inline size_t find_last_of(const char *s, size_t pos, size_t count) const {} | |
inline size_t find_last_of(const char *s, size_t pos = 0) const {} | |
inline size_t find_last_of(char ch, size_t pos = 0) const {} | |
inline size_t find_last_not_of(const kstring &str, size_t pos = 0) const {} | |
inline size_t find_last_not_of(const char *s, size_t pos, size_t count) const {} | |
inline size_t find_last_not_of(const char *s, size_t pos = 0) const {} | |
inline size_t find_last_not_of(char ch, size_t pos = 0) const {} | |
// Assignment Operators | |
kstring &operator=(const kstring &other) { memcpy(this->ResizeString(other.str->allocatedsz), other.str, other.str->allocatedsz); } | |
kstring &operator=(const std::string &other) { memcpy(this->ResizeString(other.capacity())->str, other.c_str(), other.size()); } | |
kstring &operator=(const char *other) { size_t tmplen = strlen(other); memcpy(this->ResizeString(tmplen)->str, other, tmplen); } | |
kstring &operator=(const char ch) { this->ResizeString(2); this->str->str[0] = ch; this->str->str[1] = 0; } | |
inline kstring &operator+=(const kstring &str) {} | |
inline kstring &operator+=(const std::string &str) {} | |
inline kstring &operator+=(char ch) {} | |
inline kstring &operator+=(const char *s) {} | |
inline kstring &operator+=(std::initializer_list<char> ilist) {} | |
template<class T> | |
inline kstring &operator+=(const T &t) | |
{} | |
// Able to use std::ostream and std::istream natively | |
friend std::ostream &operator<<(std::ostream &, const kstring &); | |
friend std::istream &operator>>(std::istream &, kstring &); | |
// Ability to add onto strings, just uses std::strcat | |
friend kstring operator+(const kstring &, char *); | |
friend kstring operator+(char *, const kstring &); | |
friend kstring operator+(const kstring &, const char *); | |
friend kstring operator+(const char *, const kstring &); | |
friend kstring operator+(const kstring &, const kstring &); | |
// Using strcmp to determine all the relations. | |
friend bool operator<(const kstring &, char *); | |
friend bool operator<(char *, const kstring &); | |
friend bool operator<(const kstring &, const kstring &); | |
friend bool operator<=(const kstring &, char *); | |
friend bool operator<=(char *, const kstring &); | |
friend bool operator<=(const kstring &, const kstring &); | |
friend bool operator>(const kstring &, char *); | |
friend bool operator>(char *, const kstring &); | |
friend bool operator>(const kstring &, const kstring &); | |
friend bool operator>=(const kstring &, char *); | |
friend bool operator>=(char *, const kstring &); | |
friend bool operator>=(const kstring &, const kstring &); | |
friend bool operator!=(const kstring &, char *); | |
friend bool operator!=(char *, const kstring &); | |
friend bool operator!=(const kstring &, const kstring &); | |
friend bool operator==(const kstring &, char *); | |
friend bool operator==(char *, const kstring &); | |
friend bool operator==(const kstring &, const kstring &); | |
// READ ONLY for the subscript | |
char & operator[](int i); | |
const char &operator[](int i) const; | |
// Getters/Setters/Others | |
inline size_t size() const { return this->isnull() ? 0 : this->str->length; } | |
inline size_t length() const { this->size(); } | |
inline const char *c_str() const { return this->isnull() ? nullptr : this->str->str; } | |
inline bool isnull() const { return !this->str; } | |
inline bool empty() const { return this->isnull() ? true : !this->str->length; } | |
inline char * data() { this->isnull() ? return nullptr : return this->str->str; } | |
inline char & front() { return this->str->str[0]; } | |
inline const char & front() const { return this->front(); } | |
inline char & back() { return this->str->str[this->str->length - 1]; } | |
inline const char & back() const { return this->back(); } | |
inline void reserve(size_t sz) { this->ResizeString(sz); } | |
inline size_t capacity() const { return this->str->allocatedsz; } | |
inline void shrink_to_fit() { this->ResizeString(str->length); } | |
inline void clear() | |
{ | |
if (this->str) | |
{ | |
bzero(this->str->str, this->str->length); | |
this->str->length = 0; | |
} | |
} | |
// Casting operators | |
inline explicit operator int() { return this->isnull() ? 0 : static_cast<int>(strtol(this->str->str, nullptr, 10)); } | |
inline explicit operator long int() { return this->isnull() ? 0 : strtol(this->str->str, nullptr, 10); } | |
inline explicit operator long long int() { return this->isnull() ? 0 : strtoll(this->str->str, nullptr, 10); } | |
// C/C++ does not have a strtou function cuz apparently being consistent isn't top | |
// priority for ISOCPP group. So we have to do a truncating cast from unsigned long. | |
inline explicit operator unsigned int() { return this->isnull() ? 0 : static_cast<unsigned int>(strtoul(this->str->str, nullptr, 10)); } | |
inline explicit operator unsigned long int() { return this->isnull() ? 0 : strtoul(this->str->str, nullptr, 10); } | |
inline explicit operator unsigned long long int() { return this->isnull() ? 0 : strtoull(this->str->str, nullptr, 10); } | |
inline explicit operator float() { return this->isnull() ? 0.0 : strtof(this->str->str, nullptr); } | |
inline explicit operator double() { return this->isnull() ? 0.0 : strtod(this->str->str, nullptr); } | |
inline explicit operator long double() { return this->isnull() ? 0.0 : strtold(this->str->str, nullptr); } | |
private: | |
// This structure should never be exposed to the user! | |
typedef struct string_s | |
{ | |
// We reference count to dynamically expand the buffer, this is | |
// also why we require an internal object. | |
size_t refs; // Used for reference counting | |
size_t allocatedsz; // Used to get allocated size | |
size_t length; // Length of the string | |
// Okay, this takes some explaining. I got this trick from | |
// https://stackoverflow.com/a/599441 | |
// and basically what is going on is we allocate this struct | |
// for the size of the string plus the size of the struct. | |
// This will allow us to keep all the data related to the actual | |
// bytes of the string tied together so it isn't lost, even if | |
// we return somestringobj->str; as a pointer to the user. | |
// The user can use pointer arithmatic to get the length or size | |
// without having an out of bounds deference. | |
char str[1]; // String itself. | |
} _string_t; | |
// I use realloc here to change the size of the pointer | |
// if the pointer is null then it will act as a malloc call | |
// if the requested size is greater than the current size, it will allocate more | |
// space and keep the data | |
// if the requested space is smaller than the allocated space, it will shrink and truncate. | |
_string_t *ResizeString(size_t len) | |
{ | |
void *ptr = CUSTOM_REALLOC(this->str, len); | |
if (!ptr) | |
throw std::bad_alloc(); | |
this->str = reinterpret_cast<_string_t *>(ptr); | |
this->str->allocatedsz = len; | |
return this->str; | |
} | |
void FreeString() | |
{ | |
CUSTOM_FREE(this->str); | |
this->str = nullptr; | |
} | |
_string_t *str; | |
}; | |
// Useful :p | |
typedef std::vector<kstring> kvector; | |
// user-defined literal | |
inline kstring operator"" _k(const char *str, size_t len) { return kstring(str, len); } | |
// A case-insensitive map | |
struct insensitive | |
{ | |
inline bool operator()(const kstring &a, const kstring &b) const { return !strcasecmp(a.c_str(), b.c_str()); } | |
}; | |
template<typename T> | |
class kmap : public std::map<kstring, T, insensitive> | |
{}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment