From: Lars Gullik Bjønnes Date: Fri, 22 Oct 1999 02:26:50 +0000 (+0000) Subject: moved Srep definition to lyxstring.C X-Git-Tag: 1.6.10~22589 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=5117a9df99c18e970485fd1acf57cc0f6bb3c772;p=features.git moved Srep definition to lyxstring.C git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@224 a592a061-630c-0410-9148-cb99ea01b6c8 --- diff --git a/ChangeLog b/ChangeLog index 740ad21086..25c0b69247 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 1999-10-22 Lars Gullik Bjønnes + * src/support/lyxstring.C: moved the definition of lyxstring::Srep + to lyxstring.C, and only keep a forward declaration in + lyxstring.h. Simplifies the header file a bit and should help a + bit on compile time too. Also changes to Srep will not mandate a + recompile of code just using string. + (~lyxstring): definition moved here since it uses srep. + (size): definition moved here since it uses srep. + * src/support/lyxstring.h: removed a couple of "inline" that should not be there. diff --git a/src/support/lyxstring.C b/src/support/lyxstring.C index c76af29334..3cd13e4771 100644 --- a/src/support/lyxstring.C +++ b/src/support/lyxstring.C @@ -25,6 +25,12 @@ using std::min; +// This class is supposed to be functionaly equivalent to a +// standard conformant string. This mean among others that we +// are useing the same requirements. Before you change anything +// in this file consult me and/or the standard to discover the +// right behavior. + // Reference count has been checked, empty_rep removed and // introduced again in a similar guise. Where is empty_rep _really_ // needed? @@ -36,104 +42,62 @@ using std::min; // I have so far not tested them extensively and would be // happy if others took the time to have a peek. -#ifdef WITH_WARNINGS -#warning temporarily here for debugging purposes only -#endif -lyxstring::size_type lyxstring::size() const -{ - return rep->sz; -} - -//-------------------------------------------------------------------------- -// lyxstringInvariant -#ifdef DEVEL_VERSION +/////////////////////////////////////// +// The internal string representation +/////////////////////////////////////// -/** Testing of the lyxstring invariant - * By creating an object that tests the lyxstring invariant during its - * construction *and* its deconstruction we greatly simplify our code. - * Calling TestlyxstringInvariant() upon entry to an lyxstring method - * will test the invariant upon entry to the code. If the Asserts fail - * then we know from the stack trace that the corruption occurred *before* - * entry to this method. We can also be sure it didn't happen in any of - * the tested lyxstring methods. It is therefore likely to be due to some - * other external force. - * Several lyxstring methods have multiple exit points which would otherwise - * require us to insert a separate test before each return. But since we - * created an object its destructor will be called upon exit (any exit!). - * We thus get testing at both start and end of a method with one line of - * code at the head of a method. More importantly, we get good testing - * everytime we run the code. - * NOTE: just because we test the invariant doesn't mean we can forget - * about testing pre and post conditions specific to any given method. - * This test simply proves that the lyxstring/Srep is in a valid state it - * does *not* prove that the method did what it was supposed to. - */ -class lyxstringInvariant -{ -public: - lyxstringInvariant(lyxstring const *); - ~lyxstringInvariant(); +struct lyxstring::Srep { + /// + static lyxstring::size_type const xtra = + static_cast(8); + /// size + lyxstring::size_type sz; + /// Reference count + unsigned short ref; + /// The total amount of data reserved for this representaion + lyxstring::size_type res; + /// Data. At least 1 char for trailing null. + lyxstring::value_type * s; + + /// + Srep(lyxstring::size_type nsz, const lyxstring::value_type * p); + /// + Srep(lyxstring::size_type nsz, lyxstring::value_type ch); + /// + ~Srep() { delete[] s; } + /// + Srep * get_own_copy() + { + if (ref == 1) return this; + ref--; + return new Srep(sz, s); + } + + /// + void assign(lyxstring::size_type nsz, const lyxstring::value_type * p); + /// + void assign(lyxstring::size_type nsz, lyxstring::value_type ch); + /// + void append(lyxstring::size_type asz, const lyxstring::value_type * p); + /// + void push_back(lyxstring::value_type c); + /// + void insert(lyxstring::size_type pos, + const lyxstring::value_type * p, + lyxstring::size_type n); + /// + void resize(lyxstring::size_type n, lyxstring::value_type c); + /// + void reserve(lyxstring::size_type res_arg); + /// + void replace(lyxstring::size_type i, lyxstring::size_type n, + lyxstring::value_type const * p, lyxstring::size_type n2); private: - void helper() const; - lyxstring const * object; + Srep(const Srep &); + Srep & operator=(const Srep &); }; -// To test if this scheme works "as advertised" uncomment the printf's in -// the constructor and destructor below and then uncomment the printf and the -// call to TestlyxstringInvariant() in lyxstring::operator=(char const *). -// The correct output when LyX has been recompiled and run is: -// lyxstringInvariant constructor -// lyxstring::operator=(char const *) -// lyxstringInvariant constructor -// lyxstringInvariant destructor completed -// lyxstringInvariant destructor completed -// NOTE: The easiest way to catch this snippet of the output is to wait for -// the splash screen to disappear and then open and close Help->Credits -// -lyxstringInvariant::lyxstringInvariant(lyxstring const * ls) : object(ls) -{ -// printf("lyxstringInvariant constructor\n"); - helper(); -} - -lyxstringInvariant::~lyxstringInvariant() -{ - helper(); -// printf("lyxstringInvariant destructor completed\n"); -} - -void lyxstringInvariant::helper() const -{ - // Some of these tests might look pointless but they are - // all part of the invariant and if we want to make sure - // we have a bullet proof implementation then we need to - // test every last little thing we *know* should be true. - // I may have missed a test or two, so feel free to fill - // in the gaps. ARRae. - // NOTE: Don't put TestlyxstringInvariant() in any of the - // lyxstring methods used below otherwise you'll get an - // infinite recursion and a crash. - Assert(object); - Assert(object->rep); - Assert(object->rep->s); // s is never 0 - Assert(object->rep->res); // always some space allocated - Assert(object->size() <= object->rep->res); - Assert(object->rep->ref >= 1); // its in use so it must be referenced - Assert(object->rep->ref < (1 << 8*sizeof(object->rep->ref)) - 1); - // if it does ever == then we should be generating a new copy - // and starting again. (Is char always 8-bits?) -} -#define TestlyxstringInvariant(s) lyxstringInvariant lyxstring_invariant(s); -#else -#define TestlyxstringInvariant(s) -#endif //DEVEL_VERSION -//------------------------------------------------------------------------- - -/////////////////////////////////////// -// Constructors and Deconstructors. -/////////////////////////////////////// - lyxstring::Srep::Srep(lyxstring::size_type nsz, const value_type * p) { @@ -313,6 +277,96 @@ void lyxstring::Srep::replace(lyxstring::size_type i, lyxstring::size_type n, } +/////////////////////////////////////// +// The lyxstring Invariant tester +/////////////////////////////////////// +#ifdef DEVEL_VERSION + +/** Testing of the lyxstring invariant + * By creating an object that tests the lyxstring invariant during its + * construction *and* its deconstruction we greatly simplify our code. + * Calling TestlyxstringInvariant() upon entry to an lyxstring method + * will test the invariant upon entry to the code. If the Asserts fail + * then we know from the stack trace that the corruption occurred *before* + * entry to this method. We can also be sure it didn't happen in any of + * the tested lyxstring methods. It is therefore likely to be due to some + * other external force. + * Several lyxstring methods have multiple exit points which would otherwise + * require us to insert a separate test before each return. But since we + * created an object its destructor will be called upon exit (any exit!). + * We thus get testing at both start and end of a method with one line of + * code at the head of a method. More importantly, we get good testing + * everytime we run the code. + * NOTE: just because we test the invariant doesn't mean we can forget + * about testing pre and post conditions specific to any given method. + * This test simply proves that the lyxstring/Srep is in a valid state it + * does *not* prove that the method did what it was supposed to. + */ +class lyxstringInvariant { +public: + lyxstringInvariant(lyxstring const *); + ~lyxstringInvariant(); +private: + void helper() const; + lyxstring const * object; +}; + + +// To test if this scheme works "as advertised" uncomment the printf's in +// the constructor and destructor below and then uncomment the printf and the +// call to TestlyxstringInvariant() in lyxstring::operator=(char const *). +// The correct output when LyX has been recompiled and run is: +// lyxstringInvariant constructor +// lyxstring::operator=(char const *) +// lyxstringInvariant constructor +// lyxstringInvariant destructor completed +// lyxstringInvariant destructor completed +// NOTE: The easiest way to catch this snippet of the output is to wait for +// the splash screen to disappear and then open and close Help->Credits +// +lyxstringInvariant::lyxstringInvariant(lyxstring const * ls) : object(ls) +{ + // printf("lyxstringInvariant constructor\n"); + helper(); +} + +lyxstringInvariant::~lyxstringInvariant() +{ + helper(); + // printf("lyxstringInvariant destructor completed\n"); +} + +void lyxstringInvariant::helper() const +{ + // Some of these tests might look pointless but they are + // all part of the invariant and if we want to make sure + // we have a bullet proof implementation then we need to + // test every last little thing we *know* should be true. + // I may have missed a test or two, so feel free to fill + // in the gaps. ARRae. + // NOTE: Don't put TestlyxstringInvariant() in any of the + // lyxstring methods used below otherwise you'll get an + // infinite recursion and a crash. + Assert(object); + Assert(object->rep); + Assert(object->rep->s); // s is never 0 + Assert(object->rep->res); // always some space allocated + Assert(object->size() <= object->rep->res); + Assert(object->rep->ref >= 1); // its in use so it must be referenced + Assert(object->rep->ref < (1 << 8*sizeof(object->rep->ref)) - 1); + // if it does ever == then we should be generating a new copy + // and starting again. (Is char always 8-bits?) +} +#define TestlyxstringInvariant(s) lyxstringInvariant lyxstring_invariant(s); +#else +#define TestlyxstringInvariant(s) +#endif //DEVEL_VERSION + + +/////////////////////////////////////// +// Constructors and Deconstructors. +/////////////////////////////////////// + lyxstring::size_type const lyxstring::npos = static_cast(-1); lyxstring::lyxstring() @@ -373,6 +427,11 @@ lyxstring::lyxstring(iterator first, iterator last) } +lyxstring::~lyxstring() +{ + if (--rep->ref == 0) delete rep; +} + /////////////////////// // Iterators /////////////////////// @@ -425,10 +484,17 @@ const_reverse_iterator lyxstring::rend() const } #endif + /////////////////////// // Size and Capacity /////////////////////// +lyxstring::size_type lyxstring::size() const +{ + return rep->sz; +} + + void lyxstring::resize(size_type n, value_type c) { TestlyxstringInvariant(this); @@ -563,7 +629,6 @@ lyxstring & lyxstring::assign(iterator first, iterator last) lyxstring::const_reference lyxstring::operator[](size_type pos) const { Assert(pos < rep->sz); - return rep->s[pos]; } @@ -581,7 +646,6 @@ lyxstring::reference lyxstring::operator[](size_type pos) lyxstring::const_reference lyxstring::at(size_type n) const { Assert(n < rep->sz); - return rep->s[n]; } @@ -1103,7 +1167,8 @@ lyxstring::size_type lyxstring::find_first_not_of(value_type const * ptr, } -lyxstring::size_type lyxstring::find_first_not_of(value_type c, size_type i) const +lyxstring::size_type lyxstring::find_first_not_of(value_type c, + size_type i) const { if (!rep->sz) return npos; Assert(i < rep->sz); @@ -1117,7 +1182,7 @@ lyxstring::size_type lyxstring::find_first_not_of(value_type c, size_type i) con lyxstring::size_type lyxstring::find_last_not_of(lyxstring const & a, - size_type i) const + size_type i) const { TestlyxstringInvariant(this); @@ -1147,7 +1212,7 @@ lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr, lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr, - size_type i) const + size_type i) const { Assert(ptr); TestlyxstringInvariant(this); @@ -1160,7 +1225,8 @@ lyxstring::size_type lyxstring::find_last_not_of(value_type const * ptr, } -lyxstring::size_type lyxstring::find_last_not_of(value_type c, size_type i) const +lyxstring::size_type lyxstring::find_last_not_of(value_type c, + size_type i) const { TestlyxstringInvariant(this); @@ -1185,8 +1251,8 @@ lyxstring & lyxstring::replace(size_type i, size_type n, lyxstring const & x) } -lyxstring & lyxstring::replace(size_type i,size_type n, lyxstring const & x, - size_type i2, size_type n2) +lyxstring & lyxstring::replace(size_type i,size_type n, lyxstring const & x, + size_type i2, size_type n2) { Assert((i < rep->sz || i == 0) && (i2 < x.rep->sz || i2 == 0)); TestlyxstringInvariant(this); @@ -1197,8 +1263,8 @@ lyxstring & lyxstring::replace(size_type i,size_type n, lyxstring const & x, } -lyxstring & lyxstring::replace(size_type i, size_type n, value_type const * p, - size_type n2) +lyxstring & lyxstring::replace(size_type i, size_type n, + value_type const * p, size_type n2) { Assert(p && i < rep->sz); TestlyxstringInvariant(this); @@ -1218,7 +1284,8 @@ lyxstring & lyxstring::replace(size_type i, size_type n, value_type const * p) } -lyxstring & lyxstring::replace(size_type i, size_type n, size_type n2, value_type c) +lyxstring & lyxstring::replace(size_type i, size_type n, + size_type n2, value_type c) { Assert(i < rep->sz); TestlyxstringInvariant(this); @@ -1241,7 +1308,7 @@ lyxstring & lyxstring::replace(iterator i, iterator i2, const lyxstring & str) lyxstring & lyxstring::replace(iterator i, iterator i2, - value_type const * p, size_type n) + value_type const * p, size_type n) { Assert(p); TestlyxstringInvariant(this); @@ -1259,7 +1326,8 @@ lyxstring & lyxstring::replace(iterator i, iterator i2, value_type const * p) } -lyxstring & lyxstring::replace(iterator i, iterator i2, size_type n , value_type c) +lyxstring & lyxstring::replace(iterator i, iterator i2, + size_type n , value_type c) { TestlyxstringInvariant(this); @@ -1267,7 +1335,8 @@ lyxstring & lyxstring::replace(iterator i, iterator i2, size_type n , value_type } -lyxstring & lyxstring::replace(iterator i, iterator i2, iterator j, iterator j2) +lyxstring & lyxstring::replace(iterator i, iterator i2, + iterator j, iterator j2) { TestlyxstringInvariant(this); @@ -1329,7 +1398,8 @@ lyxstring::value_type const * lyxstring::data() const } -lyxstring::size_type lyxstring::copy(value_type * buf, size_type len, size_type pos) const +lyxstring::size_type lyxstring::copy(value_type * buf, size_type len, + size_type pos) const { Assert(buf); TestlyxstringInvariant(this); @@ -1421,7 +1491,6 @@ lyxstring lyxstring::substr(size_type i, size_type n) const } - ///////////////////////////////////////////// // String operators, non member functions ///////////////////////////////////////////// diff --git a/src/support/lyxstring.h b/src/support/lyxstring.h index 85ca222032..d78adfe03f 100644 --- a/src/support/lyxstring.h +++ b/src/support/lyxstring.h @@ -12,6 +12,12 @@ // This one is heavily based on the string class in The C++ // Programming Language by Bjarne Stroustrup +// This class is supposed to be functionaly equivalent to a +// standard conformant string. This mean among others that we +// are useing the same requirements. Before you change anything +// in this file consult me and/or the standard to discover the +// right behavior. + #ifndef LYXSTRING_H #define LYXSTRING_H @@ -27,29 +33,30 @@ #include #endif -#include -#include "LAssert.h" +#include // for size_t + /** A string class for LyX This is a permanent String class. It is modeled closely after the C++ STL - string class. In comparison with STL string LString lack support for - reverse iterators and allocators, in all other senses it is written to be - a drop in replacement for STL string (or as a transition tool). So - documentation for STL string should be valid for LString too. + string class. In comparison with STL string lyxstring lack support for + reverse iterators and allocators, also char_traits is not used. In most + other senses it is written to be a drop in replacement for STL string + (or as a transition tool). So documentation for STL string should be + valid for lyxstring too. Notes for usage: - When you declare an LString, it is initially empty. There is no need to - do things like #LString a= "";#, especially not in constructors. + When you declare an lyxstring, it is initially empty. There is no need to + do things like #lyxstring a= "";#, especially not in constructors. - If you want to use a default empty LString as a parameter, use + If you want to use a default empty lyxstring as a parameter, use - #void foo(LString par = LString()); // Correct# + #void foo(lyxstring par = lyxstring()); // Correct# rather than - #void foo(LString par = ""); // WRONG!# - #void foo(LString par = 0); // WRONG!# + #void foo(lyxstring par = ""); // WRONG!# + #void foo(lyxstring par = 0); // WRONG!# (The last one is only wrong because some compilers can't handle it.) @@ -60,7 +67,7 @@ Wrong: & #bar.substring(0, length());# \end{tabular} - It is important that you declare LStrings as const if possible, because + It is important that you declare lyxstring as const if possible, because some methods are much more efficient in const versions. If you want to check whether a string is empty, do @@ -71,15 +78,15 @@ #if (!foo) completely wrong# -When you want to copy an LString, just do +When you want to copy an lyxstring, just do - #LString a, b = "String";# + #lyxstring a, b = "String";# #a = b; // That's it!# not something like - #LString a, b = "String";# - #a = b.copy(); // This leaks.# + #lyxstring a, b = "String";# + #a = b.copy(); // This leaks. // and does not work either. # The class automatically handles deep copying when required. */ @@ -113,10 +120,10 @@ public: #if 0 /// typedef reverse_iterator -reverse_iterator; + reverse_iterator; /// typedef reverse_iterator const_reverse_iterator; + const_reference> const_reverse_iterator; #endif //@} @@ -167,7 +174,7 @@ const_reference> const_reverse_iterator; lyxstring(iterator first, iterator last); /// - ~lyxstring() { if (--rep->ref == 0) delete rep; } + ~lyxstring(); //@} @@ -176,7 +183,7 @@ const_reference> const_reverse_iterator; //@{ /// number of characters - size_type size() const; // { return rep->sz; } + size_type size() const; /// largest possible string size_type max_size() const { return npos -1; } @@ -201,7 +208,6 @@ const_reference> const_reverse_iterator; //@} - /**@name Assignment */ //@{ @@ -251,7 +257,6 @@ const_reference> const_reverse_iterator; //@} - /**@name Insert */ //@{ @@ -351,7 +356,8 @@ const_reference> const_reverse_iterator; size_type find_first_of(lyxstring const &, size_type i = 0) const; /// - size_type find_first_of(value_type const * p, size_type i, size_type n) const; + size_type find_first_of(value_type const * p, size_type i, + size_type n) const; /// size_type find_first_of(value_type const * p, size_type i = 0) const; @@ -363,7 +369,8 @@ const_reference> const_reverse_iterator; size_type find_last_of(lyxstring const &, size_type i = npos) const; /// - size_type find_last_of(value_type const * p, size_type i, size_type n) const; + size_type find_last_of(value_type const * p, size_type i, + size_type n) const; /// size_type find_last_of(value_type const * p, size_type i = npos) const; @@ -379,20 +386,23 @@ const_reference> const_reverse_iterator; size_type n) const; /// - size_type find_first_not_of(value_type const * p, size_type i = 0) const; + size_type find_first_not_of(value_type const * p, + size_type i = 0) const; /// size_type find_first_not_of(value_type c, size_type i = 0) const; /// - size_type find_last_not_of(lyxstring const &, size_type i = npos) const; + size_type find_last_not_of(lyxstring const &, + size_type i = npos) const; /// size_type find_last_not_of(value_type const * p, size_type i, size_type n) const; /// - size_type find_last_not_of(value_type const * p, size_type i = npos) const; + size_type find_last_not_of(value_type const * p, + size_type i = npos) const; /// size_type find_last_not_of(value_type c, size_type i = npos) const; @@ -420,7 +430,8 @@ const_reference> const_reverse_iterator; lyxstring & replace(size_type i,size_type n, value_type const * p); /// - lyxstring & replace(size_type i, size_type n, size_type n2, value_type c); + lyxstring & replace(size_type i, size_type n, + size_type n2, value_type c); /// lyxstring & replace(iterator i, iterator i2, const lyxstring & str); @@ -433,7 +444,8 @@ const_reference> const_reverse_iterator; lyxstring & replace(iterator i, iterator i2, value_type const * p); /// - lyxstring & replace(iterator i, iterator i2, size_type n , value_type c); + lyxstring & replace(iterator i, iterator i2, + size_type n , value_type c); /// lyxstring & replace(iterator i, iterator i2, iterator j, iterator j2); @@ -468,7 +480,8 @@ const_reference> const_reverse_iterator; /** This one returns a verbatim copy. Not the trailing '\0' The caller must provide a buffer with engough room. */ - size_type copy(value_type * buf, size_type len, size_type pos = 0) const; + size_type copy(value_type * buf, size_type len, + size_type pos = 0) const; //@} @@ -513,74 +526,25 @@ private: /// lyxstring & operator+=(int); - /// A string representation - struct Srep { - /// - static lyxstring::size_type const xtra = - static_cast(8); - /// size - lyxstring::size_type sz; - /// Reference count - unsigned short ref; - /// The total amount of data reserved for this representaion - lyxstring::size_type res; - /// Data. At least 1 char for trailing null. - lyxstring::value_type * s; - - /// - Srep(lyxstring::size_type nsz, const lyxstring::value_type * p); - /// - Srep(lyxstring::size_type nsz, lyxstring::value_type ch); - /// - ~Srep() { delete[] s; } - /// - Srep * get_own_copy() - { - if (ref == 1) return this; - ref--; - return new Srep(sz, s); - } - - /// - void assign(lyxstring::size_type nsz, const lyxstring::value_type * p); - /// - void assign(lyxstring::size_type nsz, lyxstring::value_type ch); - /// - void append(lyxstring::size_type asz, const lyxstring::value_type * p); - /// - void push_back(lyxstring::value_type c); - /// - void insert(lyxstring::size_type pos, - const lyxstring::value_type * p, - lyxstring::size_type n); - /// - void resize(lyxstring::size_type n, lyxstring::value_type c); - /// - void reserve(lyxstring::size_type res_arg); - /// - void replace(lyxstring::size_type i, lyxstring::size_type n, - lyxstring::value_type const * p, lyxstring::size_type n2); - private: - Srep(const Srep &); - Srep & operator=(const Srep &); - }; - - /** The empty_rep is a local static in each function that + /// Forward declaration of the string representation + struct Srep; + + /// A string is a pointer to it's representation + Srep * rep; + + /** Note: The empty_rep is a local static in each function that benefits from one. There is no "global" empty srep but lyxstring doesn't need one (no code actually relies upon a single empty srep). This overcomes *all* "static initialization" problems, at maximum speed, with a small overhead of a few local static empty_reps. - */ - - /// A string is a pointer to it's representation - Srep * rep; + */ #ifdef DEVEL_VERSION /// lyxstringInvariant is used to test the lyxstring Invariant friend class lyxstringInvariant; -#endif //DEVEL_VERSION +#endif }; // The usual comparison operators ==, !=, >, <, >=, <= are