Main Page | Namespace List | Class Hierarchy | Compound List | File List | Compound Members | File Members

SubString Class Reference

This class supports the creation and manipulation of SubStrings, which are sections of Strings. More...

#include <SubString.h>

Collaboration diagram for SubString:

Collaboration graph
[legend]
List of all members.

Public Member Functions

 SubString (String &s, const size_t start, const size_t len) throw (std::out_of_range)
 This constructor initializes the SubString object with a reference to a String object, a start index for the SubString section and a length.

 operator String () const
 User defined type conversion between SubString and String.

size_t getRefCnt ()
size_t length ()
String operator+ (const char *Cstr)
 String = SubString + Cstr.

String operator+ (const SubString &sub)
 String = SubString + SubString.

String operator+ (const String &str)
 String = SubString + String.

String operator= (const char *CStr)
 operator =: This function assigns a C character string to a SubString.

String operator= (String &str)
 operator =: Assign a String to a SubString.

String operator= (const SubString &sub)
 operator = (SubStr &)

bool operator== (const char *Cstr)
bool operator== (String &s)
bool operator== (SubString subStr)
bool operator!= (const char *Cstr)
bool operator!= (String &s)
bool operator!= (SubString subStr)
bool operator<= (const char *Cstr)
bool operator<= (String &s)
bool operator<= (SubString subStr)
bool operator>= (const char *Cstr)
bool operator>= (String &s)
bool operator>= (SubString subStr)
bool operator< (const char *Cstr)
bool operator< (String &s)
bool operator< (SubString subStr)
bool operator> (const char *Cstr)
bool operator> (String &s)
bool operator> (SubString subStr)

Private Member Functions

void rangeCheck (String &s, const size_t start, const size_t len) throw (std::out_of_range)
 Check that start and len are within the bounds of the String argument s.

int compareTo (const char *CStr)
 Compare the SubString to a C string (e.g., const char *).

int compareTo (String &s)
 Compare the SubString to a String.

int compareTo (SubString &subStr)
 Compare two SubStrings.

void createCopySpace (size_t start, size_t charsToCopy)
 A SubString defines a region in a String.

String string () const
 Return the String section defined by the SubString as a String result.


Private Attributes

RCPtr< SharedDatavalue

Detailed Description

This class supports the creation and manipulation of SubStrings, which are sections of Strings.

SubStrings are usually created by the "()" operator of the String class. As a result, this class and the String class are closely related.

The String class "()" operator takes two numeric arguments, the starting index and the length (String objects follow C/C++ indexing and start at 0).

Examples:

String a("abcdefgh"); String b; String tmp;

b = a(0,4); -- assignment of SubString to String

a(0, 4) = "0123"; -- assignment of CString to SubString

a(0, 4) = a(4, 4); -- assignment of SubString to SubString

a(0, 4) = b; -- assignment of String to SubString

Although a SubString is usually created by the String "()" operator, it can also be created explicitly. For example:

String s = "the lazy dog"; SubString t(s, 9, 3);

t = "golden"; std::cout << (const char *)s << std::endl;

Note that a SubString is a reference to a String. So the assignment to the SubString alters the String. The example above will write "the lazy golden" to std::cout.

The SubString class suports relational operators. This is faster than converting the SubString to a String and performing the relational operation on String operands.

The SubString class does not support an argumentless constructor. This assures that all SubString objects are properly initialized with a String and a range (start index and length). The starting index and length are checked in the constructor to assure that they are within the bounds of the String argument. If they are not, an std::out_of_range exception will be thrown.

There is no type cast supported for SubString to const char * although it might be nice to be able to do the following

String a = "morgan dreams of being fat"; const char *sleep = a(0, 13); // Not supported!

Unfortunately, there is no practical way to implement this. The right-hand-side operation a(0, 13) creates a compiler generated String temporary. This temporary will be deallocated after the statement containing the assignment. If the memory for the temporary were referenced from the const char *, the const char * pointer would point to deallocated memory.

