_Algorithm Alley_ 
by Fred Wild
               

Example 1:

string name = "joe";
Istring fastname (name);

ASSERT ( *fastname == "joe" ) ;
ASSERT ( (*fastname).length() == 3 ) ;
ASSERT ( fastname->length() == 3 ) ;


Listing One
////////////////////////////////////////////////////////////////////////////
//  Istring class internalizes strings for fast comparison for equality

using std::string ;

#define StrStrptrMap_t std::map<string, string*, std::less<std::string> >
#define StrptrIntMap_t std::map<string*, int, std::less<string*> >

class Istring {
private:
    static StrStrptrMap_t ustrings ;
    static StrptrIntMap_t ustring_counts ;
    
    string *m_ustring ;       // the "unique string" value being shared

    // Empty Istring case thwarted by declaring def. ctor private
    Istring() { } 
public:
    // Standard parts 
    Istring(const Istring &istr);
    ~Istring();

    // Special ctors
    Istring (const string &str);
    // Assignment
    const Istring & operator=(const Istring &istr);
    // Deferencing operators
    const string * operator->() const { return  m_ustring ; }    // dangerous
    const string & operator*() const  { return *m_ustring ; }    // more safe
    int operator==(const Istring &istr) const 
        { return this->m_ustring == istr.m_ustring ; }
    int operator!=(const Istring &istr) const 
        { return this->m_ustring != istr.m_ustring ; }
};

Listing Two
Istring::Istring (const string &str)
{
    if ( ustrings.find(str) == ustrings.end() ) {
        string *s = new string(str);
        ustrings[str] = s ;
        ustring_counts[this->m_ustring] = 0 ;
    }
    // Adopt the shared string ptr from the map
    this->m_ustring = ustrings[str] ;
    // Increase usage by one
    int n_users = ustring_counts[this->m_ustring] ;
    ustring_counts[this->m_ustring] = ++n_users ;
}

Listing Three 
Istring::Istring(const Istring & istr)
{
    this->m_ustring = istr.m_ustring ;
    // Increase usage by one
    int n_users = ustring_counts[this->m_ustring] ;
    ustring_counts[this->m_ustring] = ++n_users ;
}
const Istring & 
Istring::operator=(const Istring &istr)
{
    if (this == &istr || this->m_ustring == istr.m_ustring) return *this ;
    // Reduce usage by one on current m_ustring
    int n_users = ustring_counts[this->m_ustring] ;
    ustring_counts[this->m_ustring] = --n_users ;
    this->m_ustring = istr.m_ustring ;
    // Increase usage by one on assigned m_ustring
    n_users = ustring_counts[this->m_ustring] ;
    ustring_counts[this->m_ustring] = ++n_users ;
    return *this ;
}

Listing Four
Istring::~Istring()
{
    int n_users = ustring_counts[this->m_ustring] ;
    n_users-- ;

    // We can delete the ustring when it is no longer referenced 
    if (n_users == 0) {
        ustrings.erase(*m_ustring) ;
        ustring_counts.erase(m_ustring) ;
        delete m_ustring ;
    }
    else {
        ustring_counts[this->m_ustring] = n_users ;
    }
}


