+/** @defgroup utf32props Unicode Code Point Properties */
+/*@{*/
+
+static const struct unidata *utf32__unidata_hard(uint32_t c);
+
+/** @brief Find definition of code point @p c
+ * @param c Code point
+ * @return Pointer to @ref unidata structure for @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ * The returned pointer is NOT guaranteed to be unique to @p c.
+ */
+static inline const struct unidata *utf32__unidata(uint32_t c) {
+ /* The bottom half of the table contains almost everything of interest
+ * and we can just return the right thing straight away */
+ if(c < UNICODE_BREAK_START)
+ return &unidata[c / UNICODE_MODULUS][c % UNICODE_MODULUS];
+ else
+ return utf32__unidata_hard(c);
+}
+
+/** @brief Find definition of code point @p c
+ * @param c Code point
+ * @return Pointer to @ref unidata structure for @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ * The returned pointer is NOT guaranteed to be unique to @p c.
+ *
+ * Don't use this function (although it will work fine) - use utf32__unidata()
+ * instead.
+ */
+static const struct unidata *utf32__unidata_hard(uint32_t c) {
+ if(c < UNICODE_BREAK_START)
+ return &unidata[c / UNICODE_MODULUS][c % UNICODE_MODULUS];
+ /* Within the break everything is unassigned */
+ if(c < UNICODE_BREAK_END)
+ return utf32__unidata(0xFFFF); /* guaranteed to be Cn */
+ /* Planes 15 and 16 are (mostly) private use */
+ if((c >= 0xF0000 && c <= 0xFFFFD)
+ || (c >= 0x100000 && c <= 0x10FFFD))
+ return utf32__unidata(0xE000); /* first Co code point */
+ /* Everything else above the break top is unassigned */
+ if(c >= UNICODE_BREAK_TOP)
+ return utf32__unidata(0xFFFF); /* guaranteed to be Cn */
+ /* Currently the rest is language tags and variation selectors */
+ c -= (UNICODE_BREAK_END - UNICODE_BREAK_START);
+ return &unidata[c / UNICODE_MODULUS][c % UNICODE_MODULUS];
+}
+
+/** @brief Return the combining class of @p c
+ * @param c Code point
+ * @return Combining class of @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+static inline int utf32__combining_class(uint32_t c) {
+ return utf32__unidata(c)->ccc;
+}
+
+/** @brief Return the combining class of @p c
+ * @param c Code point
+ * @return Combining class of @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+int utf32_combining_class(uint32_t c) {
+ return utf32__combining_class(c);
+}
+
+/** @brief Return the General_Category value for @p c
+ * @param c Code point
+ * @return General_Category property value
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+static inline enum unicode_General_Category utf32__general_category(uint32_t c) {
+ return utf32__unidata(c)->general_category;
+}
+
+/** @brief Determine Grapheme_Break property
+ * @param c Code point
+ * @return Grapheme_Break property value of @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+static inline enum unicode_Grapheme_Break utf32__grapheme_break(uint32_t c) {
+ return utf32__unidata(c)->grapheme_break;
+}
+
+/** @brief Determine Word_Break property
+ * @param c Code point
+ * @return Word_Break property value of @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+static inline enum unicode_Word_Break utf32__word_break(uint32_t c) {
+ return utf32__unidata(c)->word_break;
+}
+
+/** @brief Determine Sentence_Break property
+ * @param c Code point
+ * @return Word_Break property value of @p c
+ *
+ * @p c can be any 32-bit value, a sensible value will be returned regardless.
+ */
+static inline enum unicode_Sentence_Break utf32__sentence_break(uint32_t c) {
+ return utf32__unidata(c)->sentence_break;
+}
+
+/** @brief Return true if @p c is ignorable for boundary specifications
+ * @param wb Word break property value
+ * @return non-0 if @p wb is unicode_Word_Break_Extend or unicode_Word_Break_Format
+ */
+static inline int utf32__boundary_ignorable(enum unicode_Word_Break wb) {
+ return (wb == unicode_Word_Break_Extend
+ || wb == unicode_Word_Break_Format);
+}
+
+/** @brief Return the canonical decomposition of @p c
+ * @param c Code point
+ * @return 0-terminated canonical decomposition, or 0
+ */
+static inline const uint32_t *utf32__decomposition_canon(uint32_t c) {
+ const struct unidata *const data = utf32__unidata(c);
+ const uint32_t *const decomp = data->decomp;
+
+ if(decomp && !(data->flags & unicode_compatibility_decomposition))
+ return decomp;
+ else
+ return 0;
+}
+
+/** @brief Return the compatibility decomposition of @p c
+ * @param c Code point
+ * @return 0-terminated decomposition, or 0
+ */
+static inline const uint32_t *utf32__decomposition_compat(uint32_t c) {
+ return utf32__unidata(c)->decomp;
+}
+
+/*@}*/