Skip to main content
Code Review

Return to Revisions

2 of 9
add source code

I created something much faster than a std::string

Welcome everyone πŸ‘‹

I work as a freelancer in C++.

some time ago a company asked me to work on a special type of database system and their condition was that the system be very fast, faster than any known database!

I did this already and it turns out that my system is 50 times faster than MySQL!

The work was done, I received my salary and everything was fine.

But they contacted me a few days ago and told me why don't you try to develop the system further? And i agreed.

I tested just about everything, everything was perfect except for a few things like: std::string, std::vector.

I created mini libraries from those to compare performance and was surprised that what I did was much faster!

Therefore, I developed a special string system and wanted to share it with you for the benefit, and also to benefit from your suggestions and experience.

System Features:

  • Much faster than std::string.

  • Easy to use.

  • It was designed as part of a large database so it is very fast and good at handling memory.

  • Responsive to all types of data, you can enter characters, numbers, even decimal numbers, boolean values ​​or even lists, without the need to convert data types to a string.

  • It contains a system dedicated to calculating numbers and converting them into text strings, It works great with decimal numbers. see below to learn more.

  • All functions tested, no errors detected.

The reason for the speed of performance:

The reason lies in the way I handle the heap memory, I don't need to realloc memory every time the value changes, and I don't need to completely reset the object when any modification is made.

If you are interested you can check out the set() function, i have left comments that can explain this further.

Test results:

+-------------------------+--------+------+------------------------------+
|METHOD |CLASS |TIME |NOTES |
+-------------------------+--------+------+------------------------------+
|create empty |xstring |210 | |
| |string |1586 | |
+-------------------------+--------+------+------------------------------+
|create by string |xstring |1859 | |
| |string |3194 | |
+-------------------------+--------+------+------------------------------+
|create by character |xstring |1852 | |
| |string |2680 |Unavailable, used to_string() |
+-------------------------+--------+------+------------------------------+
|create by bool |xstring |1836 | |
| |string |2487 |Unavailable, used to_string() |
+-------------------------+--------+------+------------------------------+
|create by integer |xstring |2477 | |
| |string |2453 |Unavailable, used to_string() |
+-------------------------+--------+------+------------------------------+
|create by decimal |xstring |4428 | |
| |string |23053 |Unavailable, used to_string() |
+-------------------------+--------+------+------------------------------+
|create by same object |xstring |3750 | |
| |string |9779 | |
+-------------------------+--------+------+------------------------------+
|create by multiple |xstring |3726 | |
| |string |-- |Unavailable |
+-------------------------+--------+------+------------------------------+
|append |xstring |2426 | |
| |string |7685 | |
+-------------------------+--------+------+------------------------------+
|prepend |xstring |2593 | |
| |string |10665 |Unavailable, used insert(0,) |
+-------------------------+--------+------+------------------------------+
|insert |xstring |2574 | |
| |string |10579 | |
+-------------------------+--------+------+------------------------------+
|compare |xstring |3985 | |
| |string |8200 | |
+-------------------------+--------+------+------------------------------+
|swap |xstring |3928 | |
| |string |11579 | |
+-------------------------+--------+------+------------------------------+
|to lower |xstring |2407 | |
| |string |-- |Unavailable |
+-------------------------+--------+------+------------------------------+
|to upper |xstring |2432 | |
| |string |-- |Unavailable |
+-------------------------+--------+------+------------------------------+
|select by index |xstring |1984 | |
| |string |3303 | |
+-------------------------+--------+------+------------------------------+
|select by char and pos |xstring |1976 | |
| |string |4138 | |
+-------------------------+--------+------+------------------------------+
|select last |xstring |1910 | |
| |string |3563 | |
+-------------------------+--------+------+------------------------------+
|pop last |xstring |2114 | |
| |string |4338 | |
+-------------------------+--------+------+------------------------------+
|pop by index |xstring |2095 | |
| |string |6591 | |
+-------------------------+--------+------+------------------------------+
|reverse |xstring |2465 | |
| |string |-- |Unavailable |
+-------------------------+--------+------+------------------------------+
|find first of |xstring |2001 | |
| |string |4446 | |
+-------------------------+--------+------+------------------------------+
|find last of |xstring |1979 | |
| |string |4199 | |
+-------------------------+--------+------+------------------------------+
|sub string |xstring |4070 | |
| |string |17287 | |
+-------------------------+--------+------+------------------------------+
|is empty |xstring |1909 | |
| |string |3262 | |
+-------------------------+--------+------+------------------------------+

