String Pools

Many systems, components and applications deal with pre-defined, well known string constants. For example, parsing and manipulating text containing structure mostly requires comparisons against standard string constants.

In a complex system, composed of a large number of objects, there may also be a need to pass strings between objects, and to route processing depending on the value of some string. The implementation of the HTTP transport framework and the XML framework are examples within the Symbian platform where such intense string handling is required.

To improve efficiency, the Symbian platform uses the idea of the string pool.

A string pool is referenced through an RStringPool, which is a handle like object. The following diagram illustrates the basic idea:

Figure 1. String pool representation

A string pool is a mechanism for storing strings in a particular way that makes the comparison of strings a very fast operation. It is particularly efficient at handling strings that can be set up at program compile time. For example, strings that identify lexical elements in a structured text. Typically, they are well known strings that are likely to be used very often in a given context.

Such strings are organised into tables, and each string within a table can be referenced by an index value, which can be symbolised by an enum. Such tables are referred to as static string tables (See Static string tables). The basic algorithm used internally ensures that the pool contains only one string of any particular value, and uses a reference counting mechanism to keep track of usage.

The advantages of representing string constants in such a way are:

  • avoiding a proliferation of duplicate strings throughout a component or an application; typically there is one string pool per thread, and one copy of a string

  • allowing string constants to be represented by integer values

  • allowing strings to be passed between objects by passing integer values, wrapped in a class (any one of the String and RStringF classes)

  • allowing strings to be compared by comparing the integer values.

Internally, a string pool uses hash tables to reference strings.

Static string tables and string constants can be added dynamically to the string pool, for example, at run time. However, there is always a performance penalty while adding either a static or a dynamic string to the string pool as the hash tables need to be updated. This means that it is better to add static string tables at string pool initialisation time, as this is the best time to absorb the overhead.

Key features of string pool

  • The string pool as supplied by the Symbian platform supports any strings that can be represented by a TDes8 descriptor; this includes ASCII or UTF-8 encoded strings. Note that a TDes8 type can represent any type of data , including binary data, and means that a string pool can easily handle the extended characters of another encoding.

  • Within the string pool, strings are of two types - case sensitive and case insensitive. This affects the way strings are compared. Case insensitivity implies that strings are folded for the purpose of comparison.

  • A string pool can contain up to 4,096 static string tables, and each table can represent up 26,2144 strings.

Static string tables

Static string tables are defined and built at compile time. They are represented by a TStringTable object. A string table can be added to the string pool by passing the string table reference to a call to:

void RStringTable::OpenL( const TStringTable& aTable );

The following diagram illustrates a general picture. Note that the strings in any given string table are deemed to be either case sensitive or case insensitive, and this governs how comparisons are made.

As the name implies, a static string table is declared as a const TStringTable data member of a class with a user-defined name. The class name is defined in a header file while the table itself is implemented in a .cpp C++ source file. Both the header file and the C++ source file are normally included in the project definition. Typically, a set of enum values are also defined within the scope of the class, and each value is associated with the strings in the table; code in other parts of the program access the strings in the string pool using these enum values.

The Perl script, stringtable.pl, located in ...\syslibs\bafl\stringtools\, can be used to generate these .cpp and .h files from a simple text definition. The text definition file simply lists the strings and the enum symbols to be associated with them; the file itself is given a .st file type.

Following is a simple example of ExampleStringTable.st file:

# Example String Table
fstringtable ExampleStringTable
!// Some types of fruit
# This comment won't appear in the .h file, but the one above will.
EApple apple
EOrange orange
EBanana banana
# Some animals
ECat cat
EDog dog

The main points to note are:

  • the keyword fstringtable is used to define the name of the class that contains the string table declaration and the enum value symbols. The class name itself follows the keyword. For example, ExampleStringTable.

    Note that you can include underscore characters in the class name. For example, Example_StringTable.

  • the symbols EApple and EOrange form the enum value symbols that correspond to the strings apple and orange respectively.

  • all statements starting with a # are comments and are completely ignored. However # characters can appear in a string. For example ap#ple is a valid string and is not interpreted as a comment.

  • all statements starting with a ! are comments that are inserted into the generated header file.

Running the Perl script with ExampleStringTable.st as source generates the header file ExampleStringTable.h and the C++ source file ExampleStringTable.cpp as illustrated below:

// Autogenerated from epoc32\build\generated\example\ExampleStringTable.st by the stringtable tool - Do not edit

#ifndef STRINGTABLE_ExampleStringTable
#define STRINGTABLE_ExampleStringTable

#include "StringPool.h"

struct TStringTable;

/** A String table */
class ExampleStringTable 
       {
    public:
           enum TStrings
              {
              // Some types of fruit
              /** apple */
              EApple,
              /** orange */
              EOrange,
              /** banana */
              EBanana,
              /** cat */
              ECat,
              /** dog */
              EDog
              };
       static const TStringTable Table;    
       };

#endif // STRINGTABLE_ExampleStringTable
// Autogenerated from epoc32\build\generated\example\ExampleStringTable.st by the stringtable tool - Do not edit
#include <e32std.h>
#include "StringPool.h"
#include "StringTableSupport.h"
#include "ExampleStringTable.h"
#ifdef _DEBUG
#undef _DEBUG
#endif

_STLIT8( K1, "apple" );
_STLIT8( K2, "orange" );
_STLIT8( K3, "banana" );
_STLIT8( K4, "cat" );
_STLIT8( K5, "dog" );

// Intermediate
const void * const KStringPointers[] =
       {
       ( const void* )&K1,
       ( const void* )&K2,
       ( const void* )&K3,
       ( const void* )&K4,
       ( const void* )&K5
       };

const TStringTable ExampleStringTable::Table = {5, KStringPointers, EFalse};

The table itself is the static data member Table of class ExampleStringTable.

Related concepts