00001
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
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 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00430 #endif // !GROOVX_RUTZ_FSTRING_CC_UTC20050626084020_DEFINED