// -*- C++ -*-
/***************************************************************************
 *
 * string_ref - Declarations for the Standard Library string_ref classes
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-1999 Rogue Wave Software, Inc.  All Rights Reserved.
 *
 * This computer software is owned by Rogue Wave Software, Inc. and is
 * protected by U.S. copyright laws and other laws and by international
 * treaties.  This computer software is furnished by Rogue Wave Software,
 * Inc. pursuant to a written license agreement and may be used, copied,
 * transmitted, and stored only in accordance with the terms of such
 * license and with the inclusion of the above copyright notice.  This
 * computer software or any other copies thereof may not be provided or
 * otherwise made available to any other person.
 *
 * U.S. Government Restricted Rights.  This computer software is provided
 * with Restricted Rights.  Use, duplication, or disclosure by the
 * Government is subject to restrictions as set forth in subparagraph (c)
 * (1) (ii) of The Rights in Technical Data and Computer Software clause
 * at DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of the
 * Commercial Computer Software – Restricted Rights at 48 CFR 52.227-19,
 * as applicable.  Manufacturer is Rogue Wave Software, Inc., 5500
 * Flatiron Parkway, Boulder, Colorado 80301 USA.
 *
 **************************************************************************/

#ifndef __STD_STRING_REF
#define __STD_STRING_REF

#include <stdcomp.h>
#include "rw/stddefs.h"
#include <memory>     // For allocator.
#include <rw/traits>