There are some corner cases that I could not figure out how to protect against. For example, it is possible to create a SubString object that references a deallocated string. This is shown in the function makeSubString below:

// // Don't do this! // This function will result in a SubString that references // a String which has been deallocated. // SubString makeSubString(const char *Cstr, size_t start, size_t len) { String s( Cstr ); SubString t(s, start, len); return t; // The String "s" will be deallocated on exit }

For this function to work, the SubString constructor would have to increment the reference count of the String, so that the String would not be deallocated on exit (when its reference count reaches zero). This could be done if an actual String, rather than a pointer to a String were used in the SubString shared data.

Implementing the SubString in this way break the functionality of the SubString object. Consider the code below:

String a = "12345678"; a(3,0) = "abcd";

If the SubString shared data contained a String, rather than a pointer to a string, the constructor for the SubString would increment the reference count for a to 2. This would work well for the makeSubString function, but would break the assignment above.

If the SubString shared data contained a String, the assignment to this String would result in a unique copy being be made, since the String is shared (e.g., reference count > 1). The C-string "abcd" would be inserted into the String in the SubString shared data (which is now unique). The result will be that "a" is unchanged and the String we have assigned into will be deallocated when the SubString destructor is executed.

In contrast to the String class, only a few SubString functions are inlined. Many SubString functions reference the String class. The String class is defined only as an abstract class here. This is required by the fact that the String class also includes SubString.h.

Author:
Ian Kaplan www.bearcave.com

Definition at line 160 of file SubString.h.


Constructor & Destructor Documentation

SubString::SubString String s,
const size_t  start,
const size_t  len
throw (std::out_of_range)
 

This constructor initializes the SubString object with a reference to a String object, a start index for the SubString section and a length.

For example:

String s = "max is a cat"; SubString t(s, 9, 3);

Except for initialization, nothing happens in the SubString constructor. It is only when a SubString is assigned or otherwise operated on that a new String is created (the region of the initialization String defined by the start and length).

SubStrings are commonly created by the String class. When creating a SubString object the String class initializes the SubString with itself, and with the starting index and length. The code below shows an example of an sub-string expression created by the String class.

String a("abcd12345jkl");

String b = a(4, 5);

The first argument is the starting index (where Strings start with index 0). The second argument is the length.

This class throws the std::out_of_range error when either the start or (start+len) are out of range (beyond the end of the String). Exceptions are described in The C++ Programming Language, Third Edition by Stroustrup, section 14.10.

One of the corner cases that must be considered is a SubString of an empty String:

String empty; // empty string String empty2 = empty(0, 0); // This will throw an exception

Ok, so we're taking a zero length section of a String starting at zero. Is that so wrong? I don't know about so wrong, but it does seem incorrect. The rules with with a SubString is that the starting index must be less than the String length. In this case the starting index is equal to the String length. As a result this example would throw an exception.

A SubString can be thought of as copy on demand. The SubString expression will not actually section the String until the SubString is assigned, either explicitly or implicitly.

The SubString will not alter the reference count of the String that it references.

Definition at line 132 of file SubString.C.

00134           : value( new SharedData() )
00135 {
00136   try {
00137     rangeCheck(s, start, len);
00138     size_t sLen = s.strlen();
00139     value->pStr( &s );
00140     value->start( start );
00141     value->subStrLen(len);
00142   }
00143   catch (std::out_of_range e) {
00144     throw e;
00145   }
00146 } // SubString constructor


Member Function Documentation

int SubString::compareTo SubString subStr  )  [private]
 

Compare two SubStrings.

As noted above, we know that the String is initialized in each case, although the Strings might still be null. We also know that the start and length are in range, since this is checked in the constructor.

Definition at line 541 of file SubString.C.

References value.

