C++ Locales
by Nathan Myers

Listing One
#include <iosfwd> // istream, ostream
#include <ctime>  // struct tm
namespace ChronLib {
class Date {
  long day;  // days since 1752-09-14
public:
  enum Month { jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
  Date(int year, Month month, int day);
  void asCLibTime(struct tm*) const;
};
std::ostream&
operator<< (std::ostream& os, Date const& date);
std::istream&
operator>> (std::istream& is, Date& date);
}

Listing Two
namespace std {
  template <class Facet>
    Facet const&
    use_facet(locale const& loc);
};

Listing Three
// date_insert.C
#include <ctime>   // struct tm
#include <ostream> // ostream
#include <locale>  // use_facet
#include "date.h"

std::ostream&
ChronLib::operator<<(std::ostream& os, Date const& date)
{
  using namespace std;
  ostream::sentry cerberus(os);
  if (!cerberus) return os;
  struct tm tmbuf;
  date.asCLibTime(&tmbuf);
  use_facet< time_put<char> >(os.getloc())
    .put(os, os, os.fill(), &tmbuf, 'x');
  return os;
}

Listing Four
#include <iostream> // cout
#include <locale>   // locale
#include "date.h"

int main()  {
  using namespace std;
  using ChronLib::Date;
  cout.imbue(locale(""));
  cout << Date(1942, Date::dec, 7) << endl;
  return 0;
}

Listing Five
//stats.h
#include <locale>
class Stats : public std::locale::facet {
 public:
  static std::locale::id id;
  Stats (int ss)       : shoeSize_(ss) {}
  int shoeSize() const { return shoeSize_; }
 private:
  Stats (Stats&);           // not defined:
  void operator=(Stats&);   // not defined:
  int shoesize_;
};
//stats.C
#include "stats.h"
std::locale::id Stats::id;

Listing Six
locale here(locale(), new Stats(48));
int ss = use_facet<Stats>(here).shoesize();

Listing Seven
class locale {
 public:
  class facet;
  class id;
 ~locale() { if (imp_->refs_-- == 0) delete imp_; }
  locale() : imp_(__global_imp) { ++imp_->refs; }
  explicit locale(char const* name);
  locale(locale const& other)
    : imp_(other.imp_) { ++imp_->refs_; }
  locale& operator=(locale const& l);
  template <class Facet>
    locale(locale const& other, Facet* f);
  // other constructors
  template <class Facet>
    friend Facet const& use_facet(locale const&);
private:
  struct imp {
    size_t refs_; // ref-counter
    vector<facet*> facets_;
    ~imp();
    imp(imp const&);
  };
  imp* imp_;
};

Listing Eight
class locale::facet {
  friend class locale;
  friend class locale::imp;
  size_t refs_;    //initially 0 = One reference
 protected:
  explicit facet(int refs = 0);
  virtual ~facet();
};

Listing Nine
class locale::id {
  friend class locale;
  size_t index_;
  static size_t mark_;
};

Listing Ten
template <class Facet>
locale::locale(locale const& other, Facet* f) {
  imp_ = new imp(*other.imp_);
  imp_->refs_ = 0;  // one reference
  size_t& index = Facet::id.index_;
  if (!index)
     index = ++Facet::id.mark_;
  if (index >= imp_->facets_.size())
    imp_->facets_.resize(index+1);
  ++f->facet::refs_;
  facet*& fpr = imp_->facets_[index];
  if (fpr) --fpr->refs_;
  fpr = f;
}

Listing Eleven
template <class Facet>
  inline Facet const& use_facet(locale const& loc)
{
  size_t index = Facet::id.index_;
  locale::facet* fp;
  if (index >= loc.imp_->facets_.size() ||
      (fp = loc.imp_->facets_[index]) == 0)
    throw bad_cast();
  return static_cast<Facet const&>(*fp);
}