Test Info

  • OS linux, ubuntu 20.04

  • processor Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz

  • memory 8064MiB System memory

  • Compiler g++ 11

  • C++ Version c++ 20

  • tested by valgrind, you can test with just run script and you will got same ratios

You can find the source file and test script here GitHub: xString

I have some questions :

  1. Are there any errors that I did not notice?

  2. Is there anything that can be done to improve performance?

  3. Is there anything missing?

  4. What is your opinion and what are your suggestions?


Edit: xstring.h

/*
 All rights reserved: Maysara Khalid Elshewehy [github.com/xeerx]
 Created on: 4 Apr 2022
 Commercial use of this file is prohibited without written permission
*/
#ifndef XCPP_XSTRING_H
#define XCPP_XSTRING_H
#include <string.h> // strlen
#include <cstdlib> // calloc, realloc, free
#include <initializer_list> // initializer_list
#include <stddef.h> // size_t
#include <stdint.h> // SIZE_MAX
#include <ostream> // ostream operator
// xstring macros
#define xnpos SIZE_MAX // max size of size_t, when error, return to it
#define _xs_extra_space_ 25 // the extra space size in heap memory
// xstring helpers
namespace x::hlpr
{
 // [INTEGER LENGTH]
 #define __sig_int_len__(t) (t int src) { unsigned t int len = src < 0 ? 1 : 0; while(true) { src /= 10; if(src != 0) len ++; else return len; } }
 #define __uns_int_len__(t) (unsigned t int src) { unsigned t int len = 0; while(true) { src /= 10; if(src != 0) len ++; else return len; } }
 unsigned int intlen __sig_int_len__() 
 unsigned int uintlen __uns_int_len__() 
 unsigned short int sintlen __sig_int_len__(short) 
 unsigned short int usintlen __uns_int_len__(short) 
 unsigned long lintlen __sig_int_len__(long) 
 unsigned long ulintlen __uns_int_len__(long) 
 unsigned long long llintlen __sig_int_len__(long long) 
 unsigned long long ullintlen __uns_int_len__(long long)
 // [INTEGER TO STRING]
 #define __sig_int_str__(s,t) (char *ref, s src, unsigned s len = 0) { if(src == 0){ ref[0] = '0'; ref[1] = '0円'; return; } if (len == 0) len = t(src) + 1; if (src < 0) { src = src * -1; ref[0] = '-'; } len--; ref[len + 1] = '0円'; while (src > 0) { ref[len] = src % 10 + '0'; src /= 10; len--; } } 
 #define __uns_int_str__(s,t) (char *ref, unsigned s src, unsigned s len = 0) { if(src == 0){ ref[0] = '0'; ref[1] = '0円'; return; } if(len == 0) len = t(src) +1; len --; ref[len+1] = '0円'; while(src >= 1) { ref[len] = src % 10 + '0'; src /= 10; len --; } }
 
 void intstr __sig_int_str__(int,intlen) 
 void uintstr __uns_int_str__(int ,uintlen)
 
 void sintstr __sig_int_str__(short int,sintlen) 
 void usintstr __uns_int_str__(short int ,usintlen)
 void lintstr __sig_int_str__(long int,lintlen)
 void ulintstr __uns_int_str__(long int ,ulintlen)
 void llintstr __sig_int_str__(long long int,llintlen) 
 void ullintstr __uns_int_str__(long long int ,ullintlen)
 // [INTEGER MACROS]
 #define __int_str_shortcut__(src,l,lfunc,sfunc) unsigned l __len = x::hlpr::lfunc(src) +1; char * __ref = new char[__len+1]; x::hlpr::sfunc(__ref,src,__len); delete [] __ref;
 
 #define __intstr__(src) __int_str_shortcut__(src,int,intlen,intstr)
 #define __uintstr__(src) __int_str_shortcut__(src,int,uintlen,uintstr)
 #define __sintstr__(src) __int_str_shortcut__(src,short int,sintlen,sintstr)
 #define __usintstr__(src) __int_str_shortcut__(src,short int,usintlen,usintstr)
 
