Skip to content

Instantly share code, notes, and snippets.

@dgodfrey206
Last active December 28, 2015 19:49
Show Gist options
  • Save dgodfrey206/7553400 to your computer and use it in GitHub Desktop.
Save dgodfrey206/7553400 to your computer and use it in GitHub Desktop.
My try at the address_put facet from the book Standard C++ IOStreams and Locales
#include <iostream>
#include <string>
#include <locale>
#include <typeinfo>
#include <map>
template<class charT>
class address
{
template<class CharT>
friend std::basic_ostream<CharT>&
operator<<(std::basic_ostream<CharT>&, const address<CharT>&);
template<class CharT>
friend std::basic_istream<CharT>
operator>>(std::basic_istream<CharT>&, address<CharT>&);
typedef std::basic_string<charT> string;
public:
address(string _name, string _address)
: name(_name), street_address(_address)
{ }
private:
string name, street_address;
};
template<class charT, class Iter = std::ostreambuf_iterator<charT>>
class address_put : public std::locale::facet
{
typedef std::basic_string<charT> string;
public:
explicit address_put(std::size_t refs = 0) : std::locale::facet(refs)
{ }
static std::locale::id id;
typedef Iter iter_type;
virtual void put(iter_type it, const string& name,
const string& street) const = 0;
protected:
virtual void do_put(iter_type it, const string& name,
const string& street) const = 0;
void put_address(iter_type it, const string& fullAddress) const
{
for (auto c : fullAddress)
*it = c;
}
};
template<class charT, class Iter>
std::locale::id address_put<charT, Iter>::id;
template<class charT, class Iter = std::ostreambuf_iterator<charT>>
class US_address_put : public address_put<charT, Iter>
{
using address_put<charT, Iter>::put_address;
typedef std::basic_string<charT> string;
public:
US_address_put(std::size_t refs = 0)
: address_put<charT, Iter>(refs)
{ }
void put(Iter it, const string& name,
const string& street) const
{ do_put(it, name, street); }
protected:
void do_put(Iter it, const string& name,
const string& street) const
{ put_address(it, street + ", " + name); }
};
template<class charT>
std::basic_ostream<charT>& operator<<(std::basic_ostream<charT>& os,
const address<charT>& ad)
{
if (!os.good())
return os;
std::locale loc = os.getloc();
try
{
auto& f = std::use_facet<address_put<char>>(loc);
f.put(os, ad.name, ad.street_address);
} catch (const std::bad_cast&)
{
std::cerr << "Output stream has no locale address_put<char>.";
}
return os;
}
class locale_factory
{
protected:
virtual std::locale make_locale(const std::string& localeName)
{
return std::locale(localeName.c_str());
}
};
class address_locale_factory : public locale_factory
{
private:
typedef std::ostreambuf_iterator<char> iter_type;
public:
address_locale_factory()
{
facets["en_US.UTF8"] = new US_address_put<char, iter_type>(1);
facets["C"] = new US_address_put<char, iter_type>(1);
}
~address_locale_factory()
{
delete facets["en_US.UTF8"];
delete facets["C"];
}
std::locale make_locale(const std::string& localeName)
{
if (facets.find(localeName) == facets.end())
return locale_factory::make_locale(localeName);
else
return std::locale(std::locale(localeName.c_str()),
(*facets.find(localeName)).second);
}
private:
std::map<std::string, address_put<char, iter_type>*> facets;
};
void putAddress(std::ostream& os, const address<char>& ad, std::locale loc)
{
std::locale oldLocale = os.imbue(loc);
os << ad;
os.imbue(oldLocale);
}
int main()
{
std::locale localeWithAddressFacet
= std::locale(std::cout.getloc(), new US_address_put<char>);
std::cout.imbue(localeWithAddressFacet);
address<char> ad("David", "4120 Hutchinson Rv Pkwy");
putAddress(std::cout, ad, address_locale_factory().make_locale("en_US.UTF8"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment