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