// -*- C++ -*-
/***************************************************************************
 *
 * string_ref - Declarations for the Standard Library string_ref classes
 *
 ***************************************************************************
 *    
 *  Copyright 2000 Compaq Computer Corporation
 *
 *  COMPAQ Registered in U.S. Patent and Trademark Office.
 *
 *  Confidential computer software. Valid license from Compaq required for
 *  possession, use or copying. Consistent with FAR 12.211 and 12.212,
 *  Commercial Computer Software, Computer Software Documentation, and
 *  Technical Data for Commercial Items are licensed to the U.S. Government
 *  under vendor's standard commercial license.
 *
 ****************************************************************************
 *
 * (c) Copyright 1994, 1998 Rogue Wave Software, Inc.
 * ALL RIGHTS RESERVED
 *
 * The software and information contained herein are proprietary to, and
 * comprise valuable trade secrets of, Rogue Wave Software, Inc., which
 * intends to preserve as trade secrets such software and information.
 * This software is furnished 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 software and information or any other copies thereof may
 * not be provided or otherwise made available to any other person.
 *
 * Notwithstanding any other lease or license that may pertain to, or
 * accompany the delivery of, this computer software and information, the
 * rights of the Government regarding its use, reproduction and disclosure
 * are as set forth in Section 52.227-19 of the FARS Computer
 * Software-Restricted Rights clause.
 * 
 * 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.
 * Contractor/Manufacturer is Rogue Wave Software, Inc.,
 * P.O. Box 2328, Corvallis, Oregon 97339.
 *
 * This computer software and information is distributed with "restricted
 * rights."  Use, duplication or disclosure is subject to restrictions as
 * set forth in NASA FAR SUP 18-52.227-79 (April 1985) "Commercial
 * Computer Software-Restricted Rights (April 1985)."  If the Clause at
 * 18-52.227-74 "Rights in Data General" is specified in the contract,
 * then the "Alternate III" clause applies.
 *
 **************************************************************************/

#ifndef __STD_STRING_REF
#define __STD_STRING_REF

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


#if defined(__DECCXX)
#   ifdef __PRAGMA_ENVIRONMENT
#      pragma __environment __save
#      pragma __environment __cxx_header_defaults
#   endif
#endif

#if defined(__linux__) && defined(__DECFIXCXXL1648)
#define _RWSTD_NO_TEST_AND_SET
#endif

#if defined(__DECCXX) && !defined(__DECFIXCXXL1138) && defined(_RWSTD_MULTI_THREAD) && !defined(_RWSTD_NO_TEST_AND_SET)

#if defined(__unix)

#include <machine/builtins.h>

#define _RWSTD_MT_INCREMENT(v) __MB(), __ATOMIC_INCREMENT_QUAD(&v), __MB()
#define _RWSTD_MT_DECREMENT(v) __MB(), __ATOMIC_DECREMENT_QUAD(&v), __MB()
#define _RWSTD_MT_SET(v,new)  __MB(), __ATOMIC_EXCH_QUAD(&v,new), __MB()
#endif // UNIX

#if defined(__VMS)
#include <machine/builtins.h>

#define _RWSTD_MT_INCREMENT(v) __MB(), __ATOMIC_INCREMENT_LONG(&v), __MB()
#define _RWSTD_MT_DECREMENT(v) __MB(), __ATOMIC_DECREMENT_LONG(&v), __MB()
#define _RWSTD_MT_SET(v,new)   __MB(), __ATOMIC_EXCH_LONG(&v,new),  __MB()

#endif // VMS

#else

#if defined(__DECCXX) && !defined(__DECFIXCXXL956)

#if defined(_RWSTD_MULTI_THREAD) && !defined(_RWSTD_NO_TEST_AND_SET)
#ifdef __WIN32__
#define _RWSTD_MT_INCREMENT(v) InterlockedIncrement(&v)
#define _RWSTD_MT_DECREMENT(v) InterlockedDecrement(&v)
#define _RWSTD_MT_SET(v,new) InterlockedExchange(&v,new)
#else
#define _RWSTD_MT_INCREMENT(v) v++
#define _RWSTD_MT_DECREMENT(v) v--
#define _RWSTD_MT_SET(v,new) v = new
#endif // __WIN32__
#else
#define _RWSTD_MT_INCREMENT(v) v++
#define _RWSTD_MT_DECREMENT(v) v--
#define _RWSTD_MT_SET(v,new) v = new
#endif // _RWSTD_MULTI_THREAD

#endif // CXXL 956

#endif // CXXL 1138

#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#pragma __extern_prefix __save
#pragma __extern_prefix "CXXL$" 
#endif

#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 _RWrwstd {
#endif

  //
  // _RWstring_noref_rep and _RWstring_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 _RWstring_noref_rep
  {
  public:
     _EXPLICIT _RWstring_noref_rep(long refs = 0)
      : _RWrefs_((bool)refs), _RWcapacity_(0), _RWnchars_(0)  {;}
    _RWstring_noref_rep(const _RWstring_noref_rep& r)
      : _RWrefs_((bool)r._RWrefs_), _RWcapacity_(0), _RWnchars_(0)  {;}
  
    typedef Allocator                        allocator_type;
    typedef _TYPENAME _RWSTD_ALLOC_SIZE_TYPE size_type;

  protected:

#if defined(__DECCXX) && !defined(__DECFIXCXXL1141)
#else
    bool            _RWrefs_;      // true if null ref, else false
#endif
    size_type       _RWcapacity_;  // Size of allocated memory
    size_type       _RWnchars_;    // Number of actual data values stored
#if defined(__DECCXX) && !defined(__DECFIXCXXL1141)
    bool            _RWrefs_;      // true if null ref, else false
#endif
  };

  template <class charT, class traits , class Allocator>
  class _RWSTDExportTemplate _RWstring_noref
   : public _RWstring_noref_rep<Allocator>
  {
  public:
    typedef _RWstring_noref_rep<Allocator> _RWstring_ref_rep_type;
    typedef _TYPENAME _RWstring_noref_rep<Allocator>::size_type size_type;
  
    _EXPLICIT _RWstring_noref (long=0) 
    { ; }
    _RWstring_noref (const _RWstring_noref<charT,traits,Allocator>& ref)
    { ; }
    ~_RWstring_noref() { ; }

  private:
    long _RWreferences () const
    { 
      return (long)_RWstring_noref_rep<Allocator>::_RWrefs_; 
    }
    void _RWsetRefCount (long r)
    { ; }
    void _RWaddReference ()
    { ; }
    long  _RWremoveReference ()
    { 
      return (long)_RWstring_noref_rep<Allocator>::_RWrefs_;
    }
    size_type length () const
    { 
      return _RWstring_noref_rep<Allocator>::_RWnchars_; 
    }
    size_type _RWgetCapac () const
    { 
      return _RWstring_noref_rep<Allocator>::_RWcapacity_;
    }
    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
  };


  //
  // _RWstring_ref_rep and _RWstring_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 _RWrw_string_mutex;
#endif /* _RWSTD_MULTI_THREAD */

  template <class Allocator>
  class _RWSTDExportTemplate _RWstring_ref_rep
  {
  public:
    //  the _RWrefs_ are initialized to 1 because of a problem
    //  where the destructor was being called when it
    //  should not be.
  
    _RWstring_ref_rep()
      : _RWrefs_(0), _RWcapacity_(0), _RWnchars_(0) {;}
    _RWstring_ref_rep(long x)
      : _RWrefs_(x), _RWcapacity_(0), _RWnchars_(0) {;}
    _RWstring_ref_rep(const _RWstring_ref_rep& r)
      : _RWrefs_(r._RWrefs_), _RWcapacity_(0), _RWnchars_(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 _RWmutex_;
#endif /* _RWSTD_MULTI_THREAD */  

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


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

    _RWstring_ref (const _RWstring_ref<charT,traits,Allocator>& ref)
      : _RWstring_ref_rep<Allocator>(ref._RWrefs_)
    { ; }
    ~_RWstring_ref() { ; }

  private:
    long _RWreferences () const 
    { 
      return _RWstring_ref_rep<Allocator>::_RWrefs_+1; 
    }

    void _RWsetRefCount (long r)       
    { 
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::_RWgetNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(_RWrw_string_mutex);
#else
         _RWSTDGuard guard(this->_RWmutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        _RWSTD_MT_SET(this->_RWrefs_,r-1);
      }
    }

    void _RWaddReference ()
    { 
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::_RWgetNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(_RWrw_string_mutex);
#else
         _RWSTDGuard guard(this->_RWmutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        _RWSTD_MT_INCREMENT(this->_RWrefs_);
      }
    }
    long  _RWremoveReference ()                
    {
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::_RWgetNullRep())
      {
#ifdef _RWSTD_NO_TEST_AND_SET
#ifdef _RWSTD_MULTI_THREAD
#ifdef _RWSTD_ONE_STRING_MUTEX
         _RWSTDGuard guard(_RWrw_string_mutex);
#else
         _RWSTDGuard guard(this->_RWmutex_);
#endif
#endif /* _RWSTD_MULTI_THREAD */
#endif /* _RWSTD_NO_TEST_AND_SET */
        return _RWunSafeRemoveReference();
      }
      else
        return 1;
    }
    long  _RWunSafeRemoveReference ()                
    {
      if (this != _RW_STD::basic_string<charT,traits,Allocator>::_RWgetNullRep())
      {
        _RWSTD_MT_DECREMENT(this->_RWrefs_);
        return this->_RWrefs_+1;
      }
      else
        return 1;
    }

    size_type length () const
    { return _RWstring_ref_rep<Allocator>::_RWnchars_; }
    size_type _RWgetCapac () const
    { return _RWstring_ref_rep<Allocator>::_RWcapacity_;}

    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
  };


  //
  // _RWnull_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(_RWstring_ref_rep<Allocator>) >
  struct _RWSTDExportTemplate _RWnull_string_ref_rep
  {
    //
    // _RWref_hdr_ has to be immediately followed by _RWeos_char_ !
    //
    stringRef      _RWref_hdr_;
    charT          _RWeos_char_; 

    _RWnull_string_ref_rep ()
      : _RWref_hdr_(1), _RWeos_char_(charT(0)) {;}
    _RWnull_string_ref_rep (const _RWnull_string_ref_rep<charT,traits, 
                                                       Allocator,stringRef>& r)
      : _RWref_hdr_(r._RWref_hdr_), _RWeos_char_(charT(0)) {;}

  };

#ifndef _RWSTD_NO_NAMESPACE
} // End of _RWrwstd 
#endif

#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#   pragma __extern_prefix __restore
#endif

#if defined(__DECCXX)
#   ifdef __PRAGMA_ENVIRONMENT
#      pragma __environment __restore
#   endif
#endif

#endif // __STD_STRING_REF