 #define __lintstr__(src) __int_str_shortcut__(src,long int,lintlen,lintstr)
 #define __ulintstr__(src) __int_str_shortcut__(src,long int,ulintlen,ulintstr)
 #define __llintstr__(src) __int_str_shortcut__(src,long long int,llintlen,llintstr)
 #define __ullintstr__(src) __int_str_shortcut__(src,long long int,ullintlen,ullintstr)
 // [DECIMAL LENGTH]
 #define __decimal_len__(t) (t src, unsigned short int max = 6) { unsigned int len = 0, ilen = 0, i = 0; int isrc = (int)src; if(src < 0) src *= -1; if(src > 0) { ilen = intlen(isrc); src -= isrc;} while(i < max && (isrc - src) != 0) { src = src * 10; i++; len ++; } return len + ilen; }
 unsigned int floatlen __decimal_len__(float)
 unsigned int doublelen __decimal_len__(double)
 unsigned int ldoublelen __decimal_len__(long double)
 
 // [DECIMAL TO STRING]
 #define __decimal_str__(t,lfunc) (char *ref, t src, unsigned short int max = 0, bool setmax = false) { bool neg = false; if(src < 0) { src = src * -1; neg = true; } if(src == 0) { ref[0] = '0'; ref[1] = '.'; ref[2] = '0'; ref[3] = '0円'; } int numbers = src, digit = 0, numberslen = x::hlpr::intlen(numbers), index = numberslen + 1; long pow_value = 0; unsigned int flen = x::hlpr::lfunc(src); if(numberslen > 0) flen -= numberslen; if(!max) max = flen; else if(setmax) max -= numberslen; max --; x::hlpr::intstr(ref,numbers,index); ref[index] = '.'; index ++; if(numbers == src) { ref[index] = '0'; index ++; if(neg) { unsigned int bi = index; ref[bi] = '0円'; while (index >= 0) { ref[index+1] = ref[index]; index --; } ref[0] = '-'; return bi +1; } else ref[index] = '0円'; return index; } t fraction_part = src - numbers; t tmp1 = fraction_part, tmp =0; for( int i= 1; i < max + 2; i++) { pow_value = 10; tmp = tmp1 * pow_value; digit = tmp; ref[index] = digit +48; tmp1 = tmp - digit; index ++; } int temp_index = index -1; while(temp_index >= 0) { if(ref[temp_index] == '0') { ref[temp_index] = '0円'; index --; } else break; temp_index --; } temp_index = index -1; while(temp_index >= 0) { if(ref[temp_index] == ref[temp_index-1]) { ref[temp_index] = '0円'; index --; } else break; temp_index --; } if(neg) { unsigned int bi = index; ref[bi] = '0円'; while (index >= 0) { ref[index+1] = ref[index]; index --; } ref[0] = '-'; return bi+1; } else ref[index] = '0円'; return index;}
 unsigned int floatstr __decimal_str__(float,floatlen)
 unsigned int doublestr __decimal_str__(double,doublelen)
 unsigned int ldoublestr __decimal_str__(long double,ldoublelen)
 // [DECIMAL MACROS]
 #define __decimal_str_shortcut__(src,lfunc,sfunc,max) unsigned short int __len = x::hlpr::lfunc(src,max) +1; char * __ref = new char[__len+4];__len = x::hlpr::sfunc(__ref,src,__len,true); delete [] __ref;
 #define __floatstr__(src) __decimal_str_shortcut__(src,floatlen,floatstr,max)
 #define __doublestr__(src) __decimal_str_shortcut__(src,doublelen,doublestr,max)
 #define __ldoublestr__(src) __decimal_str_shortcut__(src,ldoublelen,ldoublestr,max)
}
// xstring class
namespace x
{
 // some variables used to return to error
 char xstr_null_char = '0円';
 class xstring
 {
 public:
 
 // data
 char *src = nullptr; // pointer to character array wich contains to value of object
 size_t len = 0; // length of src, zero means empty
 size_t siz = 0; // size of src in heap memory
 // constructor -> default empty
 xstring () { }
 xstring (const char *ref, size_t rlen = 0) { set(ref,rlen); }
 xstring (char ref) { set(ref); }
 xstring (bool ref) { set(ref); }
 xstring ( int ref) { set(ref); }
 xstring (unsigned int ref) { set(ref); }
 xstring (short int ref) { set(ref); }
 xstring (unsigned short int ref) { set(ref); }
 xstring (long int ref) { set(ref); }
 xstring (unsigned long int ref) { set(ref); }
 
