Why using std::string when you can create it yourself...

Started by
12 comments, last by MarkS_ 9 years, 1 month ago

I am not sure why or what was going on my mind, while creating this "dishy" code somewhere around 2005 where i started to learn c/c++ tongue.png

But this is ridiculous and if i remember correctly, there was memory leaks in it - have fun to find it...

Source file:


#include "r3d_string.h"
#include "r3d_global.h"

// Static string

sR3DStaticString::sR3DStaticString()
{
    data[0] = '\0';
}

sR3DStaticString::sR3DStaticString(const char* str)
{
    data[0] = '\0';
    if (strlen(str) > 0)
        AddTo((char*)str);
}

sR3DStaticString::sR3DStaticString(const sR3DStaticString &s)
{
    data[0] = '\0';
    if (strlen(s.data) > 0)
        AddTo(s.data);
}

bool sR3DStaticString::operator == (const char* cmpstr)
{
    return StaticStringCompare(*this, cmpstr) == 0;
}

bool sR3DStaticString::operator == (const sR3DStaticString &s)
{
    return StaticStringCompare(*this, s) == 0;
}

void sR3DStaticString::operator += (const char addc)
{
    char buf[2];
    buf[0] = addc;
    buf[1] = '\0';
    AddTo((char*)buf);
}

void sR3DStaticString::operator += (const char* addstr)
{
    AddTo((char*)addstr);
}

void sR3DStaticString::operator += (const sR3DStaticString &s)
{
    AddTo(s.data);
}

void sR3DStaticString::Clear()
{
    data[0] = '\0';
}

void sR3DStaticString::AddTo(const char* addstr)
{
    strcat(data, addstr);
    data[strlen(data)] = '\0';
}

void sR3DStaticString::AddTo(const char* addstr, const int len)
{
    strncat(data, addstr, len);
    data[strlen(data)] = '\0';
}

void sR3DStaticString::ReplaceChar(const char oldchar, const char newchar)
{
    for (int i = 0; i < strlen(data); i++)
        if (data[i] == oldchar) data[i] = newchar;
}

void sR3DStaticString::AddTrailingPathDelimiter()
{
    if (strlen(data) > 0)
        if (data[strlen(data)-1] != '/')
            AddTo("/");
}

int sR3DStaticString::Pos(const char* substr)
{
    int i = 1;
    char* pch = data;
    while (*pch)
    {
        if (strncmp(pch, substr, strlen(substr)) == 0) return i;
        pch++;
        i++;
    }
    return 0;
}

int sR3DStaticString::Delete(int start, int to)
{
    sR3DStaticString news = "";
    for (int i = 1; i < strlen(data)+1; i++)
    {
        if ((i < start) || (i > to))
            news+=data[i-1];
    }
    if (news.Len() != strlen(data))
    {
        Clear();
        AddTo(news.data);
    }
    return to-start;
}

int sR3DStaticString::RemoveComments()
{
    int commentpos = Pos("//");
    if (commentpos > 0)
        return Delete(commentpos, strlen(data)+1);
    else
        return 0;
}

sR3DStaticString operator + (const sR3DStaticString &s1, const sR3DStaticString  &s2)
{
    char buffer[255];
    buffer[0] = '\0';
    strcat(buffer, s1.data);
    strcat(buffer, s2.data);
    buffer[strlen(buffer)] = '\0';
    return sR3DStaticString(buffer);
}

sR3DStaticString operator + (const sR3DStaticString &s, const char* value)
{
    char buffer[255];
    buffer[0] = '\0';
    strcat(buffer, s.data);
    strcat(buffer, value);
    buffer[strlen(buffer)] = '\0';
    return sR3DStaticString(buffer);
}

sR3DStaticString StaticStringCopy(char* str, int from, int to)
{
    sR3DStaticString newstr;

    // Check if from and to is in range
    if (((from > 0) && (from <= strlen(str))) &&
        ((to > 0) && (to <= strlen(str))))
    {
        int realfrom = from-1;
        int realto = to-1;
        int len = (to - from)+1;
        char* sptr = str;

        // Only left to right allowed
        if (from <= to)
        {
            sptr+=realfrom;
            char m[255];
            strncpy(m, sptr, len);
            m[len] = '\0';
            newstr.AddTo(m);
            free(m);
        }
    }
    return newstr;
}

int StaticStringCompare(const sR3DStaticString &str1, const char* str2)
{
    if (strlen(str1.data) == strlen(str2))
        return strcmp(str1.data,(char*) str2);
    else
        return -1;
}

