7
\$\begingroup\$

I've ported some standard library facilities like vector, algorithm, etc. to my kernel so I can code in C++ instead of C. This is one of them. I'm looking for concerns regarding:

  • Performance
  • Safety
  • Friendly interface

Perhaps there are more idiomatic ways to accomplish what I'm going for?

#ifndef _LIBCPP_STRING_H_
#define _LIBCPP_STRING_H_

#include <prefix.h>
#include <libc/stddef.h>
#include <libc/string.h>
#include <libc/stdint.h>

#include "algorithm.h"

namespace std
{
    template<size_t Size>
    class fixed_string
    {
    public:
        static constexpr size_t npos = static_cast<size_t>(UINT32_MAX);

        fixed_string() :
            _length(0)
        {
            _buffer[0] = '\0';
        }
        fixed_string(const char *string)
        {
            assign(string, strlen(string));
        }
        fixed_string(const fixed_string &other)
        {
            assign(other._buffer, other._length);
        }


        fixed_string &operator =(const fixed_string &other)
        {
            assign(other._buffer, other._length);
            return *this;
        }
        fixed_string &operator =(const char *string)
        {
            assign(string, strlen(string));
            return *this;
        }


        bool operator ==(const fixed_string &other) const
        {
            if(_length != other._length)
                return false;

            return (strcmp(other._buffer, _buffer) == 0);
        }
        bool operator ==(const char *string) const
        {
            return (strcmp(string, _buffer) == 0);
        }

        bool operator !=(const fixed_string &other) const
        {
            return !(*this == other);
        }
        bool operator !=(const char *string) const
        {
            return !(*this == string);
        }


        size_t find(const fixed_string &other) const
        {
            return find(other._buffer, _length);
        }
        size_t find(const char *other) const
        {
            return find(other, strlen(other));
        }
        size_t find(const char *other, size_t length) const
        {
            size_t found  = 0;

            char *buffer = _buffer;
            while(*buffer)
            {
                if(found >= length)
                {
                    size_t diff = ((buffer - found) - _buffer);
                    return diff;
                }

                found = (*buffer == other[found]) ? found + 1 : 0;
                buffer ++;
            }

            return npos;
        }

        const char *c_str() const { return _buffer; }
        size_t length() const { return _length; }

    private:
        void assign(const char *string, size_t length)
        {
            if(!string)
            {
                _buffer[0] = '\0';
                _length = 0;

                return;
            }

            _length = std::min(length, Size);
            strlcpy(_buffer, string, _length);
        }

        char _buffer[Size + 1];
        size_t _length;
    };
}

#endif /* _LIBCPP_STRING_H_ */
\$\endgroup\$
3
\$\begingroup\$

In operator=(), you should always first check to see whether you're doing a self-assignment and do an early exit:

fixed_string &operator =(const fixed_string &other)
{
    if (this == &other) {
        return *this;
    }
    assign(other._buffer, other._length);
    return *this;
}

I would write the found assignment as the more explicit:

if (*buffer == other[found]) {
    found++;
} else {
    found = 0;
}

The compiler will generate the equivalent code to yours.

In fact, your find has a bug. Consider:

fixed_string<10> a = "abcabcd";
assert(a.find("abcd") == 3);

Your assign method calls strlcpy incorrectly. Instead of calling with _length as the third parameter, use the actual size of the buffer:

strlcpy(_buffer, string, sizeof(_buffer));

As a matter of style, I would always surround conditional blocks with braces, even if they only contain one statement:

bool operator ==(const fixed_string &other) const
{
    if(_length != other._length) {
        return false;
    }
    // ...
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.