00542 {
00543   int result;
00544   const char *pThisCStr = *(value->pStr());
00545   const char *pRhsCStr = *(subStr.value->pStr());
00546 
00547   // The Strings in both SubStrings are NULL
00548   if (pThisCStr == 0 && pRhsCStr == 0) {
00549     result = 0;
00550   }
00551   else if (pThisCStr != 0 && pRhsCStr == 0) {
00552     result = 1;
00553   }
00554   else if (pThisCStr == 0 && pRhsCStr != 0) {
00555     result = -1;
00556   }
00557   else {
00558     size_t thisLen = value->subStrLen();
00559     size_t rhsLen = subStr.value->subStrLen();
00560     size_t compareLen = thisLen;
00561     if (compareLen > rhsLen) {
00562       compareLen = rhsLen;
00563     }
00564     size_t thisStart = value->start();
00565     size_t rhsStart = subStr.value->start();
00566 
00567     result = strncmp( pThisCStr+thisStart,
00568                       pRhsCStr+rhsStart,
00569                       compareLen );
00570     if (result == 0) {
00571       if (thisLen < rhsLen) {
00572         result = -1;
00573       }
00574       else if (thisLen > rhsLen) {
00575         result = 1;
00576       }
00577     }
00578   }
00579   return result;
00580 } // compareTo for SubString

int SubString::compareTo String s  )  [private]
 

Compare the SubString to a String.

The function returns:

  • result == 0 when SubString is equal to the CString
  • result > 0 when the SubString is greater than the CString
  • result < 0 when the Substring is less than the Cstring

Definition at line 524 of file SubString.C.

References compareTo().

00525 {
00526   const char *pCStr = s;
00527   return compareTo( pCStr );
00528 } // compareTo for String

int SubString::compareTo const char *  CStr  )  [private]
 

Compare the SubString to a C string (e.g., const char *).

The function returns:

  • result == 0 when SubString is equal to the CString
  • result > 0 when the SubString is greater than the CString
  • result < 0 when the Substring is less than the Cstring

Notes:

value->pStr() returns a pointer to the String which was used to initialize the SubString. This String pointer is stored as part of the shared data. Since compareTo is called when a SubString operation is being applied, we know that pStr() will is not NULL. However, it IS possible that the string is empty. In this case the String "const char *" operator will return null.

If the strings are not the same length, the compareTo function acts as if the shorter string is extended with null characters until both strings are the same length.

The compareTo function does not have to check the range of the SubString, since it was checked by the SubString constructor.

Definition at line 483 of file SubString.C.

References value.

Referenced by compareTo(), operator!=(), operator<(), operator<=(), operator==(), operator>(), and operator>=().

00484 {
00485   int result;
00486   const char *pThisCStr = *(value->pStr());
00487   if (pThisCStr == 0 && CStr == 0) {
00488     result = 0;
00489   } else if (pThisCStr == 0 && CStr != 0) {
00490     result = -1;
00491   } else if (pThisCStr != 0 && CStr == 0) {
00492     result = 1;
00493   } else { // both pThisCStr and CStr are non-NULL
00494     size_t subStrLen = value->subStrLen();
00495     size_t start = value->start();
00496     result = strncmp((pThisCStr + start), CStr, subStrLen);
00497     if (result == 0) {
00498       size_t CStrLen = strlen( CStr );
00499       if (CStrLen > subStrLen) {
00500         result = -1; // ThisCStr < CStr
00501       }
00502     }
00503   }
00504   return result;
00505 } // compareTo for const char *

void SubString::createCopySpace size_t  start,
size_t  charsToCopy
[private]
 

A SubString defines a region in a String.

When an assignment is made to a SubString and the length of the data being assigned is not the same as the SubString length, a copy space must be created.

In the case where the length of the data being copied is larger than the SubString length, the area defined by the SubString must be made larger. This extends the length of the string and moves characters above the region to higher indices.

In the case where the length of the data being copied is less than the SubString length, the area defined by the SubString must be reduced. This reduces the length of the String and results in moving characters above the copy region to lower indices.

This function allows assignment code to simply copy data into the assignment region. Note that both the write() and resize() functions will create an unshared String if the String is shared.