int StaticStringCompare(const sR3DStaticString &str1, const sR3DStaticString &str2)
{
    if (strlen(str1.data) == strlen(str2.data))
        return strcmp(str1.data,str2.data);
    else
        return -1;
}

sR3DStaticString ExtractFilePath(char* S)
{
    sR3DStaticString res = "";
    int i,j,k;
    k = 0;
    j = strlen(S);
    for (i = j; i >= 1; i--)
    {
        if ((S[i] == '\\') || (S[i] == '/') || (S[i] == ':'))
        {
            k = i;
            break;
        }
    }
    if (k > 0) res.AddTo(S, k);
    return res;
}

sR3DStaticString ExtractFileNameWithoutExt(char* S)
{
    sR3DStaticString res = "";
    int i,j,k;
    k = 0;
    j = strlen(S);
    for (i = j; i >= 1; i--)
    {
        if (S[i] == '.')
        {
            k = i;
            break;
        }
    }
    if (k > 0) res.AddTo(S, k);
    return res;
}

// Dynamic

sR3DString::sR3DString()
{
    data = NULL;
    datalen = 0;
    len = 0;
}

sR3DString::sR3DString(const char* str)
{
    data = NULL;
    datalen = 0;
    len = 0;
    AddTo((char*)str);
}

sR3DString::sR3DString(const sR3DString &s)
{
    data = NULL;
    datalen = 0;
    len = 0;
    AddTo(s.data);
}

sR3DString::~sR3DString(void)
{
    Clear();
}

bool sR3DString::operator == (const char* cmpstr)
{
    return StringCompare(*this, cmpstr) == 0;
}

bool sR3DString::operator == (const sR3DString &s)
{
    return StringCompare(*this, s) == 0;
}

void sR3DString::operator += (const char addc)
{
    char buf[2];
    buf[0] = addc;
    buf[1] = '\0';
    AddTo((char*)buf);
}

void sR3DString::operator += (const char* addstr)
{
    AddTo((char*)addstr);
}

void sR3DString::operator += (const sR3DString &s)
{
    AddTo(s.data);
}

void sR3DString::Clear()
{
    if (data) free(data);
    datalen = 0;
}

void sR3DString::AddTo(const char* addstr)
{
    if (strlen(addstr) > 0)
    {
        if (datalen > 0)
        {
            // Save and kill data
            int oldlen = strlen(data);
            int olddatalen = sizeof(char) * oldlen+1;
            char* saved = (char*) malloc(olddatalen);
            memset(saved, 0, olddatalen);
            strncpy(saved, data, oldlen);
            saved[oldlen] = '\0';
            free(data);

            // Create new one and add old+new
            len = oldlen + strlen(addstr);
            datalen = sizeof(char) * len+1;
            data = (char*) malloc(datalen);
            memset(data, 0, datalen);
            strncpy(data, saved, oldlen);
            strcat(data, addstr);
            data[len] = '\0';
            free(saved);
        } else {
            // Create new one
            len = strlen(addstr);
            datalen = sizeof(char) * len+1;
            data = (char*) malloc(datalen);
            strncpy(data, addstr, len);
            data[len] = '\0';
        }
    }
}

void sR3DString::Alloc(const int newlen)
{
    Clear();
    datalen = newlen+1;
    len = newlen;
    data = (char*) malloc(datalen);
    data[0] = '\0';
}

sR3DString operator + (const sR3DString &s1, const sR3DString  &s2)
{
    sR3DString* newstr = new sR3DString();
    newstr->AddTo(s1.data);
    newstr->AddTo(s2.data);
    return *newstr;
}

sR3DString operator + (const sR3DString &s, const char* value)
{
    sR3DString* newstr = new sR3DString();
    newstr->AddTo(s.data);
    newstr->AddTo((char*)value);
    return *newstr;
}

sR3DString StringCopy(char* str, int from, int to)
{
    sR3DString* newstr = new sR3DString();

    // Check if from and to is in range
    if (((from > 0) && (from <= strlen(str))) &&
        ((to > 0) && (to <= strlen(str))))
    {
        int realfrom = from-1;
        int realto = to-1;
        int len = (to - from)+1;
        char* sptr = str;

        // Only left to right allowed
        if (from <= to)
        {
            sptr+=realfrom;
            char* m = (char*)malloc(sizeof(char) * len+1);
            strncpy(m, sptr, len);
            m[len] = '\0';
            newstr->AddTo(m);
            free(m);
        }

    }
    return *newstr;
}

int StringCompare(const sR3DString &str1, const char* str2)
{
    if (strlen(str1.data) == strlen(str2))
        return strcmp(str1.data,(char*) str2);
    else
        return -1;
}

