#ifndef cmw_lil_string_hh #define cmw_lil_string_hh /* $Id: my_string.h 16 2007-12-07 17:43:41Z csl $ * * Copyright (C) Christian Stigen Larsen, 2007 * Placed in the Public Domain by the author. * * My go at writing a simple string class. * * You can probably replace std::string with this one in many * cases, but a lot of stuff is missing, and I would recommend * you stick to std::string anyway. * * I want to point out that there is nothing fancy about this class. * It keeps every string in its own buffer, and copies as often as * needed. * * However, I believe that is a good approach. For instance, it * uses malloc rather than new, which makes it possible to use * realloc. On many systems, realloc will try to use up "invisible" * space that was used by malloc to pad a string for memory alignment. * That makes it potentially fast for small concatenations. * * I don't propose to use this class for anything practical, since * we already have std::string, but it may be an interesting read * for C++ novices at the very least. * * If you're actually going to use this, at least inline c_str(), * empty(), size() and operator[], or even all of the one-line * functions. * * Please send bug reports and suggestions to * */ #include // malloc, realloc #include // strlen #include // size_t #include #include #include /* * Like new, we want to guarantee that we NEVER * return NULL. Loop until there is free memory. * */ static char* malloc_never_null (size_t const b) { char *p; do { p = static_cast(malloc(b)); } while ( p == NULL ); return p; } static char* strdup_never_null (char const* s) { size_t const len = strlen(s) + 1; char* p = malloc_never_null(len); memcpy(p, s, len); return p; } unsigned int const max_size = 255; class lil_string { char* p_; public: typedef size_t size_type; lil_string () : p_(strdup_never_null("")) {} ~lil_string () { free(p_); } #ifdef MOVE_CTORS lil_string (lil_string&& lstring) { p_ = lstring.p_; lstring.p_ = 0; } #endif lil_string (lil_string const& s) : p_(strdup_never_null(s.p_)) {} lil_string (char const* s) { if (strlen(s) > max_size) { throw ::std::out_of_range("lil_string::constructor: size limit violation"); } p_ = strdup_never_null(s); } template explicit lil_string (B& buf) { uint8_t slen; buf.Give(slen); p_ = malloc_never_null(slen + 1); buf.Give(p_, slen); p_[slen] = '\0'; } void CalculateMarshallingSize (Counter& cntr) const { cntr.Add(sizeof(uint8_t) + size()); } template void Marshal (B& buf, bool = false) const { uint8_t slen = size(); buf.Receive(&slen, sizeof(slen)); buf.Receive(c_str(), slen); } lil_string& operator= (char const* s) { if ( p_ != s ) { if (strlen(s) > max_size) { throw ::std::out_of_range("lil_string::operator= size limit violation"); } // this should work with overlapping memory char *copy = strdup_never_null(s); free(p_); p_ = copy; } return *this; } lil_string& operator= (lil_string const& s) { return operator=(s.p_); } void swap (lil_string& s) { ::std::swap(p_, s.p_); } lil_string& operator+= (lil_string const& s) { size_type const lenp = strlen(p_); size_type const lens = strlen(s.p_) + 1; if (lenp + lens > max_size) { throw ::std::out_of_range("lil_string::operator+= size limit violation"); } p_ = static_cast(realloc(p_, lenp + lens)); // could return NULL memmove(p_+lenp, s.p_, lens); // p and s.p MAY overlap return *this; } friend lil_string operator+ (lil_string const& lhs, lil_string const& rhs) { return lil_string(lhs) += rhs; } bool operator== (char const* s) const { return !strcmp(p_, s); } bool operator== (lil_string const& s) const { return !strcmp(p_, s.p_); } void clear () { free(p_); p_ = strdup_never_null(""); } void resize (size_type newsize) { if (newsize > max_size) { throw ::std::out_of_range("lil_string::resize size limit violation"); } free(p_); p_ = malloc_never_null(newsize + 1); } size_type size () const { return strlen(p_); } bool empty () const { return *p_ == '\0'; } char const* c_str () const { return p_; } lil_string substr (size_type const start, size_type const len_orig) const { lil_string s; size_type len = strlen(p_); if ( start > len ) throw ::std::out_of_range("lil_string::substr"); if ( len > len_orig ) len = len_orig; free(s.p_); s.p_ = malloc_never_null(len + 1); memcpy(s.p_, p_ + start, len); s.p_[len] = '\0'; return s; } // unchecked access char& operator[] (size_type const n) { return p_[n]; } // checked access char at (size_type const n) const { if ( n > strlen(p_) ) throw ::std::out_of_range("my::lil_string::at()"); return p_[n]; } lil_string& erase (size_type pos, size_type len) { size_type s = size(); if (pos > s) throw ::std::out_of_range("my::lil_string::erase"); s -= pos; if (len > s) len = s; ++s; // erase by overwriting memmove(p_ + pos, p_ + pos + len, s); // remove unused space p_ = static_cast(realloc(p_, s+pos)); return *this; } }; #endif