Definition at line 172 of file SubString.C.

References value.

Referenced by operator=().

00173 {
00174     size_t subStrLen = value->subStrLen();
00175 
00176     if (charsToCopy != subStrLen) {
00177       size_t strlen = value->pStr()->strlen();
00178       if (charsToCopy < subStrLen) {
00179         // The end of the copy region will be start+charsToCopy
00180         // The end of the SubString section is start+subStrLen
00181         size_t dest = start+charsToCopy;
00182         for (size_t i = start+subStrLen; i < strlen; i++, dest++) {
00183           char ch = value->pStr()->read(i);
00184           value->pStr()->write(dest, ch );
00185         }
00186         size_t shrink = subStrLen - charsToCopy;
00187         size_t newLen = strlen - shrink;
00188         value->pStr()->resize( newLen );
00189       }
00190       else if (charsToCopy > subStrLen) {
00191         size_t expand = charsToCopy - subStrLen;
00192         size_t newLen = strlen + expand;
00193         value->pStr()->resize( newLen );
00194 
00195         size_t dest = newLen-1;
00196         for (int i = strlen-1; i >= (int)start; i--, dest--) {
00197           char ch = value->pStr()->read(i);
00198           value->pStr()->write(dest, ch );
00199         }
00200       }
00201     }
00202 } // createCopySpace

size_t SubString::getRefCnt  )  [inline]
 

Definition at line 208 of file SubString.h.

References value.

Referenced by SubStringPassByReference(), SubStringPassByValue(), subStrRefCnt(), and test_substr_func_valarg().

00208 { return value->getRefCnt(); }

size_t SubString::length void   )  [inline]
 

Definition at line 210 of file SubString.h.

References value.

00210 { return value->subStrLen(); }

SubString::operator String  )  const
 

User defined type conversion between SubString and String.

For example

String a("abcdefg"); String b = a(0,4);

The string() function sections the SubString, resulting in a String.

Definition at line 43 of file SubString.C.

References string().

00044 { 
00045   return this->string(); 
00046 }

bool SubString::operator!= SubString  subStr  )  [inline]
 

Definition at line 227 of file SubString.h.

References compareTo().

00227 { return (compareTo(subStr) != 0); }

bool SubString::operator!= String s  )  [inline]
 

Definition at line 226 of file SubString.h.

References compareTo().

00226 { return (compareTo( s ) != 0); }

bool SubString::operator!= const char *  Cstr  )  [inline]
 

Definition at line 225 of file SubString.h.

References compareTo().

00225 { return (compareTo( Cstr ) != 0); }

String SubString::operator+ const String str  ) 
 

String = SubString + String.

Definition at line 232 of file SubString.C.

00233 {
00234   String s1 = *this;
00235   String result = s1 + str;
00236   return result;
00237 }

String SubString::operator+ const SubString sub  ) 
 

String = SubString + SubString.

Definition at line 220 of file SubString.C.

00221 {
00222   String s1 = *this;
00223   String s2 = sub;
00224   String result = s1 + s2;
00225   return result;
00226 }

String SubString::operator+ const char *  Cstr  ) 
 

String = SubString + Cstr.

Definition at line 207 of file SubString.C.

00208 {
00209   String result = *this;
00210   if (Cstr != 0) {
00211     result += Cstr;
00212   }
00213   return result;
00214 }

bool SubString::operator< SubString  subStr  )  [inline]
 

Definition at line 239 of file SubString.h.

References compareTo().

00239 { return (compareTo(subStr) < 0); }

bool SubString::operator< String s  )  [inline]
 

Definition at line 238 of file SubString.h.

References compareTo().

00238 { return (compareTo( s ) < 0); }

bool SubString::operator< const char *  Cstr  )  [inline]
 

Definition at line 237 of file SubString.h.

References compareTo().

00237 { return (compareTo( Cstr ) < 0); }

bool SubString::operator<= SubString  subStr  )  [inline]
 

Definition at line 231 of file SubString.h.

