// locale standard header
#pragma once
#ifndef _LOCALE_
#define _LOCALE_
#ifndef RC_INVOKED
#include <string>
#include <xlocbuf>
#include <xlocmes>
#include <xlocmon>
#include <xlocnum>
#include <xloctime>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,_STL_WARNING_LEVEL)
 #pragma warning(disable: _STL_DISABLED_WARNINGS)
 _STL_DISABLE_CLANG_WARNINGS
 #pragma push_macro("new")
 #undef new

_STD_BEGIN
		// CLASS TEMPLATE collate
template<class _Elem>
	class collate
		: public locale::facet
	{	// facet for ordering sequences of elements
public:
	typedef _Elem char_type;
	typedef basic_string<_Elem, char_traits<_Elem>,
		allocator<_Elem> > string_type;

	int compare(const _Elem *_First1, const _Elem *_Last1,
		const _Elem *_First2, const _Elem *_Last2) const
		{	// compare [_First1, _Last1) to [_First2, _Last2)
		return (do_compare(_First1, _Last1, _First2, _Last2));
		}

	string_type transform(const _Elem *_First, const _Elem *_Last) const
		{	// transform [_First, _Last) to key string
		return (do_transform(_First, _Last));
		}

	long hash(const _Elem *_First, const _Elem *_Last) const
		{	// compute hash code for [_First, _Last)
		return (do_hash(_First, _Last));
		}

	__PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id;	// unique facet id

	explicit collate(size_t _Refs = 0)
		: locale::facet(_Refs)
		{	// construct from current locale
		_BEGIN_LOCINFO(_Lobj)
			_Init(_Lobj);
		_END_LOCINFO()
		}

	collate(const _Locinfo& _Lobj, size_t _Refs = 0)
		: locale::facet(_Refs)
		{	// construct from specified locale
		_Init(_Lobj);
		}

	static size_t _Getcat(const locale::facet **_Ppf = nullptr,
		const locale *_Ploc = nullptr)
		{	// return locale category mask and construct standard facet
		if (_Ppf != nullptr && *_Ppf == nullptr)
			*_Ppf = new collate<_Elem>(
				_Locinfo(_Ploc->name().c_str()));
		return (_X_COLLATE);
		}

protected:
	__CLR_OR_THIS_CALL ~collate() noexcept
		{	// destroy the object
		_CSTD free(_Coll._LocaleName);
		}

protected:
	collate(const char *_Locname, size_t _Refs = 0)
		: locale::facet(_Refs)
		{	// construct from specified locale
		_BEGIN_LOCINFO(_Lobj(_Locname))
			_Init(_Lobj);
		_END_LOCINFO()
		}

	void _Init(const _Locinfo& _Lobj)
		{	// initialize from _Lobj
		_Coll = _Lobj._Getcoll();
		}

	virtual int __CLR_OR_THIS_CALL do_compare(const _Elem *_First1, const _Elem *_Last1,
		const _Elem *_First2, const _Elem *_Last2) const
		{	// compare [_First1, _Last1) to [_First2, _Last2)
		_Adl_verify_range(_First1, _Last1);
		_Adl_verify_range(_First2, _Last2);
		int _Ans = _LStrcoll(_First1, _Last1, _First2, _Last2, &_Coll);
		return (_Ans < 0 ? -1 : _Ans == 0 ? 0 : +1);
		}

	virtual string_type __CLR_OR_THIS_CALL do_transform(const _Elem *_First,
		const _Elem *_Last) const
		{	// transform [_First, _Last) to key string
		_Adl_verify_range(_First, _Last);
		size_t _Count;
		string_type _Str;

		for (_Count = static_cast<size_t>(_Last - _First); 0 < _Count; )
			{	// grow string if locale-specific strxfrm fails
			_Str.resize(_Count);
			if ((_Count = _LStrxfrm(&*_Str.begin(),
				&*_Str.begin() + _Str.size(),
					_First, _Last, &_Coll)) <= _Str.size())
				break;
			}
		_Str.resize(_Count);
		return (_Str);
		}

	virtual long __CLR_OR_THIS_CALL do_hash(const _Elem *_First, const _Elem *_Last) const
		{	// compute hash code for [_First, _Last)
		_Adl_verify_range(_First, _Last);
		return (static_cast<long>(_Hash_array_representation(_First, static_cast<size_t>(_Last - _First))));
		}

private:
	_Locinfo::_Collvec _Coll;	// used by _LStrcoll and _XStrxfrm
	};

		// STATIC collate::id OBJECT
#ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif /* __clang__ */

template<class _Elem>
	__PURE_APPDOMAIN_GLOBAL locale::id collate<_Elem>::id;

 #if defined(_DLL_CPPLIB)

  #if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template __PURE_APPDOMAIN_GLOBAL locale::id collate<char>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id collate<wchar_t>::id;
  #endif /* !defined(_CRTBLD) || defined(__FORCE_INSTANCE) */

  #ifdef __FORCE_INSTANCE
