moved Srep definition to lyxstring.C

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@224 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Lars Gullik Bjønnes 1999-10-22 02:26:50 +00:00
parent a795073d30
commit 5117a9df99
3 changed files with 237 additions and 196 deletions

View File

@ -1,5 +1,13 @@
1999-10-22 Lars Gullik Bjønnes <larsbj@lyx.org>
* 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.

View File

@ -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;
}
///////////////////////////////////////
// The internal string representation
///////////////////////////////////////
//--------------------------------------------------------------------------
// lyxstringInvariant
#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();
struct lyxstring::Srep {
///
static lyxstring::size_type const xtra =
static_cast<lyxstring::size_type>(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<lyxstring::size_type>(-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
/////////////////////////////////////////////

View File

@ -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 <iterator>
#endif
#include <cstring>
#include "LAssert.h"
#include <cstring> // 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<iterator, value_type, reference>
reverse_iterator;
reverse_iterator;
///
typedef reverse_iterator<const_iterator, const value_type,
const_reference> 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<lyxstring::size_type>(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;
/// Forward declaration of the string representation
struct Srep;
///
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 &);
};
/// A string is a pointer to it's representation
Srep * rep;
/** The empty_rep is a local static in each function that
/** 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