References compareTo().

00231 { return (compareTo(subStr) <= 0); }

bool SubString::operator<= String s  )  [inline]
 

Definition at line 230 of file SubString.h.

References compareTo().

00230 { return (compareTo( s ) <= 0); }

bool SubString::operator<= const char *  Cstr  )  [inline]
 

Definition at line 229 of file SubString.h.

References compareTo().

00229 { return (compareTo( Cstr ) <= 0); }

String SubString::operator= const SubString str  ) 
 

operator = (SubStr &)

For example:

a(0, 4) = b(4, 4);

Definition at line 407 of file SubString.C.

References string().

00408 {
00409   // convert to a SubStr = String
00410   *this = str.string();
00411   return (*this).string();
00412 } // operator=

String SubString::operator= String str  ) 
 

operator =: Assign a String to a SubString.

For example:

String a("the quick brown fox jumped"); String b("dog");

a(16, 3) = b;

This function does the same thing as the C-string version of operator=. Please see the comment associated with this function.

Definition at line 369 of file SubString.C.

References createCopySpace(), String::strlen(), and value.

00370 {
00371   size_t charsToCopy;
00372 
00373   if ((charsToCopy = str.strlen()) > 0) {
00374     size_t start = value->start();
00375 
00376     // create a copy region that is the correct size
00377     createCopySpace(start, charsToCopy );
00378 
00379     if (value->pStr()) {
00380       size_t i, cnt;
00381       for (i = start, cnt = 0; i < start + charsToCopy; i++,cnt++) {
00382         value->pStr()->write(i, str[cnt]);
00383       }
00384     }
00385   }
00386 
00387   if (value->pStr())
00388     return *(value->pStr());
00389   else {
00390     String empty;
00391 
00392     return empty;
00393   }
00394 } // operator = (String)

String SubString::operator= const char *  Cstr  ) 
 

operator =: This function assigns a C character string to a SubString.

For example:

String foo("abcdefghijkl"); String bar = foo;

foo(4, 4) = "1234";

After the SubString assignment is executed, the String "foo" will contain "abcd1234ijkl". Note that the contents of bar will be unchanged. However, the reference count of bar will be 1.

A smaller string can be assigned to a larger string:

foo(4, 4) = "12";

will result in "abcd12ijkl" (note that in this case a length 4 string ("efgh") was replaced by a length 2 string ("12"))

The symetric case, where a longer string is assigned to a smaller string:

foo(4, 4) = "123456

Results in a longer String, as the length 4 string is replaced by a length 6 string: "abcd123456ijkl".

Assignment to a SubString results in a String. The String is the String that was used to initialize the SubString constructor, modified by the assignment. The assignment

foo(4, 4) = "1234";

can be broken up into two steps:

  • SubString creation:
    SubString t1(foo, 4, 4);
  • Assignment to the SubString, resulting in a string:
    String t2 = (t1 = "1234");

There are three cases that are dealt with in this assignment:

  • The length of the Cstr is equal to the length of the SubString section. In this case the Cstr can simply be copied into the String.
  • The length of the Cstr is less than the length of the SubString section. In this case the String is collapsed before the assignment.
  • The length of the Cstr is greater than the length of the SubString section. In this case the String is expanded before the assignment.

As a result of the limitations imposed by the SubString constructor, a SubString will always be initialized with a String and the start and length will always be within bounds of that String.

Definition at line 323 of file SubString.C.

References createCopySpace(), and value.

00324 {
00325   size_t charsToCopy;
00326 
00327   if (Cstr && (charsToCopy = ::strlen( Cstr)) > 0) {
00328     size_t start = value->start();
00329 
00330     // create a copy region that is the correct size
00331     createCopySpace( start, charsToCopy );
00332 
00333     size_t cnt = 0;
00334     for (size_t i = start; i < start + charsToCopy; i++, cnt++) {
00335       value->pStr()->write(i, Cstr[ cnt ] );
00336     }
00337   }
00338 
00339   //
00340   // C/C++ allows chained assignment, so one can do something like
00341   //
00342   //    String a = b(2,4) = "abcd";
00343   //
00344   // So the string that results from the substring assignment should
00345   // be returned.
00346   //
00347   String retStr( *(value->pStr()) );
00348 
00349   return retStr;
00350 } // operator = (Cstr)