#ifndef _RWSTD_NO_NAMESPACE
namespace std {
#endif

//
// Class & Structure Declarations
//
  template< class charT, class traits _RWSTD_COMPLEX_DEFAULT(char_traits<charT>), 
  class Allocator _RWSTD_COMPLEX_DEFAULT(allocator<charT>) >
  class basic_string;

#ifndef _RWSTD_NO_NAMESPACE
} namespace __rwstd {
#endif

  //
  // __string_noref_rep and __string_noref are used to implement a 
  // non-reference counted string.  Use this implementation when the 
  // overhead from the reference counting (including mutex locking) 
  // overwhelms the advantages.  One example of such a situation would 
  // be in an application that infrequently copies short strings and 
  // only very rarely copies long ones.  Another example would be an 
  // application that makes heavy use of iterators from basic_string, 
  // since any outstanding refernece into the string data nullifies 
  // the advantages of reference counting.
  //

  template <class Allocator>
  class _RWSTDExportTemplate __string_noref_rep
  {
  public:
     _EXPLICIT __string_noref_rep(long refs = 0)
      : __refs_((bool)refs), __capacity_(0), __nchars_(0)  {;}
    __string_noref_rep(const __string_noref_rep& r)
      : __refs_((bool)r.__refs_), __capacity_(0), __nchars_(0)  {;}
  
    typedef Allocator                        allocator_type;
    typedef _TYPENAME _RWSTD_ALLOC_SIZE_TYPE size_type;

  protected:

    bool            __refs_;      // true if null ref, else false
    size_type       __capacity_;  // Size of allocated memory
    size_type       __nchars_;    // Number of actual data values stored
  };

  template <class charT, class traits , class Allocator>
  class _RWSTDExportTemplate __string_noref
   : public __string_noref_rep<Allocator>
  {
  public:
    typedef __string_noref_rep<Allocator> __string_ref_rep_type;
    typedef _TYPENAME __string_noref_rep<Allocator>::size_type size_type;
  
    _EXPLICIT __string_noref (long=0) 
    { ; }

  private:
    long __references () const
    { 
      return (long)__string_noref_rep<Allocator>::__refs_; 
    }
    void __setRefCount (long r)
    { ; }
    void __addReference ()
    { ; }
    long  __removeReference ()
    { 
      return (long)__string_noref_rep<Allocator>::__refs_;
    }
    size_type length () const
    { 
      return __string_noref_rep<Allocator>::__nchars_; 
    }
    size_type __getCapac () const
    { 
      return __string_noref_rep<Allocator>::__capacity_;
    }
    charT*    data () const
    {
      return (charT*)(this+1);
    }
    charT&   operator[]     (size_type i)      
    { 
      return (_RWSTD_REINTERPRET_CAST(charT*,(this+1)))[i]; 
    }
    const charT&  operator[]     (size_type i) const
    {
      return ((charT*)(this+1))[i];
    }
#ifndef _RWSTD_NO_NAMESPACE
    friend class std::basic_string<charT, traits, Allocator>;
#else
    friend class basic_string<charT, traits, Allocator>;
#endif
  };


  //
  // __string_ref_rep and __string_ref are used to implement a 
  // reference counted string.  Using this class  basic_string 
  // optimizes copying by sharing data whenever possible.  Copies 
  // are only made when absolutely necessary.
  //


#if defined (_RWSTD_MULTI_THREAD) && defined(_RWSTD_ONE_STRING_MUTEX) && defined(_RWSTD_NO_TEST_AND_SET)
  extern  _RWSTDMutex _RWSTDExport __rw_string_mutex;
#endif /* _RWSTD_MULTI_THREAD */

  template <class Allocator>
  class _RWSTDExportTemplate __string_ref_rep
  {
  public:
    //  the __refs_ are initialized to 1 because of a problem
    //  where the destructor was being called when it
    //  should not be.
  
    __string_ref_rep()
      : __refs_(0), __capacity_(0), __nchars_(0) {;}
    __string_ref_rep(long x)
      : __refs_(x), __capacity_(0), __nchars_(0) {;}
    __string_ref_rep(const __string_ref_rep& r)
      : __refs_(r.__refs_), __capacity_(0), __nchars_(0)  {;}
  
    typedef Allocator                        allocator_type;
    typedef _TYPENAME _RWSTD_ALLOC_SIZE_TYPE size_type;

  protected:

#if defined (_RWSTD_MULTI_THREAD) && !defined(_RWSTD_ONE_STRING_MUTEX) && defined(_RWSTD_NO_TEST_AND_SET)
    _RWSTDMutex __mutex_;
#endif /* _RWSTD_MULTI_THREAD */  

    long   __refs_;               // (1 less than) number of references
                                  // (-2 if reference counting disabled)
    size_type       __capacity_;  // Size of allocated memory
    size_type       __nchars_;    // Number of actual data values stored
  };


  template <class charT, class traits , class Allocator >
  class _RWSTDExportTemplate __string_ref : public __string_ref_rep<Allocator>
  {
  public:
    typedef __string_ref_rep<Allocator> __string_ref_rep_type;
    typedef _TYPENAME __string_ref_rep<Allocator>::size_type size_type;
  
    _EXPLICIT __string_ref (long initRef = 0) 
      :  __string_ref_rep<Allocator>(initRef - 1)
    { ; }

    __string_ref (const __string_ref<charT,traits,Allocator>& ref)
      : __string_ref_rep<Allocator>(ref.__refs_)
    { ; }

  private:
    long __references () const 
    { 
      return __string_ref_rep<Allocator>::__refs_+1; 
    }

    void __setRefCount (long r)       
    { 
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::__getNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(__rw_string_mutex);
#else
         _RWSTDGuard guard(this->__mutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        _RWSTD_MT_SET(this->__refs_,r-1);
      }
    }

    void __addReference ()
    { 
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::__getNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(__rw_string_mutex);
#else
         _RWSTDGuard guard(this->__mutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        _RWSTD_MT_INCREMENT(this->__refs_);
      }
    }
    long  __removeReference ()                
    {
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::__getNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(__rw_string_mutex);
#else
         _RWSTDGuard guard(this->__mutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        return __unSafeRemoveReference();
      }
      else
        return 1;
    }
    long  __unSafeRemoveReference ()                
    {
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::__getNullRep())
      {
        _RWSTD_MT_DECREMENT(this->__refs_);
        return this->__refs_+1;
      }
      else
        return 1;
    }

    size_type length () const
    { return __string_ref_rep<Allocator>::__nchars_; }
    size_type __getCapac () const
    { return __string_ref_rep<Allocator>::__capacity_;}

    charT*    data () const
    {
      return (charT*)(this+1);
    }
    charT&   operator[]     (size_type i)      
    { 
      return (_RWSTD_REINTERPRET_CAST(charT*,(this+1)))[i]; 
    }
    const charT&  operator[]     (size_type i) const
    {
      return ((charT*)(this+1))[i];
    }
#ifndef _RWSTD_NO_NAMESPACE
    friend class std::basic_string<charT, traits, Allocator>;
#else
    friend class basic_string<charT, traits, Allocator>;
#endif
  };


  //
  // __null_string_ref_rep is used to provide a single empty
  // string reference for all instances of empty strings.
  // This makes empty strings much smaller and avoids unecessary
  // allocations of reference objects.
  //

  template <class charT, class traits , class Allocator, 
            class stringRef _RWSTD_COMPLEX_DEFAULT(__string_ref_rep<Allocator>) >
  struct _RWSTDExportTemplate __null_string_ref_rep
  {
    //
    // __ref_hdr_ has to be immediately followed by __eos_char_ !
    //
    stringRef      __ref_hdr_;
    charT          __eos_char_; 

    __null_string_ref_rep ()
      : __ref_hdr_(1), __eos_char_(charT(0)) {;}
    __null_string_ref_rep (const __null_string_ref_rep<charT,traits, 
                                                       Allocator,stringRef>& r)
      : __ref_hdr_(r.__ref_hdr_), __eos_char_(charT(0)) {;}

  };

#ifndef _RWSTD_NO_NAMESPACE
} // End of __rwstd 
#endif

#endif // __STD_STRING_REF