 xstring (long long int ref) { set(ref); }
 xstring (unsigned long long int ref) { set(ref); }
 xstring (float ref,unsigned short max = 1) { set(ref,max); }
 xstring (double ref,unsigned short max = 1) { set(ref,max); }
 xstring (long double ref,unsigned short max = 1) { set(ref,max); }
 xstring (xstring &ref) { set(ref); }
 xstring (const xstring &ref) { set(ref); }
 template <typename T>
 xstring (std::initializer_list<T> ref) { for(auto i:ref) append(i); }
 // set
 bool set (const char *ref, size_t rlen);
 bool set (char ref) { char __ref[] = {ref}; return set(__ref, 1); }
 bool set (bool ref) { return set(ref ? "1" : "0", 1); }
 bool set ( int ref) { __intstr__ (ref) return set(__ref, __len); }
 bool set (unsigned int ref) { __uintstr__ (ref) return set(__ref, __len); }
 bool set (short int ref) { __sintstr__ (ref) return set(__ref, __len); }
 bool set (unsigned short int ref) { __usintstr__ (ref) return set(__ref, __len); }
 bool set (long int ref) { __lintstr__ (ref) return set(__ref, __len); }
 bool set (unsigned long int ref) { __ulintstr__ (ref) return set(__ref, __len); }
 bool set (long long int ref) { __llintstr__ (ref) return set(__ref, __len); }
 bool set (unsigned long long int ref) { __ullintstr__ (ref) return set(__ref, __len); }
 bool set (float ref,unsigned short max = 1) { __floatstr__ (ref) return set(__ref, __len); }
 bool set (double ref,unsigned short max = 1) { __doublestr__ (ref) return set(__ref, __len); }
 bool set (long double ref,unsigned short max = 1) { __ldoublestr__ (ref) return set(__ref, __len); }
 
 bool set (xstring &ref) { if(&ref != this) return set(ref.src, ref.len); else return false; }
 bool set (const xstring &ref) { if(&ref != this) return set(ref.src, ref.len); else return false; }
 template <typename T>
 bool set (std::initializer_list<T> ref) { reset(); for(auto i:ref) if(!append(i)) return false; return true; }
 template <typename T> 
 bool operator = (T ref) { return set(ref); }
 template <typename T> 
 bool operator = (std::initializer_list<T> ref) { return set(ref); }
 // append
 bool append (const char *ref, size_t rlen);
 bool append (char ref) { char __ref[] = {ref}; return append(__ref, 1); }
 bool append (bool ref) { return append(ref ? "1" : "0", 1); }
 bool append ( int ref) { __intstr__ (ref) return append(__ref, __len); }
 bool append (unsigned int ref) { __uintstr__ (ref) return append(__ref, __len); }
 bool append (short int ref) { __sintstr__ (ref) return append(__ref, __len); }
 bool append (unsigned short int ref) { __usintstr__ (ref) return append(__ref, __len); }
 bool append (long int ref) { __lintstr__ (ref) return append(__ref, __len); }
 bool append (unsigned long int ref) { __ulintstr__ (ref) return append(__ref, __len); }
 bool append (long long int ref) { __llintstr__ (ref) return append(__ref, __len); }
 bool append (unsigned long long int ref) { __ullintstr__ (ref) return append(__ref, __len); }
 bool append (float ref,unsigned short max = 1) { __floatstr__ (ref) return append(__ref, __len); }
 bool append (double ref,unsigned short max = 1) { __doublestr__ (ref) return append(__ref, __len); }
 bool append (long double ref,unsigned short max = 1) { __ldoublestr__ (ref) return append(__ref, __len); }
 
 bool append (xstring &ref) { if(&ref != this) return append(ref.src, ref.len); else return false; }
 bool append (const xstring &ref) { if(&ref != this) return append(ref.src, ref.len); else return false; }
 template <typename T>
 bool append (std::initializer_list<T> ref) { for(auto i:ref) if(!append(i)) return false; return true; }
 template <typename T> 
 bool operator += (T ref) { return append(ref); }
 template <typename T> 
 bool operator += (std::initializer_list<T> ref) { return append(ref); }
 
