+#define toLOWER_uni(c,s,l) to_uni_lower(c,s,l)
+#define toTITLE_uni(c,s,l) to_uni_title(c,s,l)
+#define toUPPER_uni(c,s,l) to_uni_upper(c,s,l)
+
+#define _gnrc_is_LC_uvchr(latin1, above_latin1, c) \
+ (c < 256 ? latin1(c) : above_latin1(NATIVE_TO_UNI(c)))
+#define isALNUMC_LC_uvchr(c) _gnrc_is_LC_uvchr(isALNUMC_LC, is_uni_alnumc_lc, c)
+#define isALNUM_LC_uvchr(c) isWORDCHAR_LC_uvchr(c)
+#define isALPHA_LC_uvchr(c) _gnrc_is_LC_uvchr(isALPHA_LC, is_uni_alpha_lc, c)
+#define isASCII_LC_uvchr(c) isASCII_LC(c)
+#define isBLANK_LC_uvchr(c) _gnrc_is_LC_uvchr(isBLANK_LC, is_HORIZWS_cp_high, c)
+#define isCNTRL_LC_uvchr(c) (c < 256 ? isCNTRL_LC(c) : 0)
+#define isDIGIT_LC_uvchr(c) _gnrc_is_LC_uvchr(isDIGIT_LC, is_uni_digit_lc, c)
+#define isGRAPH_LC_uvchr(c) _gnrc_is_LC_uvchr(isGRAPH_LC, is_uni_graph_lc, c)
+#define isIDFIRST_LC_uvchr(c) _gnrc_is_LC_uvchr(isIDFIRST_LC, \
+ is_uni_idfirst_lc, c)
+#define isLOWER_LC_uvchr(c) _gnrc_is_LC_uvchr(isLOWER_LC, is_uni_lower_lc, c)
+#define isPRINT_LC_uvchr(c) _gnrc_is_LC_uvchr(isPRINT_LC, is_uni_print_lc, c)
+#define isPSXSPC_LC_uvchr(c) isSPACE_LC_uvchr(c) /* space is identical to posix
+ space under locale */
+#define isPUNCT_LC_uvchr(c) _gnrc_is_LC_uvchr(isPUNCT_LC, is_uni_punct_lc, c)
+#define isSPACE_LC_uvchr(c) _gnrc_is_LC_uvchr(isSPACE_LC, \
+ is_XPERLSPACE_cp_high, c)
+#define isUPPER_LC_uvchr(c) _gnrc_is_LC_uvchr(isUPPER_LC, is_uni_upper_lc, c)
+#define isWORDCHAR_LC_uvchr(c) _gnrc_is_LC_uvchr(isWORDCHAR_LC, \
+ is_uni_alnum_lc, c)
+#define isXDIGIT_LC_uvchr(c) _gnrc_is_LC_uvchr(isXDIGIT_LC, is_XDIGIT_cp_high, c)
+
+
+#define isBLANK_LC_uni(c) isBLANK_LC_uvchr(UNI_TO_NATIVE(c))
+
+/* For internal core Perl use only. If the input is in the Latin1 range, use
+ * the Latin1 macro 'classnum' on 'p' which is a pointer to a UTF-8 string.
+ * Otherwise use the value given by the 'utf8' parameter. This relies on the
+ * fact that ASCII characters have the same representation whether utf8 or not.
+ * Note that it assumes that the utf8 has been validated, and ignores 'use
+ * bytes' */
+#define _generic_utf8_utf8(classnum, p, utf8) (UTF8_IS_INVARIANT(*(p)) \
+ ? _generic_isCC(*(p), classnum) \
+ : (UTF8_IS_DOWNGRADEABLE_START(*(p))) \
+ ? _generic_isCC( \
+ TWO_BYTE_UTF8_TO_UNI(*(p), \
+ *((p)+1 )), \
+ classnum) \
+ : utf8)
+/* Like the above, but calls 'function(p)' to get the utf8 value */
+#define _generic_utf8(classnum, function, p) \
+ _generic_utf8_utf8(classnum, p, function(p))
+
+/* Like the above, but should be used only when it is known that there are no
+ * characters in the range 128-255 which the class is TRUE for. Hence it can
+ * skip the tests for this range */
+#define _generic_utf8_no_upper_latin1(classnum, function, p) \
+ (UTF8_IS_INVARIANT(*(p)) \
+ ? _generic_isCC(*(p), classnum) \
+ : (UTF8_IS_ABOVE_LATIN1(*(p))) \
+ ? function(p) \
+ : 0)
+
+/* NOTE that some of these macros have very similar ones in regcharclass.h.
+ * For example, there is (at the time of this writing) an 'is_SPACE_utf8()'
+ * there, differing in name only by an underscore from the one here
+ * 'isSPACE_utf8(). The difference is that the ones here are probably more
+ * efficient and smaller, using an O(1) array lookup for Latin1-range code
+ * points; the regcharclass.h ones are implemented as a series of
+ * "if-else-if-else ..." */
+
+#define isALNUMC_utf8(p) _generic_utf8(_CC_ALNUMC, is_utf8_alnumc, p)
+#define isALNUM_utf8(p) isWORDCHAR_utf8(p) /* back compat */
+#define isALPHA_utf8(p) _generic_utf8(_CC_ALPHA, is_utf8_alpha, p)
+#define isASCII_utf8(p) isASCII(*p) /* Because ASCII is invariant under
+ utf8, the non-utf8 macro works
+ */
+#define isBLANK_utf8(p) _generic_utf8(_CC_BLANK, is_HORIZWS_high, p)
+#define isCNTRL_utf8(p) _generic_utf8_utf8(_CC_CNTRL, p, 0)
+#define isDIGIT_utf8(p) _generic_utf8_no_upper_latin1(_CC_DIGIT, \
+ is_utf8_digit, p)
+#define isGRAPH_utf8(p) _generic_utf8(_CC_GRAPH, is_utf8_graph, p)
+#define isIDCONT_utf8(p) _generic_utf8(_CC_WORDCHAR, is_utf8_xidcont, p)