I am trying to create a string class without std::string
. Just for educational purpose.
So I created some utility functions, and it would be very nice if you guys could take a look at the code for mistakes.
Does anyone see any errors? (probably)
// Includes.
#include <iostream> // for "print()" and "std".
#include <sstream> // for "tostr()".
// Print.
template <typename Arg, typename... Args>
void print(Arg&& arg, Args&&... args) {
std::cout << std::forward<Arg>(arg);
((std::cout << ' ' << std::forward<Args>(args)), ...);
std::cout << std::endl;
}
// Allocate a new array.
template <class T>
T * alloc(
// The new size of the array.
size_t n
) {
T *a;
a = (T *) malloc((n + 1) * sizeof(T));
return a;
}
// Delete.
template <class T>
void del(T *x) {
delete[] x;
x = NULL;
}
// Length.
size_t len(const char* x) {
return ::strlen(x);
}
size_t len(char x) {
if (std::isblank(x)) { return 0; }
return 1;
}
// Cast const char* to char *.
char* strcast(const char* x, size_t n = -1) {
char *s;
if (n == -1) { n = len(x); }
s = alloc<char>(n); // real alloc size afterwards is n + 1
if (n == 0) {
s[0] = '\0';
return s;
}
return strcat(strcpy(s, x), "");
}
// String is null.
// Will cause segmentation fault if x is unallocated [const char x;], when x is [const char *x = ""] it will run.
bool strnull(const char* x) {
return (x == NULL || ! *x);
}
// Safely dump a string.
// Not necessary.
// Will cause segmentation fault if x is [const char x;], when x is [const char *x = ""] it will run.
// const char* strdump(const char* x) {
// return x;
// }
// char* strdump(char* x) {
// return x;
// }
// String equals.
// Will again cause segfault if x / y is unallocated [const char x;].
bool streq(const char* x, const char* y) {
return strcmp(x, y) == 0;
}
// Char equals.
// Does not cause segfault if a / b is unallocated [char x].
bool chareq(char a, char b) {
if (std::isspace(a) and std::isspace(b)) { return true; }
return not (a < b) and not (a > b) and a == b;
}
// String from double.
template <class T>
char* tostr(T x) {
std::stringstream ss;
ss << x;
char *y;
y = ss.str().data();
return y;
}
// From string to double.
// Will cause segmentation fault if x is unallocated [const char x;], when x is [const char *x = ""] it will run.
float fromstr(const char* x) {
if (strnull(x)) { return 0; }
return std::atof(x);
}
// Concatenate multiple char*.
// Will cause segmentation fault if x / y is unallocated [const char x;], when x / y is [const char *x = ""] it will run.
char *strconcat(char *x, const char*y) {
size_t xn = strlen(x);
size_t yn = strlen(y);
char *z = alloc<char>(xn + yn);
memcpy(z, x, xn);
memcpy(z + xn, y, yn);
return z;
}
const char *strconcat(const char *x, const char *y) {
size_t xn = strlen(x);
size_t yn = strlen(y);
char *z = alloc<char>(xn + yn);
memcpy(z, x, xn);
memcpy(z + xn, y, yn);
return z;
}
char *strconcat(char *x) { return x; }
const char *strconcat(const char *x) { return x; }
template <class... Args> char *strconcat(char *x, const char *y, Args&&... args) { return strconcat(strconcat(x, y), args...); }
template <class... Args> const char *strconcat(const char *x, const char *y, Args&&... args) { return strconcat(strconcat(x, y), args...); }
// Find substring in str.
// Will cause segmentation fault if str / substr is unallocated [const char x;], when str / substr is [const char *x = ""] it will run.
// class npos {
// public:
// size_t m_pos;
// bool found = false;
// npos() {};
// npos(size_t pos) { m_pos = pos; found = true; }
// npos(int pos) { if (pos > 0) { m_pos = pos; found = true; } }
// operator size_t() { return m_pos; }
// };
class nposclass {
public:
size_t m_pos;
nposclass() {}
operator size_t() { return m_pos; }
};
nposclass npos = nposclass();
size_t strfind(char* str, const char* substr) {
char *dest = strstr(str, substr);
if (dest == NULL) { return npos; };
return dest - str;
}
size_t strfind(char* str, const char* substr, size_t start) {
size_t i = strfind(str + start, substr);
if (i != -1) { return start + i; }
return i;
}
// Replace a substring in a string.
// Will cause segmentation fault if str / from / to is unallocated [const char x;], when str / from / to is [const char *x = ""] it will run.
char* strreplace(char* str, const char* from, const char* to, double increaser = 2.0) {
if (strnull(from)) { return str; }
size_t nt = strlen(to); // to size.
size_t nf = strlen(from); // from size.
size_t n = strlen(str); // str size.
size_t mn = n; // max alloc size.
char *result = alloc<char>(mn);
size_t nn = 0; // new size.
while (*str) {
// Found from.
if (strstr(str, from) == str) {
// Check resize.
if (nn + nt > mn) {
mn = (nn + nt) * increaser;
char *a = alloc<char>(mn);
memcpy(a, result, nn);
delete[] result; result = NULL;
result = a;
}
// Add to.
memcpy(&result[nn], to, nt);
nn += nt;
str += nf;
}
// Add current char.
else { result[nn++] = *str++; }
}
result[nn] = '\0';
return result;
}
// Testing.
// Test code produces the warnings "ISO C++11 does not allow conversion from string literal to 'char *'", but that will be fixed by creating a string object.
int main() {
// strcast.
const char* x = "Hello";
char *y = strcast(x);
print("strcast:",y);
// strnull.
const char* x0 = "s ";
const char* x1 = "";
print("len: 2 ==>",strnull(x0));
print("len: 0 ==>", strnull(x1));
// len.
print("strnull: 0 ==>",strnull(x0));
print("strnull: 1 ==>", strnull(x1));
// streq.
print("streq: 0 ==>",streq(x0, x1));
print("streq: 1 ==>", streq(x1, x1));
// chareq.
char c;
print("chareq: 0 ==>", chareq('a', 'b'));
print("chareq: 1 ==>",chareq('a', 'a'));
print("chareq: 0 ==>",chareq('a', c));
// tostr.
char * y0 = tostr<double>(1.1);
print("tostr: 1.1 ==>", y0);
// fromstr.
double d0 = fromstr("1.1");
print("fromstr: 1.1 ==>", d0);
// Strconcat.
const char *x2 = "Hello";
x2 = strconcat(x2, " World!", " Howdy!");
print("strconcat: Hello World! Howdy =", x2);
char *y1 = "Hello";
y1 = strconcat(y1, " World!", " Howdy!");
print("strconcat: Hello World! Howdy =", y1);
// strfind.
print("strfind: 4 ==>", strfind("Hello World!", "o"));
print("strfind: 7 ==>", strfind("Hello World!", "o", 5));
print("strfind: 1 ==>", strfind("Hello World!", "?") == npos);
print("strfind: 0 ==>", strfind("Hello World!", "?") == 10);
// strreplace.
print("strreplace: Hello Universe! ==>", strreplace("Hello World!", "World", "Universe"));
print("strreplace: Hello! ==>", strreplace("Hello World!", " World", ""));
print("strreplace: Hello World! ==>", strreplace("Hello World!", "", ""));
return 0;
}
```