 // prepend
 bool prepend (const char *ref, size_t rlen);
 bool prepend (char ref) { char __ref[] = {ref}; return prepend(__ref, 1); }
 bool prepend (bool ref) { return prepend(ref ? "1" : "0", 1); }
 bool prepend ( int ref) { __intstr__ (ref) return prepend(__ref, __len); }
 bool prepend (unsigned int ref) { __uintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (short int ref) { __sintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (unsigned short int ref) { __usintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (long int ref) { __lintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (unsigned long int ref) { __ulintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (long long int ref) { __llintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (unsigned long long int ref) { __ullintstr__ (ref) return prepend(__ref, __len); }
 bool prepend (float ref,unsigned short max = 1) { __floatstr__ (ref) return prepend(__ref, __len); }
 bool prepend (double ref,unsigned short max = 1) { __doublestr__ (ref) return prepend(__ref, __len); }
 bool prepend (long double ref,unsigned short max = 1) { __ldoublestr__ (ref) return prepend(__ref, __len); }
 
 bool prepend (xstring &ref) { if(&ref != this) return prepend(ref.src, ref.len); else return false; }
 bool prepend (const xstring &ref) { if(&ref != this) return prepend(ref.src, ref.len); else return false; }
 template <typename T>
 bool prepend (std::initializer_list<T> ref) { for(auto i:ref) if(!prepend(i)) return false; return true; }
 template <typename T> 
 bool operator |= (T ref) { return prepend(ref); }
 template <typename T> 
 bool operator |= (std::initializer_list<T> ref) { return prepend(ref); }
 // print
 friend std::ostream &operator<<(std::ostream &os, const xstring &s) { os << (s.src ? s.src : ""); return (os); }
 // insert
 bool insert (size_t pos, const char *ref, size_t rlen);
 bool insert (size_t pos, char ref) { char __ref[] = {ref}; return insert(pos,__ref, 1); }
 // compare between two strings
 bool compare(const char *ref) { return strcmp(src,ref) == 0; }
 bool compare(xstring& ref) { return compare(ref.src); }
 bool compare(const xstring& ref) { return compare(ref.src); }
 bool compare( char ref) { char __ref[] = {ref}; return compare(__ref); }
 bool operator == (const char *ref) { return compare(ref) == true; }
 bool operator == (xstring& ref) { return compare(ref) == true; }
 bool operator == (const xstring& ref) { return compare(ref) == true; }
 bool operator == ( char ref) { return compare(ref) == true; }
 
 // no need in C++ 20
 // bool operator != (const char *ref) { return compare(ref) == false; }
 // bool operator != (xstring& ref) { return compare(ref) == false; }
 // bool operator != (const xstring& ref) { return compare(ref) == false; }
 // bool operator != ( char ref) { return compare(ref) == false; }
 // swap value,len,size between two string objects
 void swap(xstring &ref)
 {
 char *tmp_src = src;
 size_t tmp_len = len;
 size_t tmp_siz = siz;
 
 src = ref.src;
 len = ref.len;
 siz = ref.siz;
 ref.src = tmp_src;
 ref.len = tmp_len;
 ref.siz = tmp_siz;
 }
 // convert src characters to lower case
 void to_lower() 
 {
 size_t i = 0;
 while(src[i] != '0円') { src[i] = std::tolower(src[i]); i++; }
 }
 // convert src characters to upper case
 void to_upper() 
 {
 size_t i = 0;
 while(src[i] != '0円') { src[i] = std::toupper(src[i]); i++; }
 }
 // select character by index, return xstr_null_char if not found
 char& getChar(size_t ref) 
 {
 if(ref > len) return xstr_null_char;
 return src[ref];
 } 
 char& operator[](size_t ref) { return getChar(ref); }
 // select index by value, start from position, return xnpos if not found
 size_t getIndex(char ref, size_t pos = 0) 
 {
 if(pos > len) return xnpos;
 size_t counter = pos;
 while(counter < len) 
 {
 if(src[counter] == ref) return counter;
 counter ++;
 }
 return xnpos;
 }
 // get last character
 char& getLast() { return src[len-1]; }
 
 // remove from value by index
 bool pop(size_t pos = 0, size_t max = 1)
 {
 if(pos >= len) return false;
 if(max > len || max == 0) max = len;
 memmove(&src[pos], &src[pos + max], len - pos - 1);
 src[len - 1] = '0円';
 len --;
 return true;
 }
 // remove last character using pop(len-1)
 bool pop_last() { return pop(len-1); }
 // reverse characters
 void reverse()
 {
 char *tmp = new char[len];
 size_t count = len;
 size_t count_src = 0;
 while(count > 0)
 {
 tmp[count-1] = src[count_src];
 count --;
 count_src ++;
 }
 tmp[len] = '0円';
 memcpy(src,tmp,len+1);
 delete [] tmp;
 }
 // check if value is empty by check if length equals zero
 bool empty() { return len == 0; }
 // find first matched character in string, start from begin + pos, if failed return to xnpos
 size_t first_of(char ref, size_t pos = 0)
 {
 if(pos >= len) return xnpos;
 while( src[pos]!=ref && pos < len) pos++;
 return pos == len ? xnpos : pos;
 }
 // find last matched character in string, start from end - pos, if failed return to xnpos
 size_t last_of (char ref, size_t pos = 0)
 {
 if(pos >= len) return xnpos;
 pos = len - pos -1; 
 while(src[pos]!=ref && pos > 0) pos--;
 if(src[pos] == ref) return pos; else return xnpos;
 }
 // cut string from [start] to [end] and set to ref
 bool sub(xstring &ref, size_t start = 0, size_t end = 0)
 {
 if(start >= len) start = len -1;
 if(start == end) return false;
 if(end == 0 || end >= len) end = len;
 size_t llen = end - start;
 char *res = new char[llen+1];
 size_t pos = 0;
 while(start < end) 
 {
 res[pos] = src[start];
 start ++;
 pos ++;
 }
 res[pos] = '0円';
 ref.set(res, llen+1);
 delete [] res;
 return true;
 }
 // free memory, set values to zero
 void reset () { if(!siz) return; free(src); len = 0; siz = 0; }
 
 // destructor
 ~xstring () { reset(); }
 };
}
// xstring class functions, i will write long functions here to arrange the file and keep it beautiful
namespace x
{
 /**
 * @brief set value of xstring object
 */
 bool xstring::set (const char *ref, size_t rlen = 0)
 {
 if(!rlen) rlen = strlen(ref); // [increase performance] If the length is known, there is no need to recalculate it
 if(siz == 0) // alloc space in heap memory to store value
 {
 siz = rlen + _xs_extra_space_; // [increase performance] extra 25 bytes space to avoid realloc in next times if space is enough
 if(siz >= xnpos - 25) { siz -= rlen + _xs_extra_space_; return false; } // check if size > max size
 src = (char*) calloc(siz, sizeof(char)); // allocate space
 if(src == nullptr) return false; // check if space is allocated
 }
 else if(siz <= rlen) // realloc more space to contains the new value
 {
 siz = rlen + _xs_extra_space_; 
 if(siz >= xnpos - 25) { siz -= rlen + _xs_extra_space_; return false; }
 src = (char*) realloc(src, siz * sizeof(char)); 
 if(src == nullptr) return false; 
 }
 memcpy(src, ref, rlen+1); // copy value from ref
 len = rlen; // update length
 src[len] = '0円'; // terminate the array
 return true;
 }
 /**
 * @brief add value to begin of xstring object
 */
 bool xstring::append (const char *ref, size_t rlen = 0)
 {
 if(siz == 0) return set(ref,rlen); // if space is null, call set()
 if(!rlen) rlen = strlen(ref); 
 if(siz <= (len + rlen)) 
 {
 siz += rlen + _xs_extra_space_;
 if(siz >= xnpos - 25) { siz -= rlen + _xs_extra_space_; return false; }
 src = (char*) realloc(src, siz * sizeof(char)); 
 if(src == nullptr) return false;
 }
 memcpy(src + len, ref, rlen+1);
 len += rlen; 
 src[len] = '0円'; 
 return true;
 }
 /**
 * @brief add value to end of xstring object
 */
 bool xstring::prepend (const char *ref, size_t rlen = 0)
 {
 if(siz == 0) return set(ref,rlen);
 if(!rlen) rlen = strlen(ref);
 if(siz <= (len + rlen))
 {
 siz += rlen + _xs_extra_space_;
 if(siz >= xnpos - 25) { siz -= rlen + _xs_extra_space_; return false; }
 src = (char*) realloc(src, siz * sizeof(char)); if(src == nullptr) return false;
 }
 
 memmove(src + rlen, src, len); // move data to rlen pos
 size_t i = 0; 
 while(i < rlen) // loop in copy ref to begin of src
 { 
 src[i] = ref[i]; 
 ++i; 
 }
 len += rlen; 
 src[len] = '0円'; 
 return true;
 }
 
 /**
 * @brief add value to position of xstring object
 */
 bool xstring::insert (size_t pos, const char *ref, size_t rlen = 0)
 {
 if(siz == 0) return set(ref,rlen);
 if(pos > len) return false;
 if(!rlen) rlen = strlen(ref);
 if(siz <= (len + rlen))
 {
 siz += rlen + _xs_extra_space_;
 if(siz >= xnpos - 25) { siz -= rlen + _xs_extra_space_; return false; }
 src = (char*) realloc(src, siz * sizeof(char)); if(src == nullptr) return false;
 }
 memmove(src + rlen, src, len);
 size_t i = 0; while(true) { size_t target = pos == 0 ? (0 + i) : (pos+i); src[target] = ref[i]; if(++i >= rlen) break;; }
 len += rlen; src[len] = '0円'; return true;
 }
 
}
#endif

test.cpp

#include "xstring.h"
#include <chrono>
#include <string>
#include <iostream>
#include <iomanip>
#include <limits.h>
#include <float.h>
using namespace x;
using namespace std;
void TEST_PRNT (const char*f, const char*t, const char*r, const char*n, bool row = false) { char sep = row ? '+' : '|'; std::cout << std::left << sep << std::setw(25) << f << sep << std::setw(8) << t << sep << std::setw(6) << r << sep << std::setw(30) << n << sep << std::endl; }
#define TEST_STUP std::chrono::steady_clock::time_point test_begin; std::chrono::steady_clock::time_point test_end; char test_result[75]; TEST_PRNT("-------------------------", "--------", "------", "------------------------------",true);TEST_PRNT("METHOD", "CLASS", "TIME", "NOTES");TEST_PRNT("-------------------------", "--------", "------", "------------------------------",true);
#define TEST_STRT test_begin = std::chrono::steady_clock::now(); for(int i = 0; i < 1000000; ++i) {
#define TEST_STOP } test_end = std::chrono::steady_clock::now(); sprintf(test_result,"%-6ld",(std::chrono::duration_cast<std::chrono::microseconds>(test_end - test_begin).count()) / 1000);
#define TEST_LINE TEST_PRNT("-------------------------", "--------", "------", "------------------------------", true);
using namespace x;
int main()
{
 std::cout << "----------------------------------------" << std::endl;
 std::cout << "USE: g++ --std c++20 -g test.cpp -o test" << std::endl;
 std::cout << "----------------------------------------" << std::endl;
 TEST_STUP
 // create empty
 TEST_STRT xstring x; TEST_STOP TEST_PRNT("create empty","xstring" ,test_result,""); 
 TEST_STRT string x; TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // create by string
 TEST_STRT xstring x = "value"; TEST_STOP TEST_PRNT("create by string","xstring" ,test_result,""); 
 TEST_STRT string x = "value"; TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // create by character
 TEST_STRT xstring x = 'c'; TEST_STOP TEST_PRNT("create by character","xstring" ,test_result,""); 
 TEST_STRT string x = to_string('c'); TEST_STOP TEST_PRNT(" ","string" ,test_result,"Unavailable, used to_string()"); TEST_LINE
 // create by bool
 TEST_STRT xstring x = true; TEST_STOP TEST_PRNT("create by bool","xstring" ,test_result,""); 
 TEST_STRT string x = to_string(true); TEST_STOP TEST_PRNT(" ","string" ,test_result,"Unavailable, used to_string()"); TEST_LINE
 // create by integer
 TEST_STRT xstring x = 1; TEST_STOP TEST_PRNT("create by integer","xstring" ,test_result,""); 
 TEST_STRT string x = to_string(1); TEST_STOP TEST_PRNT(" ","string" ,test_result,"Unavailable, used to_string()"); TEST_LINE
 // create by decimal
 TEST_STRT xstring x = 123.456; TEST_STOP TEST_PRNT("create by decimal","xstring" ,test_result,""); 
 TEST_STRT string x = to_string(123.456); TEST_STOP TEST_PRNT(" ","string" ,test_result,"Unavailable, used to_string()"); TEST_LINE
 // create by same object
 TEST_STRT xstring y = "val"; xstring x = y; TEST_STOP TEST_PRNT("create by same object","xstring" ,test_result,""); 
 TEST_STRT string y = "val"; string x = y; TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // create by multiple
 TEST_STRT xstring x = {"Hello"," ","World","!"}; TEST_STOP TEST_PRNT("create by multiple","xstring" ,test_result,""); 
 TEST_PRNT(" ","string" ,"--" ,"Unavailable"); TEST_LINE
 
 // append
 TEST_STRT xstring x = "Hello"; x += "World"; TEST_STOP TEST_PRNT("append","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x += "World"; TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // prepend
 TEST_STRT xstring x = "Hello"; x |= "Hello"; TEST_STOP TEST_PRNT("prepend","xstring" ,test_result,""); 
 TEST_STRT string x = "World"; x.insert(0,"Hello"); TEST_STOP TEST_PRNT(" ","string" ,test_result,"Unavailable, used insert(0,)"); TEST_LINE
 
 // insert
 TEST_STRT xstring x = "Hello"; x.insert(3,"Hello"); TEST_STOP TEST_PRNT("insert","xstring" ,test_result,""); 
 TEST_STRT string x = "World"; x.insert(3,"Hello"); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // compare
 TEST_STRT xstring x = "Hello", y = "World"; x.compare(y); TEST_STOP TEST_PRNT("compare" ,"xstring" ,test_result,""); 
 TEST_STRT string x = "Hello", y = "World"; x.compare(y); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // swap
 TEST_STRT xstring x = "Hello", y = "World"; x.swap(y); TEST_STOP TEST_PRNT("swap" ,"xstring" ,test_result,""); 
 TEST_STRT string x = "Hello", y = "World"; x.swap(y); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // to lower
 TEST_STRT xstring x = "Hello"; x.to_lower(); TEST_STOP TEST_PRNT("to lower" ,"xstring" ,test_result,""); 
 TEST_PRNT(" ","string" ,"--","Unavailable"); TEST_LINE
 // to upper
 TEST_STRT xstring x = "Hello"; x.to_upper(); TEST_STOP TEST_PRNT("to upper" ,"xstring" ,test_result,""); 
 TEST_PRNT(" ","string" ,"--","Unavailable"); TEST_LINE
 
 // select by index
 TEST_STRT xstring x = "Hello"; x[0] = 'x'; TEST_STOP TEST_PRNT("select by index","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x[0] = 'x'; TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // select char
 TEST_STRT xstring x = "Hello"; x.getIndex('l',1); TEST_STOP TEST_PRNT("select by char and pos","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.find('l',1); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // select last
 TEST_STRT xstring x = "Hello"; x.getLast(); TEST_STOP TEST_PRNT("select last","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.back(); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // pop last
 TEST_STRT xstring x = "Hello"; x.pop_last(); TEST_STOP TEST_PRNT("pop last","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.pop_back(); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // pop by index
 TEST_STRT xstring x = "Hello"; x.pop(2,1); TEST_STOP TEST_PRNT("pop by index","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.erase(2,1); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // reverse
 TEST_STRT xstring x = "Hello"; x.reverse(); TEST_STOP TEST_PRNT("reverse","xstring" ,test_result,""); 
 TEST_PRNT(" ","string" ,"--","Unavailable"); TEST_LINE
 // find first of
 TEST_STRT xstring x = "Hello"; x.first_of('l'); TEST_STOP TEST_PRNT("find first of","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.find_first_of('l'); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // find last of
 TEST_STRT xstring x = "Hello"; x.last_of('l'); TEST_STOP TEST_PRNT("find last of","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; x.find_last_of('l'); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // sub string
 TEST_STRT xstring x = "Hello",y; x.sub(y, 0,3); TEST_STOP TEST_PRNT("sub string","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello",y; y = x.substr(0,3); TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
 // is empty
 TEST_STRT xstring x = "Hello"; if(x.empty()){} TEST_STOP TEST_PRNT("is empty","xstring" ,test_result,""); 
 TEST_STRT string x = "Hello"; if(x.empty()){} TEST_STOP TEST_PRNT(" ","string" ,test_result,""); TEST_LINE
}
lang-cpp

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /