text: /* /////////////////////////////////////////////////////////////////////////
   * File:        stlsoft/string/special_string_instance.hpp
   *
   * Purpose:     Special string instance class template.
   *
   * Created:     3rd June 2006
   * Updated:     29th September 2016
   *
   * Thanks to:   Pablo Aguilar for spotting my omission of string access shims
   *              for special_string_instance_1.
   *
   * Home:        http://stlsoft.org/
   *
   * Copyright (c) 2006-2016, Matthew Wilson and Synesis Software
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   * - Redistributions of source code must retain the above copyright notice,
   *   this list of conditions and the following disclaimer.
   * - Redistributions in binary form must reproduce the above copyright
   *   notice, this list of conditions and the following disclaimer in the
   *   documentation and/or other materials provided with the distribution.
   * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
   *   names of any contributors may be used to endorse or promote products
   *   derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * ////////////////////////////////////////////////////////////////////// */
  
  
  /** \file stlsoft/string/special_string_instance.hpp
   *
   * \brief [C++ only] Definition of the stlsoft::special_string_instance
   *  class template
   *   (\ref group__library__string "String" Library).
   */
  
  #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE
  #define STLSOFT_INCL_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE
  
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  # define STLSOFT_VER_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE_MAJOR       1
  # define STLSOFT_VER_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE_MINOR       3
  # define STLSOFT_VER_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE_REVISION    4
  # define STLSOFT_VER_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE_EDIT        26
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /* /////////////////////////////////////////////////////////////////////////
   * Compatibility
   */
  
  /*
  [Incompatibilies-start]
  STLSOFT_COMPILER_IS_MSVC:       _MSC_VER<1200
  [Incompatibilies-end]
   */
  
  /* Compatibility
  [<[STLSOFT-AUTO:NO-DOCFILELABEL]>]
  [<[STLSOFT-AUTO:NO-UNITTEST]>]
  */
  
  /* /////////////////////////////////////////////////////////////////////////
   * Includes
   */
  
  #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  # include <stlsoft/stlsoft.h>
  #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  # include <stlsoft/memory/auto_buffer.hpp>
  #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  #ifndef STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE
  # include <stlsoft/meta/is_same_type.hpp>
  #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_IS_SAME_TYPE */
  #ifndef STLSOFT_INCL_STLSOFT_META_HPP_SELECT_FIRST_TYPE_IF
  # include <stlsoft/meta/select_first_type_if.hpp>
  #endif /* !STLSOFT_INCL_STLSOFT_META_HPP_SELECT_FIRST_TYPE_IF */
  #ifndef STLSOFT_INCL_STLSOFT_SYNCH_HPP_LOCK_SCOPE
  # include <stlsoft/synch/lock_scope.hpp>
  #endif /* !STLSOFT_INCL_STLSOFT_SYNCH_HPP_LOCK_SCOPE */
  
  /* /////////////////////////////////////////////////////////////////////////
   * Namespace
   */
  
  #ifndef _STLSOFT_NO_NAMESPACE
  namespace stlsoft
  {
  #endif /* _STLSOFT_NO_NAMESPACE */
  
  /* /////////////////////////////////////////////////////////////////////////
   * Classes
   */
  
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  
  template<   ss_typename_param_k C
          ,   ss_size_t           N
          ,   ss_typename_param_k A
          ,   ss_typename_param_k A0
          >
  struct ssi_buffer
  {
  /// \name Member Types
  /// @{
  public:
      /// The character type
      typedef C                               char_type;
      /// The allocator type
      typedef A                               allocator_type;
      /// The size type
      typedef ss_size_t                       size_type;
      /// The argument type
      typedef A0                              argument_0_type;
      /// The class type
      typedef ssi_buffer<C, N, A, A0>         class_type;
  private:
      /// The buffer type
      typedef stlsoft::auto_buffer<
          char_type
  #if defined(STLSOFT_COMPILER_IS_BORLAND)
      ,   128
  #else /* ? compiler */
      ,   N
  #endif /* compiler */
      ,   allocator_type
      >                                       buffer_type_;
  /// @}
  
  /// \name Construction
  /// @{
  public:
      ssi_buffer()
          : m_len(0)
          , m_buffer(0)
      {}
  #if 0 || \
      defined(STLSOFT_COMPILER_IS_CLANG) || \
      defined(STLSOFT_COMPILER_IS_GCC) || \
      0
      ssi_buffer(class_type const& rhs)
          : m_len(rhs.m_len)
          , m_buffer(rhs.m_len + 1)
      {
          ::memcpy(&m_buffer[0], &rhs.m_buffer[0], sizeof(char_type) * (1u + m_len));
      }
  #endif /* compiler */
  
      void init(size_type (*pfn)(char_type*, size_type))
      {
          // We don't pass NULL here, just in case
          char_type   empty   =   '\0';
          size_type   cch     =   pfn(&empty, 0);
  
          if(m_buffer.resize(1 + cch))
          {
              for(;;)
              {
                  cch = pfn(&m_buffer[0], m_buffer.size());
  
                  if(cch < m_buffer.size())
                  {
                      m_len = cch;
                      break;
                  }
                  else
                  {
                      if(!m_buffer.resize(2 * m_buffer.size()))
                      {
                          m_buffer.resize(0);
                          break;
                      }
                  }
              }
          }
  
          m_buffer[m_len] = '\0';
      }
  
      void init(argument_0_type arg0, size_type (*pfn)(argument_0_type, char_type*, size_type))
      {
          // We don't pass NULL here, just in case
          char_type   empty   =   '\0';
          size_type   cch     =   pfn(arg0, &empty, 0);
  
          if(m_buffer.resize(1 + cch))
          {
              for(;;)
              {
                  cch = pfn(arg0, &m_buffer[0], m_buffer.size());
  
                  if(cch < m_buffer.size())
                  {
                      m_len = cch;
                      break;
                  }
                  else
                  {
                      if(!m_buffer.resize(2 * m_buffer.size()))
                      {
                          m_buffer.resize(0);
                          break;
                      }
                  }
              }
          }
  
          m_buffer[m_len] = '\0';
      }
  /// @}
  
  /// \name Accessors
  /// @{
  public:
      char_type const* data() const
      {
          return m_buffer.data();
      }
      size_type       length() const
      {
          return m_len;
      }
  /// @}
  
  /// \name Members
  /// @{
  private:
      size_type       m_len;
      buffer_type_    m_buffer;
  /// @}
  };
  
  template<   ss_typename_param_k C
          ,   ss_size_t           N
          ,   ss_typename_param_k A
          ,   ss_typename_param_k A0
          >
  struct ssi_buffer_non_static
      : public ssi_buffer<C, N, A, A0>
  {
  /// \name Member Types
  /// @{
  public:
      typedef ssi_buffer<C, N, A, A0>                         ssi_buffer_type;
      typedef ssi_buffer<C, N, A, A0>                         parent_class_type;
      typedef ssi_buffer_non_static<C, N, A, A0>              class_type;
  
      typedef ss_typename_type_k ssi_buffer_type::char_type   char_type;
      typedef ss_typename_type_k ssi_buffer_type::size_type   size_type;
  /// @}
  
  /// \name Construction
  /// @{
  public:
      ssi_buffer_non_static(size_type (*pfn)(char_type*, size_type))
      {
          parent_class_type::init(pfn);
      }
      ssi_buffer_non_static(A0 a0, size_type (*pfn)(A0, char_type*, size_type))
      {
          parent_class_type::init(a0, pfn);
      }
  #if 0 || \
      defined(STLSOFT_COMPILER_IS_CLANG) || \
      defined(STLSOFT_COMPILER_IS_GCC) || \
      0
      ssi_buffer_non_static(class_type const& rhs)
          : parent_class_type(rhs)
      {}
  #endif /* compiler */
  /// @}
  
  /// \name Accessors
  /// @{
  public:
      char_type const* data() const
      {
          return parent_class_type::data();
      }
      size_type       length() const
      {
          return parent_class_type::length();
      }
  /// @}
  
  /// \name Not to be implemented
  /// @{
  private:
  #if 1 && \
      !defined(STLSOFT_COMPILER_IS_CLANG) && \
      !defined(STLSOFT_COMPILER_IS_GCC) && \
      1
      ssi_buffer_non_static(class_type const&);
  #endif /* compiler */
      class_type& operator =(class_type const&);
  /// @}
  };
  
  template<   ss_typename_param_k C
          ,   ss_size_t           N
          ,   ss_typename_param_k A
          ,   ss_typename_param_k A0
          ,   ss_typename_param_k P   // Passes policy type, from which spin_mutex_type is elicited, so non-statics do not need to specify it
          >
  struct ssi_buffer_static
  {
  /// \name Member Types
  /// @{
  public:
      typedef ssi_buffer<C, N, A, A0>                         ssi_buffer_type;
      typedef ssi_buffer_static<C, N, A, A0, P>               class_type;
  
      typedef ss_typename_type_k ssi_buffer_type::char_type   char_type;
      typedef ss_typename_type_k ssi_buffer_type::size_type   size_type;
  private:
      typedef P                                               policy_type;
      typedef ss_typename_type_k policy_type::spin_mutex_type spin_mutex_type;
      typedef ss_typename_type_k policy_type::atomic_int_type atomic_int_type;
  /// @}
  
  /// \name Construction
  /// @{
  public:
      ssi_buffer_static(size_type (*pfn)(char_type*, size_type))
          : m_buffer(get_buffer(pfn))
      {}
      ssi_buffer_static(A0 a0, size_type (*pfn)(A0, char_type*, size_type))
          : m_buffer(a0, get_buffer(a0, pfn))
      {}
  #if 0 || \
      defined(STLSOFT_COMPILER_IS_CLANG) || \
      defined(STLSOFT_COMPILER_IS_GCC) || \
      0
      ssi_buffer_static(class_type const& rhs)
          : m_buffer(rhs.m_buffer)
      {}
  #endif /* compiler */
  /// @}
  
  /// \name Accessors
  /// @{
  public:
      char_type const* data() const
      {
          return m_buffer.data();
      }
      size_type       length() const
      {
          return m_buffer.length();
      }
  /// @}
  
  /// \name Implementation
  /// @{
  private:
      static ssi_buffer_type& get_buffer(size_type (*pfn)(char_type*, size_type))
      {
          static atomic_int_type                  s_count =   0;
          static bool                             s_bInit =   false;
          spin_mutex_type                         mx(&s_count);
          stlsoft::lock_scope<spin_mutex_type>    lock(mx);
  
          static ssi_buffer_type                  s_buffer;
  
          if(!s_bInit)
          {
              s_buffer.init(pfn);
  
              s_bInit = true;
          }
  
          return s_buffer;
      }
      static ssi_buffer_type& get_buffer(A0 a0, size_type (*pfn)(A0, char_type*, size_type))
      {
          static atomic_int_type                  s_count =   0;
          static bool                             s_bInit =   false;
          spin_mutex_type                         mx(&s_count);
          stlsoft::lock_scope<spin_mutex_type>    lock(mx);
  
          static ssi_buffer_type                  s_buffer;
  
          if(!s_bInit)
          {
              s_buffer.init(a0, pfn);
  
              s_bInit = true;
          }
  
          return s_buffer;
      }
  /// @}
  
  /// \name Members
  /// @{
  private:
      ssi_buffer_type&    m_buffer;
  /// @}
  
  /// \name Not to be implemented
  /// @{
  private:
  #if 1 && \
      !defined(STLSOFT_COMPILER_IS_CLANG) && \
      !defined(STLSOFT_COMPILER_IS_GCC) && \
      1
      ssi_buffer_static(class_type const&);
  #endif /* compiler */
      class_type& operator =(class_type const&);
  /// @}
  };
  
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  
  /** \brief Special string instance class template.
   *
   * \ingroup group__library__string
   *
   * \param P The SSI policy type.
   *
   * The policy type provides the following:
   *
   * - A member constant <code>internalBufferSize</code> that determines the
   *   size of the SSI's internal
   *   \link stlsoft::auto_buffer auto_buffer\endlink's internal buffer size.
   * - A static method <code>get_value(char_type* buffer, size_type cchBuffer)</code>
   *   that has the
   * - A member constant <code>allowImplicitConversion</code> that determines
   *   whether an implicit conversion operator (to
   *   <code>char_type const*</code>) is to be provided.
   */
  template <ss_typename_param_k P>
  class special_string_instance_0
  {
  /// \name Member Types
  /// @{
  public:
      /// \brief The policy type
      typedef P                                                                   policy_type;
      /// \brief The current instantiation of the template.
      typedef special_string_instance_0<P>                                        class_type;
      /// \brief The character type
      typedef ss_typename_type_k policy_type::char_type                           char_type;
      /// \brief The size type
      typedef ss_typename_type_k policy_type::size_type                           size_type;
  
      /// \brief The character type for ANSI specialisations
      ///
      /// \note This is used in the specification of the string access shim
      ///  functions.
  private:
      enum { charTypeIsAnsi = is_same_type<ss_char_a_t, char_type>::value };
  public:
      typedef ss_typename_type_k select_first_type_if<
          ss_char_a_t const*
      ,   void
      ,   charTypeIsAnsi
      >::type                                                                     cstring_a_type;
      /// \brief The character type for Unicode specialisations
      ///
      /// \note This is used in the specification of the string access shim
      ///  functions.
  private:
      enum { charTypeIsWide = is_same_type<ss_char_w_t, char_type>::value };
  public:
      typedef ss_typename_type_k select_first_type_if<
          ss_char_w_t const*
      ,   void
      ,   charTypeIsWide
      >::type                                                                     cstring_w_type;
  private:
      typedef ss_typename_type_k policy_type::pfn_type                            pfn_type;
  private:
      // This section allows for the case where the policy does not define an
      // allocator, which it indicates by defining its member type
      // allocator_type to be void.
      typedef ss_typename_type_k policy_type::allocator_type                      putative_allocator_type;
      enum
      {
          policy_has_allocator_type       =   (0 != size_of<putative_allocator_type>::value)
      };
      typedef ss_typename_type_k allocator_selector<char_type>::allocator_type    backup_allocator_type;
  public:
      /// \brief The allocator type
      typedef ss_typename_type_k select_first_type_if<
          putative_allocator_type
      ,   backup_allocator_type
      ,   policy_has_allocator_type
      >::type                                                                     allocator_type;
  private:
      enum { allowImplicitConversion = policy_type::allowImplicitConversion };
  public:
      /// \brief The implicit conversion operator type
      typedef ss_typename_type_k select_first_type_if<
          char_type const*
      ,   void
      ,   allowImplicitConversion
      >::type                                                                     implicit_conversion_type;
  private:
      // This section accounts for whether the policy indicates shared state.
      // If so, then the buffer type resolves to the appropriate
      // specialisation of ssi_buffer_static, which stores a threadsafe buffer
      // shared by all instances. If not, then the buffer type resolves to
      // ssi_buffer_non_static, which stores a buffer per instance.
      enum
      {
          policy_indicates_shared_state   =   (0 != policy_type::sharedState)
      };
  
      struct null_argument
      {};
  
      enum { internalBufferSize = policy_type::internalBufferSize };
      typedef ssi_buffer_static<
          char_type
      ,   internalBufferSize
      ,   allocator_type
      ,   null_argument
      ,   policy_type // Passes policy type, from which spin_mutex_type is elicited, so non-statics do not need to specify it
      >                                                                           ssi_buffer_static_type;
      typedef ssi_buffer_non_static<
          char_type
      ,   internalBufferSize
      ,   allocator_type
      ,   null_argument
      >                                                                           ssi_buffer_non_static_type;
  
      typedef ss_typename_type_k select_first_type_if<
          ssi_buffer_static_type
      ,   ssi_buffer_non_static_type
      ,   policy_indicates_shared_state
      >::type                                                                     buffer_type_;
  /// @}
  
  /// \name Construction
  /// @{
  public:
      special_string_instance_0()
          : m_buffer(policy_type::get_fn())
      {}
  /// @}
  
  /// \name Accessors
  /// @{
  public:
      size_type       length() const
      {
          return m_buffer.length();
      }
      size_type       size() const
      {
          return length();
      }
  
      char_type const* data() const
      {
          return m_buffer.data();
      }
      char_type const* c_str() const
      {
          return data();
      }
  
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
      cstring_a_type  c_str_a() const
      {
          return c_str();
      }
      cstring_w_type  c_str_w() const
      {
          return c_str();
      }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  /// @}
  
  /// \name Operators
  /// @{
  public:
  #if !defined(STLSOFT_COMPILER_IS_BORLAND)
      operator implicit_conversion_type () const
      {
          return this->c_str();
      }
  #endif /* compiler */
  /// @}
  
  /// \name Operations
  /// @{
  public:
      static size_type get(char_type* buffer, size_type cchBuffer)
      {
          return (policy_type::get_fn())(buffer, cchBuffer);
      }
  /// @}
  
  /// \name Members
  /// @{
  private:
      buffer_type_ m_buffer;
  /// @}
  };
  
  /** \brief Special string instance class template.
   *
   * \ingroup group__library__string
   *
   * \param P The SSI policy type.
   *
   * The policy type provides the following:
   *
   * - A member constant <code>internalBufferSize</code> that determines the
   *   size of the SSI's internal
   *   \link stlsoft::auto_buffer auto_buffer\endlink's internal buffer size.
   * - A static method <code>get_value(char_type* buffer, size_type cchBuffer)</code>
   *   that has the
   * - A member constant <code>allowImplicitConversion</code> that determines
   *   whether an implicit conversion operator (to
   *   <code>char_type const*</code>) is to be provided.
   */
  template <ss_typename_param_k P>
  class special_string_instance_1
  {
  /// \name Member Types
  /// @{
  public:
      /// \brief The policy type.
      typedef P                                                                   policy_type;
      /// \brief The current instantiation of the template.
      typedef special_string_instance_1<P>                                        class_type;
      /// \brief The character type
      typedef ss_typename_type_k policy_type::char_type                           char_type;
      /// \brief The size type
      typedef ss_typename_type_k policy_type::size_type                           size_type;
      /// \brief The argument type
      typedef ss_typename_type_k policy_type::argument_0_type                     argument_0_type;
  
      /// \brief The character type for ANSI specialisations
      ///
      /// \note This is used in the specification of the string access shim
      ///  functions.
  private:
      enum { charTypeIsAnsi = is_same_type<ss_char_a_t, char_type>::value };
  public:
      typedef ss_typename_type_k select_first_type_if<
          ss_char_a_t const*
      ,   void
      ,   charTypeIsAnsi
      >::type                                                                     cstring_a_type;
      /// \brief The character type for Unicode specialisations
      ///
      /// \note This is used in the specification of the string access shim
      ///  functions.
  private:
      enum { charTypeIsWide = is_same_type<ss_char_w_t, char_type>::value };
  public:
      typedef ss_typename_type_k select_first_type_if<
          ss_char_w_t const*
      ,   void
      ,   charTypeIsWide
      >::type                                                                     cstring_w_type;
  private:
      typedef ss_typename_type_k policy_type::pfn_type                            pfn_type;
  private:
      // This section allows for the case where the policy does not define an
      // allocator, which it indicates by defining its member type
      // allocator_type to be void.
      typedef ss_typename_type_k policy_type::allocator_type                      putative_allocator_type;
      enum
      {
          policy_has_allocator_type       =   (0 != size_of<putative_allocator_type>::value)
      };
      typedef ss_typename_type_k allocator_selector<char_type>::allocator_type    backup_allocator_type;
  public:
      /// \brief The allocator type
      typedef ss_typename_type_k select_first_type_if<
          putative_allocator_type
      ,   backup_allocator_type
      ,   policy_has_allocator_type
      >::type                                                                     allocator_type;
  
      /// \brief The implicit conversion operator type
  private:
      enum { allowImplicitConversion = policy_type::allowImplicitConversion };
  public:
      typedef ss_typename_type_k select_first_type_if<
          char_type const*
      ,   void
      ,   allowImplicitConversion
      >::type                                                                     implicit_conversion_type;
  private:
      // This section accounts for whether the policy indicates shared state.
      // If so, then the buffer type resolves to the appropriate
      // specialisation of ssi_buffer_static, which stores a threadsafe buffer
      // shared by all instances. If not, then the buffer type resolves to
      // ssi_buffer_non_static, which stores a buffer per instance.
      enum
      {
          policy_indicates_shared_state   =   (0 != policy_type::sharedState)
      };
  
      enum { internalBufferSize = policy_type::internalBufferSize };
      typedef ssi_buffer_static<
          char_type
      ,   internalBufferSize
      ,   allocator_type
      ,   argument_0_type
      ,   policy_type // Passes policy type, from which spin_mutex_type is elicited, so non-statics do not need to specify it
      >                                                                           ssi_buffer_static_type;
      typedef ssi_buffer_non_static<
          char_type
      ,   internalBufferSize
      ,   allocator_type
      ,   argument_0_type
      >                                                                           ssi_buffer_non_static_type;
  
      typedef ss_typename_type_k select_first_type_if<
          ssi_buffer_static_type
      ,   ssi_buffer_non_static_type
      ,   policy_indicates_shared_state
      >::type                                                                     buffer_type_;
  
  /// @}
  
  /// \name Construction
  /// @{
  public:
      special_string_instance_1(argument_0_type argument)
          : m_buffer(argument, policy_type::get_fn())
      {}
  /// @}
  
  /// \name Operations
  /// @{
  public:
      static size_type get(argument_0_type argument, char_type* buffer, size_type cchBuffer)
      {
          return (policy_type::get_fn())(argument, buffer, cchBuffer);
      }
  /// @}
  
  /// \name Attributes
  /// @{
  public:
      char_type const* c_str() const
      {
          return m_buffer.data();
      }
      char_type const* data() const
      {
          return m_buffer.data();
      }
      size_type       length() const
      {
          return m_buffer.length();
      }
      size_type       size() const
      {
          return length();
      }
  
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
      cstring_a_type  c_str_a() const
      {
          return c_str();
      }
      cstring_w_type  c_str_w() const
      {
          return c_str();
      }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  /// @}
  
  /// \name Operators
  /// @{
  public:
  #if !defined(STLSOFT_COMPILER_IS_BORLAND)
      operator implicit_conversion_type () const
      {
          return this->c_str();
      }
  #endif /* compiler */
  /// @}
  
  /// \name Member Types
  /// @{
  private:
      buffer_type_ m_buffer;
  /// @}
  };
  
  /* /////////////////////////////////////////////////////////////////////////
   * Shims
   */
  
  /** \brief \ref group__concept__shim__string_access__c_str_ptr_null for stlsoft::special_string_instance_0
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::char_type const* c_str_ptr_null(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str() : NULL;
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_a_type c_str_ptr_null_a(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str_a() : NULL;
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_w_type c_str_ptr_null_w(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str_w() : NULL;
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_ptr for stlsoft::special_string_instance_0
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::char_type const* c_str_ptr(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_a_type c_str_ptr_a(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str_a();
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_w_type c_str_ptr_w(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str_w();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_data for stlsoft::special_string_instance_0
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::char_type const* c_str_data(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_a_type c_str_data_a(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str_a();
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_0<P>::cstring_w_type c_str_data_w(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.c_str_w();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_len for stlsoft::special_string_instance_0
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      return ssi.length();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len_a(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      // If this fires, you're trying to invoke c_str_len_w() on an SSI
      // whose policy defines the character type to be something other
      // than char.
      ss_char_a_t const* const special_string_instance_must_use_narrow_character = ssi.c_str_a();
  
      STLSOFT_SUPPRESS_UNUSED(special_string_instance_must_use_narrow_character);
  
      return ssi.length();
  }
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len_w(stlsoft_ns_qual(special_string_instance_0)<P> const& ssi)
  {
      // If this fires, you're trying to invoke c_str_len_w() on an SSI
      // whose policy defines the character type to be something other
      // than wchar_t.
      ss_char_w_t const* const special_string_instance_must_use_wide_character = ssi.c_str_w();
  
      STLSOFT_SUPPRESS_UNUSED(special_string_instance_must_use_wide_character);
  
      return ssi.length();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_ptr_null for stlsoft::special_string_instance_1
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::char_type const* c_str_ptr_null(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str() : NULL;
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_a_type c_str_ptr_null_a(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str_a() : NULL;
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_w_type c_str_ptr_null_w(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return (0 != ssi.length()) ? ssi.c_str_w() : NULL;
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_ptr for stlsoft::special_string_instance_1
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::char_type const* c_str_ptr(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_a_type c_str_ptr_a(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str_a();
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_w_type c_str_ptr_w(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str_w();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_data for stlsoft::special_string_instance_1
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::char_type const* c_str_data(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_a_type c_str_data_a(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str_a();
  }
  template <ss_typename_param_k P>
  inline ss_typename_type_ret_k special_string_instance_1<P>::cstring_w_type c_str_data_w(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.c_str_w();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /** \brief \ref group__concept__shim__string_access__c_str_len for stlsoft::special_string_instance_1
   *
   * \ingroup group__concept__shim__string_access
   */
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      return ssi.length();
  }
  #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len_a(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      // If this fires, you're trying to invoke c_str_len_w() on an SSI
      // whose policy defines the character type to be something other
      // than char.
      ss_char_a_t const* const special_string_instance_must_use_narrow_character = ssi.c_str_a();
  
      STLSOFT_SUPPRESS_UNUSED(special_string_instance_must_use_narrow_character);
  
      return ssi.length();
  }
  template <ss_typename_param_k P>
  inline ss_size_t c_str_len_w(stlsoft_ns_qual(special_string_instance_1)<P> const& ssi)
  {
      // If this fires, you're trying to invoke c_str_len_w() on an SSI
      // whose policy defines the character type to be something other
      // than wchar_t.
      ss_char_w_t const* const special_string_instance_must_use_wide_character = ssi.c_str_w();
  
      STLSOFT_SUPPRESS_UNUSED(special_string_instance_must_use_wide_character);
  
      return ssi.length();
  }
  #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  
  /* ////////////////////////////////////////////////////////////////////// */
  
  #ifndef _STLSOFT_NO_NAMESPACE
  } // namespace stlsoft
  #endif /* _STLSOFT_NO_NAMESPACE */
  
  /* ////////////////////////////////////////////////////////////////////// */
  
  #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SPECIAL_STRING_INSTANCE */
  
  /* ///////////////////////////// end of file //////////////////////////// */
  