template __PURE_APPDOMAIN_GLOBAL locale::id collate<unsigned short>::id;
  #endif /* __FORCE_INSTANCE */
 #endif /* defined(_DLL_CPPLIB) */

#ifdef __clang__
 #pragma clang diagnostic pop
#endif /* __clang__ */

		// CLASS TEMPLATE collate_byname
template<class _Elem>
	class collate_byname
		: public collate<_Elem>
	{	// collate for named locale
public:
	explicit collate_byname(const char *_Locname, size_t _Refs = 0)
		: collate<_Elem>(_Locname, _Refs)
		{	// construct for named locale
		}

	explicit collate_byname(const string& _Str, size_t _Refs = 0)
		: collate<_Elem>(_Locinfo(_Str.c_str()), _Refs)
		{	// construct for named locale
		}

protected:
	virtual __CLR_OR_THIS_CALL ~collate_byname() noexcept
		{	// destroy the object
		}
	};

		// FUNCTION TEMPLATE has_facet
template<class _Facet> inline
	bool has_facet(const locale& _Loc) noexcept
	{	// test if facet is in locale
	_BEGIN_LOCK(_LOCK_LOCALE)	// the thread lock, make get atomic
		size_t _Id = _Facet::id;
		return (_Loc._Getfacet(_Id) != nullptr
			|| _Facet::_Getcat() != (size_t)(-1));
	_END_LOCK()
	}

		// FUNCTION TEMPLATE isalnum
template<class _Elem> inline
	bool (isalnum)(_Elem _Ch, const locale& _Loc)
	{	// test if character is alphanumeric, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::alnum, _Ch));
	}

		// FUNCTION TEMPLATE isalpha
template<class _Elem> inline
	bool (isalpha)(_Elem _Ch, const locale& _Loc)
	{	// test if character is alphabetic, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::alpha, _Ch));
	}

		// FUNCTION TEMPLATE isblank
template<class _Elem> inline
	bool (isblank)(_Elem _Ch, const locale& _Loc)
	{	// test if character is blank, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::blank, _Ch));
	}

		// FUNCTION TEMPLATE iscntrl
template<class _Elem> inline
	bool (iscntrl)(_Elem _Ch, const locale& _Loc)
	{	// test if character is control, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::cntrl, _Ch));
	}

		// FUNCTION TEMPLATE isdigit
template<class _Elem> inline
	bool (isdigit)(_Elem _Ch, const locale& _Loc)
	{	// test if character is digit, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::digit, _Ch));
	}

		// FUNCTION TEMPLATE isgraph
template<class _Elem> inline
	bool (isgraph)(_Elem _Ch, const locale& _Loc)
	{	// test if character is graphic, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::graph, _Ch));
	}

		// FUNCTION TEMPLATE islower
template<class _Elem> inline
	bool (islower)(_Elem _Ch, const locale& _Loc)
	{	// test if character is lower case, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::lower, _Ch));
	}

		// FUNCTION TEMPLATE isprint
template<class _Elem> inline
	bool (isprint)(_Elem _Ch, const locale& _Loc)
	{	// test if character is printing, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::print, _Ch));
	}

		// FUNCTION TEMPLATE ispunct
template<class _Elem> inline
	bool (ispunct)(_Elem _Ch, const locale& _Loc)
	{	// test if character is punctuation, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::punct, _Ch));
	}

		// FUNCTION TEMPLATE isspace
template<class _Elem> inline
	bool (isspace)(_Elem _Ch, const locale& _Loc)
	{	// test if character is whitespace, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::space, _Ch));
	}

		// FUNCTION TEMPLATE isupper
template<class _Elem> inline
	bool (isupper)(_Elem _Ch, const locale& _Loc)
	{	// test if character is upper case, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::upper, _Ch));
	}

		// FUNCTION TEMPLATE isxdigit
template<class _Elem> inline
	bool (isxdigit)(_Elem _Ch, const locale& _Loc)
	{	// test if character is hexadecimal digit, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).is(ctype_base::xdigit, _Ch));
	}

		// FUNCTION TEMPLATE tolower
template<class _Elem> inline
	_Elem (tolower)(_Elem _Ch, const locale& _Loc)
	{	// convert character to lower case, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).tolower(_Ch));
	}

		// FUNCTION TEMPLATE toupper
template<class _Elem> inline
	_Elem (toupper)(_Elem _Ch, const locale& _Loc)
	{	// convert character to upper case, locale specific
	return (_STD use_facet<ctype<_Elem>>(_Loc).toupper(_Ch));
	}
_STD_END
 #pragma pop_macro("new")
 _STL_RESTORE_CLANG_WARNINGS
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _LOCALE_ */

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
