Marking an encoding as Unicode-Capable

Sometimes, you need to make your own encodings. Whether for legacy reasons or for interoperation reasons, you need the ability to write an encoding that can losslessly handle all \(2^21\) code points. Whether it’s writing a variant of UTF-7, or dealing with a very specific legacy set like Unicode v6.0 with the Softbank Private Use Area, you are going to need to be able to say “hey, my encoding can handle all of the code points and therefore deserves to be treated like a Unicode encoding”. There are 2 ways to do this, one for decisions that can be made at compile time, and one for decisions that can be made at runtime (e.g., over a variant_encoding<X, Y, Z>).

compile time

The cheapest way to tag an encoding as Unicode Capable and have the library recognize it as such when ztd::text::is_unicode_encoding is used is to just define a member type definition:

class utf8_v6_softbank {
public:
        // …
        using is_unicode_encoding = std::true_type;
        // …
};

That is all you have to write. Both ztd::text::is_unicode_encoding and ztd::text::contains_unicode_encoding will detect this and use it.

Run-time

If your encoding cannot know at compile time whether or not it is a unicode encoding (e.g., for type-erased encodings, complex wrapping encodings, or encodings which rely on external operating system resources), you can define a method instead. When applicable, this will be picked up by the ztd::text::contains_unicode_encoding function. Here is an example of a runtime, locale-based encoding using platform-knowledge to pick up what the encoding might be, and determine if it can handle working in Unicode:

 1#endif
 2
 3	struct encode_state {
 4		std::mbstate_t c_stdlib_state;
 5
 6		encode_state() noexcept : c_stdlib_state() {
 7			// properly set for c32rtomb state
 8			code_unit ghost_ouput[MB_LEN_MAX] {};
 9			UCHAR_ACCESS c32rtomb(ghost_ouput, U'\0', &c_stdlib_state);
10		}
11	};
12
13	bool contains_unicode_encoding() const noexcept {
14#if defined(_WIN32)
15		CPINFOEXW cp_info {};
16		BOOL success = GetCPInfoExW(CP_THREAD_ACP, 0, &cp_info);
17		if (success == 0) {
18			return false;
19		}
20		switch (cp_info.CodePage) {
21		case 65001: // UTF-8
22		            // etc. etc. …
23			return true;
24		default:
25			break;
26		}
27#else
28	}

That is it. ztd::text::contains_unicode_encoding will detect this and use your function call, so you should never be calling this or accessing the above compile time classification if necessary and always delegating to the ztd::text::contains_unicode_encoding function call.