int StringCompare(const sR3DString &str1, const sR3DString &str2)
{
    if (strlen(str1.data) == strlen(str2.data))
        return strcmp(str1.data,str2.data);
    else
        return -1;
}

Header file:


#ifndef _R3D_STRING_H
#define _R3D_STRING_H

#include <stdlib.h>
#include <string.h>

// Static string

struct sR3DStaticString
{
    char data[255];
    sR3DStaticString();
    sR3DStaticString(const char* addstr);
    sR3DStaticString(const sR3DStaticString &s);
    void Clear();
	void AddTo(const char* addstr);
	void AddTo(const char* addstr, const int len);
	void Terminate() { int l = strlen(data); data[l] = '\0'; }
    void ReplaceChar(const char oldchar, const char newchar);
    void AddTrailingPathDelimiter();
    int Pos(const char* substr);
    int Delete(int start, int to);
    int RemoveComments();
	int Len() { return strlen(data); }
	bool operator == (const char* cmpstr);
	bool operator == (const sR3DStaticString &s);
	void operator += (const char addc);
	void operator += (const char* addstr);
	void operator += (const sR3DStaticString &s);
};

sR3DStaticString operator + (const sR3DStaticString &s1, const sR3DStaticString  &s2);
sR3DStaticString operator + (const sR3DStaticString &s, const char* value);

sR3DStaticString StaticStringCopy(char* str, int from, int to);
int StaticStringCompare(const sR3DStaticString &str1, const char* str2);
int StaticStringCompare(const sR3DStaticString &str1, const sR3DStaticString &str2);
sR3DStaticString ExtractFilePath(char* S);
sR3DStaticString ExtractFileNameWithoutExt(char* S);

// Dynamic string

struct sR3DString
{
    char* data;
    int datalen;
    int len;
    sR3DString();
    sR3DString(const char* addstr);
    sR3DString(const sR3DString &s);
    ~sR3DString(void);
    void Clear();
	void AddTo(const char* addstr);
	void Alloc(const int newlen);
	void Terminate() { len = strlen(data); data[len] = '\0'; }
	//int Len() { return strlen(data); }
	bool operator == (const char* cmpstr);
	bool operator == (const sR3DString &s);
	void operator += (const char addc);
	void operator += (const char* addstr);
	void operator += (const sR3DString &s);
};

sR3DString operator + (const sR3DString &s1, const sR3DString  &s2);
sR3DString operator + (const sR3DString &s, const char* value);

sR3DString StringCopy(char* str, int from, int to);
int StringCompare(const sR3DString &str1, const char* str2);
int StringCompare(const sR3DString &str1, const sR3DString &str2);

#endif /* _R3D_STRING_H */
Advertisement

My favorite:


data[strlen(data)] = '\0';

StringCompare isn't any better. It can return -1 if the strings have different length... or if the first string is smaller (numerical-wise) than the later one!

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

Man, I was all set to come in here and go "WHYYYYYY would you do that?!", before I realized, wait, this is Coding Horrors.

I love it. But why only one kind of custom string?

You need one version that uses custom memory managers. You need another version that stores the string inside what would normally be the pointer if the string is small, you need a copy-on-write version, and you need a container-like string that is backed by a temporary file on disk or network rather than kept in memory all the time.

Seems like every major library includes their own variations of the string.

Or a single template version that does all those variations based on policy classes.


if (((from > 0) && (from <= strlen(str))) &&
((to > 0) && (to <= strlen(str))))

Well...

This is the reason why my rendering demo was crashing all the time, when it was rendering text based of this "nice" string implementation biggrin.png

I think i was at a brink to just forcing myself to write everything myself... for learning purposes...

Or a single template version that does all those variations based on policy classes.

Templates you say.... at the time, i had no f...... glue what templates are - it was that magic voodoo stuff biggrin.png

A thing of beauty.

I love it. But why only one kind of custom string?

You need one version that uses custom memory managers. You need another version that stores the string inside what would normally be the pointer if the string is small, you need a copy-on-write version, and you need a container-like string that is backed by a temporary file on disk or network rather than kept in memory all the time.

Seems like every major library includes their own variations of the string.

Don't forget the variant that only gets used when the string comes from the localization table. Oh, and all the variants are actually in the same class despite the fact that their behavior is subtly different, and you can only know which is which by looking not only at the place where any particular string was initialized, but ALSO looking in the localization table to determine if that string is defined properly for that particular language.

This topic is closed to new replies.

Advertisement