fstring.cc

Go to the documentation of this file.
00001 /** @file rutz/fstring.cc ref-counted string type that allows much
00002     faster compile times than std::string */
00003 
00004 ///////////////////////////////////////////////////////////////////////
00005 //
00006 // Copyright (c) 2000-2004 California Institute of Technology
00007 // Copyright (c) 2004-2007 University of Southern California
00008 // Rob Peters <rjpeters at usc dot edu>
00009 //
00010 // created: Fri Oct 15 15:43:41 2004
00011 // commit: $Id: fstring.cc 8249 2007-04-12 06:03:40Z rjpeters $
00012 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/fstring.cc $
00013 //
00014 // --------------------------------------------------------------------
00015 //
00016 // This file is part of GroovX.
00017 //   [http://ilab.usc.edu/rjpeters/groovx/]
00018 //
00019 // GroovX is free software; you can redistribute it and/or modify it
00020 // under the terms of the GNU General Public License as published by
00021 // the Free Software Foundation; either version 2 of the License, or
00022 // (at your option) any later version.
00023 //
00024 // GroovX is distributed in the hope that it will be useful, but
00025 // WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027 // General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU General Public License
00030 // along with GroovX; if not, write to the Free Software Foundation,
00031 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
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 // rutz::string_rep member definitions
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); // includes add_terminator()
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 // fstring member definitions
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   // Check if we are pointing to the same string
00357   if (c_str() == other) return false;
00358   // ...otherwise do a string compare
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   // Check if we are pointing to the same string
00366   if (c_str() == other) return false;
00367   // ...otherwise do a string compare
00368   return strcmp(c_str(), other) > 0;
00369 }
00370 
00371 //---------------------------------------------------------------------
00372 //
00373 // Input/Output function definitions
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://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/fstring.cc $";
00430 #endif // !GROOVX_RUTZ_FSTRING_CC_UTC20050626084020_DEFINED
Generated on Sun May 8 08:42:09 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3