bool SubString::operator== SubString  subStr  )  [inline]
 

Definition at line 223 of file SubString.h.

References compareTo().

00223 { return (compareTo(subStr) == 0); }

bool SubString::operator== String s  )  [inline]
 

Definition at line 222 of file SubString.h.

References compareTo().

00222 { return (compareTo( s ) == 0); }

bool SubString::operator== const char *  Cstr  )  [inline]
 

Definition at line 221 of file SubString.h.

References compareTo().

00221 { return (compareTo( Cstr ) == 0); }

bool SubString::operator> SubString  subStr  )  [inline]
 

Definition at line 243 of file SubString.h.

References compareTo().

00243 { return (compareTo(subStr) > 0); }

bool SubString::operator> String s  )  [inline]
 

Definition at line 242 of file SubString.h.

References compareTo().

00242 { return (compareTo( s ) > 0); }

bool SubString::operator> const char *  Cstr  )  [inline]
 

Definition at line 241 of file SubString.h.

References compareTo().

00241 { return (compareTo( Cstr ) > 0); }

bool SubString::operator>= SubString  subStr  )  [inline]
 

Definition at line 235 of file SubString.h.

References compareTo().

00235 { return (compareTo(subStr) >= 0); }

bool SubString::operator>= String s  )  [inline]
 

Definition at line 234 of file SubString.h.

References compareTo().

00234 { return (compareTo( s ) >= 0); }

bool SubString::operator>= const char *  Cstr  )  [inline]
 

Definition at line 233 of file SubString.h.

References compareTo().

00233 { return (compareTo( Cstr ) >= 0); }

void SubString::rangeCheck String s,
const size_t  start,
const size_t  len
throw (std::out_of_range) [private]
 

Check that start and len are within the bounds of the String argument s.

Definition at line 53 of file SubString.C.

00055 {
00056   char *errMsg = 0;
00057   bool rangeError = false;
00058   size_t sLen = s.strlen();
00059   if (start >= sLen) {
00060     errMsg = "SubString: start >= String length";
00061     rangeError = true;
00062   }
00063   else if (start + len > sLen) {
00064     errMsg = "SubString: start + len >= String length";
00065     rangeError = true;
00066   }
00067 
00068   if (rangeError) {
00069     throw std::out_of_range( errMsg );
00070   }
00071 } // rangeCheck

String SubString::string  )  const [private]
 

Return the String section defined by the SubString as a String result.

A SubString object consists of a String and a range (e.g., start index and length) which defines a string section. In a sense, a SubString object is intent, not action. The string() function performs the action by sectioning the SubString into a String.

No bounds check is made here (for example, to assure that subStrEnd is less than sLen) because this check is made when the SubString is constructed.

Definition at line 430 of file SubString.C.

References value.

Referenced by operator String(), and operator=().

00431 {
00432   String retVal;
00433 
00434   if (value->pStr()) {
00435     size_t sLen = value->pStr()->strlen();
00436     size_t start = value->start();
00437     size_t subStrLen = value->subStrLen();
00438     size_t subStrEnd = start + subStrLen;
00439 
00440     for (size_t i = start; i < subStrEnd; i++) {
00441       retVal += (*(value->pStr()))[i];
00442     }
00443 
00444   }
00445   return retVal;
00446 } // SubString::string


Member Data Documentation

RCPtr<SharedData> SubString::value [private]
 

Definition at line 191 of file SubString.h.

Referenced by compareTo(), createCopySpace(), getRefCnt(), length(), operator=(), and string().


The documentation for this class was generated from the following files:
Generated on Mon Sep 22 20:23:03 2003 by doxygen 1.3.3