// -*- C++ -*-
/***************************************************************************
 *
 * rw/locimpl - Declarations for the Standard Library locale private
 *              implementation 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_RW_LOCIMPL__
#define __STD_RW_LOCIMPL__

#include <stdcomp>

#if defined(__DECCXX) && !defined(__DECFIXCXXL1429) && !defined(__linux)
#include <machine/builtins.h>
#endif

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

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

// Macro for declaring all the has_facet and use_facet functions to be friends.

#ifndef _RWSTD_NO_FRIEND_TEMPLATES
#ifndef _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE
#define _RWSTD_FRIEND_USE_HAS_FACET                                     \
  template <class Facet> friend                                         \
      inline const Facet& use_facet (const locale&);                    \
  template <class Facet> friend                                         \
      inline bool has_facet (const locale&) _RWSTD_THROW_SPEC_NULL;
#else
#define _RWSTD_FRIEND_USE_HAS_FACET                                     \
  template <class Facet> friend                                         \
    inline const Facet& use_facet (const locale&,Facet*);               \
  template <class Facet> friend                                         \
    inline bool has_facet (const locale&,Facet*) _RWSTD_THROW_SPEC_NULL;
#endif // _RWSTD_NO_TEMPLATE_ON_RETURN_TYPE
#else
#define _RWSTD_FRIEND_USE_HAS_FACET public:
#endif

#ifndef _RWSTD_NO_NAMESPACE
namespace _RWrwstd {
  using std::use_facet;
  using std::locale;
#endif

// Implementation class template -- timepunct<charT>
//
// A facet such as this should have been included in the standard.  We just
// declare it here; the definition occurs below, after locale::facet has been
// defined.

template <class charT> class timepunct;

#ifdef __TURBOC__

// Instantiations that go in the library:

template class _RWSTDExport timepunct<char>;
#ifndef _RWSTD_NO_WIDE_CHAR
template class _RWSTDExport timepunct<wchar_t>;
#endif

#endif // __TURBOC__

// Implementation forward declarations:

class _RWSTDExport locale_imp;
class _RWSTDExport facet_imp;

class _RWSTDExport digit_map_base;
template <class charT> class _RWSTDExportTemplate digit_map;
template <class charT> class _RWSTDExportTemplate keyword_def;
template <class charT> class _RWSTDExportTemplate keyword_map;
template <class charT> class _RWSTDExportTemplate keyword_cracker;

class _RWSTDExport digit_reader_base;
template <class charT> class digit_reader_base_1;
template <class charT,class InputIterator>
  class _RWSTDExportTemplate digit_reader;

class _RWSTDExport digit_writer_base;
template <class charT>
  class _RWSTDExportTemplate digit_writer_base_1;
template <class charT,class OutputIterator>
  class _RWSTDExportTemplate digit_writer;

// ------------------------------------
// Implementation class -- ref_counted.
// ------------------------------------

// Common base class for reference-counted classes.  Currently used only by
// locale_imp and facet_imp, but could be used more generally.

class _RWSTDExport ref_counted {
  friend class _RW_STD::locale;

  size_t _RWref_count;
  #ifdef _RWSTD_MULTI_THREAD
  _RWSTDMutex _RWmutex;
  #endif

 protected:
  ref_counted (size_t initial_refs):
      _RWref_count(initial_refs) { }

  // Ensure derived class destructors are always virtual.
  virtual ~ref_counted (void);

  // Does protected access make these accessible to friends of derived classes?
  // We're about to find out ...

  static void add_reference (ref_counted *ob) {
#if defined(__DECCXX) && !defined(__DECFIXCXXL1429)

#if defined(__unix) && !defined(__linux) // size_t is 8 bytes, a quadword
     __MB(); __ATOMIC_INCREMENT_QUAD(&ob->_RWref_count); __MB();
#else
#if defined(__VMS) // size_t is 4 bytes, a longword
     __MB(); __ATOMIC_INCREMENT_LONG(&ob->_RWref_count); __MB();
#else // linux -- no thread safety
    ++ob->_RWref_count;
#endif
#endif

#else
    STDGUARD(ob->_RWmutex);
    ++ob->_RWref_count;
#endif

  }

  static void remove_reference (ref_counted *ob) {
    size_t refs;
    {
#if defined(__DECCXX) && !defined(__DECFIXCXXL1429)

#if defined(__unix) && !defined(__linux) // size_t is 8 bytes, a quadword
     __MB(); __ATOMIC_DECREMENT_QUAD(&ob->_RWref_count); __MB();
     __ATOMIC_EXCH_QUAD(&refs,ob->_RWref_count); __MB();
#else
#if defined(__VMS) // size_t is 4 bytes, a longword
     __MB(); __ATOMIC_DECREMENT_LONG(&ob->_RWref_count); __MB();
     __ATOMIC_EXCH_LONG(&refs,ob->_RWref_count); __MB();
#else // Linux, not thread safety
      refs=--ob->_RWref_count;
#endif
#endif

#else
      STDGUARD(ob->_RWmutex);
      refs=--ob->_RWref_count;
#endif
    }
    if (!refs)
      delete ob;
  }

  static void add_possible_reference (ref_counted *ob) {
    if (ob)
      add_reference(ob);
  }

  static void remove_possible_reference (ref_counted *ob) {
    if (ob)
      remove_reference(ob);
  }
};

// We would prefer to define locale::id and locale::facet entirely as nested
// classes of locale, but current compilers have problems with out-of-line
// definition of members of such classes, so we have to derive most of their
// behavior from unnested implementation classes:

// --------------------------------------
// Implementation class -- locale_id_imp.
// --------------------------------------

class _RWSTDExport locale_id_imp {
 protected:
  _MUTABLE size_t _RWid_value;
  static size_t _RWlast_used_id;
  
  locale_id_imp() :  _RWid_value(0) {;}

  #ifdef _RWSTD_MULTI_THREAD
#if defined(__DECCXX) && !defined(__DECFIXCXXL1078)
  static _RWSTDlocale_id_imp_Mutex _RWmutex;
#else
  static _RWSTDMutex _RWmutex;
#endif
  #endif

#if defined(__DECCXX) && !defined(__DECFIXCXXL957)
  void _RWinitid () const;
#else
  void _RWinit_id () const;
#endif
};

// ----------------------------------
// Implementation class -- facet_imp.
// ----------------------------------

class _RWSTDExport facet_imp: public ref_counted
{
  _RWSTD_FRIEND_USE_HAS_FACET
  friend class locale_imp;
  friend class _RW_STD::locale;
public:
  enum {
    _RWfacet_cat = 0,
    _RWok_implicit = 0,
#if defined(__DECCXX) && !defined(__DECFIXCXXL957)
    _RWinitdone = 1
#else
    _RWinit_done = 1
#endif
  };

 private:
  int _RWflags;
  int _RWcategory;     // Should be same type as locale::category

 protected:
  facet_imp (size_t refs, int cat=0):
      ref_counted(refs), _RWflags(0), _RWcategory(cat) { }

  // _RWinit_facet() is called by locale::_RWinstall the first time a facet is 
  // installed in its first locale.  Some facets override it to set up private 
  // data that depends on return values of virtual do_xxx functions that can't
  // be called yet in a constructor.

#if defined(__DECCXX) && !defined(__DECFIXCXXL957)
  virtual void _RWinitfacet (const locale*) { }
#else
  virtual void _RWinit_facet (const locale*) { }
#endif
};

#ifndef _RWSTD_NO_NAMESPACE
}
#endif

#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#   pragma __extern_prefix __restore
#endif
#include <locvector>
#if defined(__VMS) && defined(__DECCXX) && !defined(__DECFIXCXXL1158)
#pragma __extern_prefix __save
#pragma __extern_prefix "CXXL$" 
#endif

#ifndef _RWSTD_NO_NAMESPACE
namespace _RWrwstd {
#endif

// -----------------------------------
// Implementation class -- locale_imp.
// -----------------------------------

class _RWSTDExport locale_imp: public ref_counted
{
  _RWSTD_FRIEND_USE_HAS_FACET
  friend class _RW_STD::locale;

  // Same type as locale::category ...
  typedef int locale_category;
  locale_vector<_RW_STD::string> names_;
  locale_vector<facet_imp*> vec_;

  locale_category native_cats_;
  locale_category named_cats_;
  _RW_STD::string big_name_;
  bool named_;

  locale_imp (size_t sz=36, size_t refs=0);
  locale_imp (const locale_imp&,size_t refs);
  ~locale_imp ();

 public:
  inline facet_imp *get_facet (size_t i) const
    { return i<vec_.size()? vec_[i] : NULL; }

 private:
  const char *category_name (locale_category) const;

  // Map C library LC_xxx constants into facet categories.
  static locale_category map_category (locale_category);

  // Parse a locale name into category names.
  static bool parse_name (locale_vector<_RW_STD::string>&,const char*);
  // Combine category names to create a locale name.
  static bool build_name (_RW_STD::string&,const locale_vector<_RW_STD::string>&);
};

// ---------------------------------------
// Implementation class -- digit_map_base.
// ---------------------------------------

// A place to stash some static constants, so that each instantiation of the
// derived class rwstd::digit_map does not have to have a separate copy.

struct _RWSTDExport digit_map_base {
  enum { zero, minus, plus, X, x, E, e };
  static const char punct_chars[7];   // "0-+XxEe"
  static const char digit_chars[22];  // "0123456789ABCDEFabcdef"
  static const char char_values[22];  // Corresponding values in range 0-15
};

// --------------------------------------------------
// Implementation class template -- digit_map<charT>.
// --------------------------------------------------

// Maps digits into their corresponding numeric values, and caches widened
// equivalents of some number-related punctuation characters that don't depend
// on the numpunct facet.  A private instance of this class is hidden in
// ctype<charT> for use by numeric conversion facets.  A call to init must
// precede the first call to eval if is_inited() is false.  Eval returns 0-15
// if argument is a valid digit, a negative value otherwise.
//
// Specialized for char for performance.  The specialization assumes digits
// fit into the char code-set in an ASCII-like manner ('0'..'9' contiguous,
// 'A'..'F' contiguous, 'a'..'f' contiguous, '0' < 'A' < 'a').

_RWSTD_TEMPLATE
class _RWSTDExportTemplate digit_map<char>:
    public digit_map_base
{
 public:
  typedef char char_type;

  bool is_inited (void) const { return true; }
  const char *get_punct (void) const { return punct_chars; }
  inline int eval (char c) const;
  static inline const digit_map<char>&
      get_digit_map (const _RW_STD::ctype<char>&);
};

// Inline members of digit_map<char>:
//
// (Note that the definition of get_digit_map is in <rw/ctype> because it
//  has to come after the definition of ctype<char>.)

inline int digit_map<char>::eval (char c) const {
  int num=c;
  if ((num-='0')>9) {
    if (((num-=('A'-'0'))>5 && (num-=('a'-'A'))>5) || (num+=10)<10)
      num=-1;
  }
  return num;
}

template <class charT>
class _RWSTDExportTemplate digit_map:
    public digit_map_base
{
  bool inited;
  charT punct_array[7];
  charT digit_array[22];
  char value_array[22];
 public:
  typedef charT char_type;

  digit_map (void): inited(false) { }
  bool is_inited (void) const { return inited; }
  void init (const _RW_STD::ctype<charT>& ct);
  const charT *get_punct (void) const { return punct_array; }
  int eval (charT) const;

  // Can-opener for getting the digit_map out of a ctype.  (Works because of
  // the friend declaration in ctype_helper<charT> below.)
  static inline const digit_map<charT>&
      get_digit_map (const _RW_STD::ctype<charT>& ct)
  {
    if (!ct._RWdigit_map.inited)
      (_RWSTD_CONST_CAST(digit_map<char_type>&,ct._RWdigit_map))
          .init(ct);
    return ct._RWdigit_map;
  }
};

// ----------------------------------------------------
// Implementation class template -- keyword_def<charT>.
// ----------------------------------------------------

// Helper class used in parsing keywords from input (such as true/false in
// num_get, month and day names in time_get, etc).

template <class charT>
class _RWSTDExportTemplate keyword_def {
 public:
  const charT *s;
  int v;
};

// ----------------------------------------------------
// Implementation class template -- keyword_map<charT>.
// ----------------------------------------------------

// Defines a set of keywords to be recognized on input and to be written to
// output.  Private instances are hidden in numpunct (for true/false) and
// rwstd::timepunct (for month and weekday names).

template <class charT>
class _RWSTDExportTemplate keyword_map {
 public:
  int num_defs_;
  const keyword_def<charT> *defs_;
};

// ---------------------------------------------------
// Implementation class template -- punct_data<charT>.
// ---------------------------------------------------

// Common base class for rwstd::numpunct_data and rwstd::moneypunct_data.

template <class charT>
class _RWSTDExportTemplate punct_data {
  friend class digit_reader_base_1<charT>;
  friend class digit_writer_base_1<charT>;
 public:
  typedef _RW_STD::basic_string<charT,_RW_STD::char_traits<charT>,_RW_STD::allocator<charT> > string_type;
 protected:
  charT dp_, ts_;
  _RW_STD::string gr_;
};

// ------------------------------------------------------
// Implementation function templates -- create_xxx_facet.
// ------------------------------------------------------

// The facet_maker<Facet>::maker_func functions described above delegate the
// actual construction of facets to three inline function templates named
// create_xxx_facet, where xxx is 'classic' or 'native' or 'named'.  The
// default (template) versions of these functions construct facets as follows:
//
//   classic -- default constructor for the facet with only the refs argument.
//   native -- calls create_named_facet with a name of "".
//   named -- calls create_classic_facet, ignoring the passed name.
//
// This default behavior is overridden (specialized) for certain facet types.
// In particular, create_named_facet is specialized for all facet types that
// have a derived _byname version, to construct that version with the passed
// name (see <rw/rwlocale>) and create_native_facet is specialized for all
// facet types whose "native" behavior (as determined by the vendor) differs
// from the byname facet with a name of "" (see <rw/vendor>).

template <class Facet>
inline Facet*  _RWSTDExportTemplate create_named_facet
    (Facet*,const char*,size_t refs);

template <class Facet>
inline Facet*  _RWSTDExportTemplate create_native_facet (Facet*);

template <class Facet>
inline Facet* _RWSTDExportTemplate create_classic_facet (Facet*)
{
 return new Facet(1);
}

// ----------------------------------------------------
// Implementation class template -- facet_maker<Facet>.
// ----------------------------------------------------

// When use_facet (inline) finds that a locale does not contain an explicit
// facet of the requested type, it calls locale::_RWmake_explicit (non-template)
// to create or find the facet in a cache, and install it in the locale.  As a
// parameter to _RWmake_explicit, use_facet passes a call-back function which
// _RWmake_explicit can call to construct a facet of the requested type if
// needed.  The call-back functions are obtained by instantiating the following
// helper class template:

template <class Facet>
class _RWSTDExportTemplate facet_maker {
 public:
  static facet_imp *maker_func (int t, const char* name, size_t refs)
  {
    if (t==0)
      return create_classic_facet ((Facet*)0);
    else if (t==1)
      return create_native_facet ((Facet*)0);
    else
      return create_named_facet ((Facet*)0,name,refs);
  }
};

// Typedef for the above facet_maker functions, for use in the declaration
// of locale::_RWmake_explicit.

typedef facet_imp *facet_maker_func (int,const char*,size_t);

#ifndef _RWSTD_NO_NAMESPACE
} // namespace _RWrwstd
#endif

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

#ifdef _RWSTD_COMPILE_INSTANTIATE
#include <locimpl.cc>
#endif


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

#endif // __STD_RW_LOCIMPL__

