00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 #ifndef GROOVX_RUTZ_FSTRING_CC_UTC20050626084020_DEFINED
00036 #define GROOVX_RUTZ_FSTRING_CC_UTC20050626084020_DEFINED
00037 
00038 #include "fstring.h"
00039 
00040 #include "rutz/algo.h"
00041 #include "rutz/compat_snprintf.h"
00042 #include "rutz/freelist.h"
00043 #include "rutz/mutex.h"
00044 
00045 #include <cctype>
00046 #include <cstring>
00047 #include <istream>
00048 #include <ostream>
00049 #include <pthread.h>
00050 
00051 #ifndef GVX_NO_PROF
00052 #define GVX_NO_PROF
00053 #endif
00054 
00055 #include "rutz/trace.h"
00056 #include "rutz/debug.h"
00057 GVX_DBG_REGISTER
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 namespace
00066 {
00067   rutz::free_list<rutz::string_rep>* g_rep_list;
00068   pthread_mutex_t g_rep_list_mutex = PTHREAD_MUTEX_INITIALIZER;
00069 }
00070 
00071 void* rutz::string_rep::operator new(size_t bytes)
00072 {
00073   GVX_MUTEX_LOCK(&g_rep_list_mutex);
00074   if (g_rep_list == 0) g_rep_list = new rutz::free_list<rutz::string_rep>;
00075   return g_rep_list->allocate(bytes);
00076 }
00077 
00078 void rutz::string_rep::operator delete(void* space)
00079 {
00080   GVX_MUTEX_LOCK(&g_rep_list_mutex);
00081   g_rep_list->deallocate(space);
00082 }
00083 
00084 rutz::string_rep::string_rep(std::size_t len, const char* txt,
00085                              std::size_t capac) :
00086   m_refcount(),
00087   m_capacity(rutz::max(len+1, capac)),
00088   m_length(0),
00089   m_text(new char[m_capacity])
00090 {
00091   m_refcount.atomic_set(0);
00092 
00093   if (txt)
00094     uniq_append(len, txt);
00095   else
00096     add_terminator();
00097 }
00098 
00099 rutz::string_rep::~string_rep() throw()
00100 {
00101 GVX_TRACE("rutz::string_rep::~string_rep");
00102 
00103   delete [] m_text;
00104   m_text = (char*)0xdeadbeef;
00105 }
00106 
00107 rutz::string_rep* rutz::string_rep::make(std::size_t length,
00108                                          const char* text,
00109                                          std::size_t capacity)
00110 {
00111   return new rutz::string_rep(length, text, capacity);
00112 }
00113 
00114 rutz::string_rep* rutz::string_rep::read_from_stream(std::istream& is)
00115 {
00116   rutz::string_rep* result = rutz::string_rep::make(0, 0, 32);
00117   is >> std::ws;
00118   while ( true )
00119     {
00120       int c = is.get();
00121       if (c == EOF || isspace(c))
00122         {
00123           is.unget();
00124           break;
00125         }
00126       result->uniq_append_no_terminate(char(c));
00127     }
00128   result->add_terminator();
00129 
00130   return result;
00131 }
00132 
00133 rutz::string_rep* rutz::string_rep::readsome_from_stream(std::istream& is, unsigned int count)
00134 {
00135   rutz::string_rep* result = rutz::string_rep::make(0, 0, count+2);
00136 
00137   if (count > 0)
00138     {
00139       unsigned int numread = is.readsome(result->m_text, count);
00140       result->uniq_set_length(numread); 
00141     }
00142 
00143   return result;
00144 }
00145 
00146 rutz::string_rep* rutz::string_rep::readline_from_stream(std::istream& is, char eol)
00147 {
00148   rutz::string_rep* result = rutz::string_rep::make(0, 0, 32);
00149 
00150   while ( true )
00151     {
00152       int c = is.get();
00153       if (c == EOF || c == eol)
00154         break;
00155       result->uniq_append_no_terminate(char(c));
00156     }
00157 
00158   result->add_terminator();
00159 
00160   return result;
00161 }
00162 
00163 void rutz::string_rep::debug_dump() const throw()
00164 {
00165   dbg_eval_nl(0, (const void*)this);
00166   dbg_eval_nl(0, m_refcount.atomic_get());
00167   dbg_eval_nl(0, m_length);
00168   dbg_eval_nl(0, (void*)m_text);
00169   dbg_eval_nl(0, m_text);
00170   for (unsigned int i = 0; i < m_length; ++i)
00171     dbg_print(0, (void*)(size_t)m_text[i]);
00172   dbg_print_nl(0, "");
00173 }
00174 
00175 void rutz::string_rep::uniq_append_no_terminate(char c)
00176 {
00177   if (m_length + 2 <= m_capacity)
00178     {
00179       m_text[m_length++] = c;
00180     }
00181   else
00182     {
00183       uniq_realloc(m_length + 2);
00184       m_text[m_length++] = c;
00185     }
00186 }
00187 
00188 void rutz::string_rep::add_terminator() throw()
00189 {
00190   m_text[m_length] = '\0';
00191 }
00192 
00193 void rutz::string_rep::uniq_set_length(std::size_t len) throw()
00194 {
00195   GVX_PRECONDITION(m_refcount.atomic_get() <= 1);
00196   GVX_PRECONDITION(len+1 < m_capacity);
00197   m_length = len;
00198   add_terminator();
00199 }
00200 
00201 void rutz::string_rep::uniq_append(std::size_t len, const char* txt)
00202 {
00203   GVX_PRECONDITION(m_refcount.atomic_get() <= 1);
00204   GVX_PRECONDITION(txt != 0);
00205 
00206   if (m_length + len + 1 <= m_capacity)
00207     {
00208       memcpy(m_text+m_length, txt, len);
00209       m_length += len;
00210       add_terminator();
00211     }
00212   else
00213     {
00214       uniq_realloc(m_length + len + 1);
00215       uniq_append(len, txt);
00216     }
00217 
00218   GVX_POSTCONDITION(m_length+1 <= m_capacity);
00219   GVX_POSTCONDITION(m_text[m_length] == '\0');
00220 }
00221 
00222 void rutz::string_rep::uniq_realloc(std::size_t capac)
00223 {
00224   GVX_PRECONDITION(m_refcount.atomic_get() <= 1);
00225 
00226   rutz::string_rep new_rep(rutz::max(m_capacity*2 + 32, capac), 0);
00227 
00228   new_rep.uniq_append(this->m_length, this->m_text);
00229 
00230   rutz::swap2(m_capacity, new_rep.m_capacity);
00231   rutz::swap2(m_length, new_rep.m_length);
00232   rutz::swap2(m_text, new_rep.m_text);
00233 }
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 void rutz::fstring::init_empty()
00242 {
00243 GVX_TRACE("rutz::fstring::init_empty");
00244   GVX_PRECONDITION(m_rep == 0);
00245 
00246   m_rep = string_rep::make(0, 0);
00247 
00248   m_rep->incr_ref_count();
00249 }
00250 
00251 void rutz::fstring::init_range(char_range r)
00252 {
00253 GVX_TRACE("rutz::fstring::init_range");
00254   GVX_PRECONDITION(m_rep == 0);
00255 
00256   m_rep = string_rep::make(r.len, r.text);
00257 
00258   m_rep->incr_ref_count();
00259 }
00260 
00261 rutz::fstring::fstring(rutz::string_rep* r)
00262   :
00263   m_rep(r)
00264 {
00265 GVX_TRACE("rutz::fstring::fstring(string_rep*)");
00266   m_rep->incr_ref_count();
00267 }
00268 
00269 rutz::fstring::fstring() :
00270   m_rep(string_rep::make(0,0))
00271 {
00272 GVX_TRACE("rutz::fstring::fstring");
00273 
00274   m_rep->incr_ref_count();
00275 }
00276 
00277 rutz::fstring::fstring(const rutz::fstring& other) throw() :
00278   m_rep(other.m_rep)
00279 {
00280 GVX_TRACE("rutz::fstring::fstring(const fstring&)");
00281   m_rep->incr_ref_count();
00282 }
00283 
00284 rutz::fstring::~fstring() throw()
00285 {
00286 GVX_TRACE("rutz::fstring::~fstring");
00287 
00288   dbg_dump(7, *this);
00289 
00290   if (m_rep->decr_ref_count() == 0)
00291     m_rep = (string_rep*)0xdeadbeef;
00292 }
00293 
00294 void rutz::fstring::swap(rutz::fstring& other) throw()
00295 {
00296 GVX_TRACE("rutz::fstring::swap");
00297 
00298   rutz::swap2(m_rep, other.m_rep);
00299 }
00300 
00301 rutz::fstring& rutz::fstring::operator=(const char* text)
00302 {
00303 GVX_TRACE("rutz::fstring::operator=(const char*)");
00304 
00305   fstring copy(text);
00306   this->swap(copy);
00307   return *this;
00308 }
00309 
00310 rutz::fstring& rutz::fstring::operator=(const fstring& other) throw()
00311 {
00312 GVX_TRACE("rutz::fstring::operator=(const fstring&)");
00313 
00314   rutz::fstring copy(other);
00315   this->swap(copy);
00316   return *this;
00317 }
00318 
00319 bool rutz::fstring::ends_with(const fstring& ext) const throw()
00320 {
00321 GVX_TRACE("rutz::fstring::ends_with");
00322   if (ext.length() > this->length())
00323     return false;
00324 
00325   unsigned int skip = this->length() - ext.length();
00326 
00327   return ext.equals(this->c_str() + skip);
00328 }
00329 
00330 void rutz::fstring::clear()
00331 {
00332 GVX_TRACE("rutz::fstring::clear");
00333 
00334   fstring().swap(*this);
00335 }
00336 
00337 bool rutz::fstring::equals(const char* other) const throw()
00338 {
00339 GVX_TRACE("rutz::fstring::equals(const char*)");
00340   return ( c_str() == other ||
00341            strcmp(c_str(), other) == 0 );
00342 }
00343 
00344 bool rutz::fstring::equals(const fstring& other) const throw()
00345 {
00346 GVX_TRACE("rutz::fstring::equals(const fstring&)");
00347 
00348   return c_str() == other.c_str() ||
00349     ( length() == other.length() &&
00350       strcmp(c_str(), other.c_str()) == 0 );
00351 }
00352 
00353 bool rutz::fstring::operator<(const char* other) const throw()
00354 {
00355 GVX_TRACE("rutz::fstring::operator<");
00356   
00357   if (c_str() == other) return false;
00358   
00359   return strcmp(c_str(), other) < 0;
00360 }
00361 
00362 bool rutz::fstring::operator>(const char* other) const throw()
00363 {
00364 GVX_TRACE("rutz::fstring::operator>");
00365   
00366   if (c_str() == other) return false;
00367   
00368   return strcmp(c_str(), other) > 0;
00369 }
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 void rutz::fstring::read(std::istream& is)
00378 {
00379 GVX_TRACE("rutz::fstring::read");
00380   rutz::fstring(string_rep::read_from_stream(is)).swap(*this);
00381 }
00382 
00383 void rutz::fstring::readsome(std::istream& is, unsigned int count)
00384 {
00385 GVX_TRACE("rutz::fstring::readsome");
00386   rutz::fstring(string_rep::readsome_from_stream(is, count)).swap(*this);
00387 }
00388 
00389 void rutz::fstring::write(std::ostream& os) const
00390 {
00391 GVX_TRACE("rutz::fstring::write");
00392   os.write(c_str(), length());
00393 }
00394 
00395 void rutz::fstring::readline(std::istream& is, char eol)
00396 {
00397 GVX_TRACE("rutz::fstring::readline");
00398   rutz::fstring(string_rep::readline_from_stream(is, eol)).swap(*this);
00399 }
00400 
00401 void rutz::fstring::debug_dump() const throw()
00402 {
00403   dbg_eval_nl(0, (const void*)this);
00404   m_rep->debug_dump();
00405 }
00406 
00407 using rutz::fstring;
00408 
00409 fstring rutz::sconvert(char x)          { return fstring(rutz::char_range(&x, 1)); }
00410 fstring rutz::sconvert(const char* x)   { return fstring(x); }
00411 fstring rutz::sconvert(const fstring& x){ return x; }
00412 
00413 #define NUM_CONVERT(fmt, val)                   \
00414   const int SZ = 64;                            \
00415   char buf[SZ];                                 \
00416   int n = snprintf(buf, SZ, fmt, (val));        \
00417   GVX_ASSERT(n > 0 && n < SZ);                  \
00418   return fstring(&buf[0]);
00419 
00420 fstring rutz::sconvert(bool x)          { NUM_CONVERT("%d", int(x)) }
00421 fstring rutz::sconvert(int x)           { NUM_CONVERT("%d", x) }
00422 fstring rutz::sconvert(unsigned int x)  { NUM_CONVERT("%u", x) }
00423 fstring rutz::sconvert(long x)          { NUM_CONVERT("%ld", x) }
00424 fstring rutz::sconvert(unsigned long x) { NUM_CONVERT("%lu", x) }
00425 fstring rutz::sconvert(double x)        { NUM_CONVERT("%g", x) }
00426 
00427 #undef NUM_CONVERT
00428 
00429 static const char __attribute__((used)) vcid_groovx_rutz_fstring_cc_utc20050626084020[] = "$Id: fstring.cc 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn:
00430 #endif // !GROOVX_RUTZ_FSTRING_CC_UTC20050626084020_DEFINED