#if !defined(RREFOPT_STRING_HPP) #define RREFOPT_STRING_HPP #include #include #include #include #include namespace rrefopt { class string { private: enum { DEFAULT_BUF_SIZE = 64 }; private: char *buf; size_t buf_size; size_t str_length; public: string(char const *str = nullptr) throw (std::bad_alloc) : buf(nullptr), buf_size(0), str_length(0) { if (str) { size_t len = strlen(str); ensure_buf_size_at_least(len + 1); memcpy(buf, str, len + 1); str_length = len; } else { ensure_buf_size_at_least(1); buf[0] = '\0'; } } string(string const &from) throw (std::bad_alloc) : buf(nullptr), buf_size(0), str_length(0) { std::cerr << "copying: " << from << std::endl; internal_assign(from); } string(string &&from) throw () : buf(nullptr), buf_size(0), str_length(0) { std::cerr << "moving: " << from << std::endl; internal_move(from); } ~string() throw () { if (buf) { delete [] buf; } } string &operator=(string const &from) throw (std::bad_alloc) { if (this == &from) { return *this; } internal_assign(from); return *this; } string &operator=(string &&from) throw () { if (this == &from) { return *this; } internal_move(from); return *this; } string &operator+=(string const &with) throw (std::bad_alloc) { ensure_buf_size_at_least(str_length + with.str_length + 1); memcpy(buf + str_length, with.buf, with.str_length + 1); str_length += with.str_length; return *this; } friend string operator+(string const &a, string const &b) throw (std::bad_alloc) { std::cerr << "operator+(string const & a, string const &b) "; std::cerr << "[with a=\"" << a << "\" b=\"" << b << "\"]" << std::endl; string result(a); result += b; return result; } friend string &&operator+(string &&a, string const &b) throw (std::bad_alloc) { std::cerr << "operator+(string && a, string const &b) "; std::cerr << "[with a=\"" << a << "\" b=\"" << b << "\"]" << std::endl; a += b; return std::move(a); // I don't care } friend std::ostream &operator<<(std::ostream &os, string const &str) throw () { os << str.c_str(); return os; } char const *c_str() const throw () { return (buf) ? buf : ""; } private: void ensure_buf_size_at_least(size_t least_size) throw (std::bad_alloc) { if (buf_size >= least_size) { return; // ok, no need to resize } size_t buf_size_new = buf_size; if (buf_size_new == 0) { buf_size_new = DEFAULT_BUF_SIZE; } while (buf_size_new < least_size || buf_size_new < str_length) { buf_size_new <<= 1; } char *buf_new = new char[buf_size_new]; // may throw bad_alloc if (buf) { memcpy(buf_new, buf, str_length + 1); #ifdef DEFENSIVE_PROGRAMMING memset(buf_new + str_length, '\0', buf_size_new - str_length); #endif delete [] buf; } #ifdef DEFENSIVE_PROGRAMMING else { memset(buf_new, '\0', buf_size_new); } #endif buf = buf_new; buf_size = buf_size_new; } void internal_assign(string const &from) throw (std::bad_alloc) { ensure_buf_size_at_least(from.str_length + 1); memcpy(buf, from.buf, from.str_length + 1); str_length = from.str_length; } void internal_move(string &with) throw () { if (buf) { delete [] buf; } buf = with.buf; buf_size = with.buf_size; str_length = with.str_length; with.buf = nullptr; with.buf_size = 0; with.str_length = 0; } }; } // namespace rrefopt #endif // RREFOPT_STRING_HPP