From 0b6260d46e57acfbe6f65301d9951836178bde6e Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 2 Jan 2022 21:21:50 -0500 Subject: Consolidate number support into a single "value" API --- include/serd/serd.h | 267 ++++++++++++++++++++++++++++------------------------ 1 file changed, 143 insertions(+), 124 deletions(-) (limited to 'include/serd') diff --git a/include/serd/serd.h b/include/serd/serd.h index 49046054..c09494bc 100644 --- a/include/serd/serd.h +++ b/include/serd/serd.h @@ -741,6 +741,116 @@ typedef enum { } SerdNodeType; /** + @defgroup serd_node_value Values + + Serd supports reading and writing machine-native numbers, called "values", + in a standards-conformant and portable way. The value structure is used in + the API to allow passing and returning a primitive value of any supported + type. Note that this is just an API convenience, literal nodes themselves + always store their values as strings. + + @{ +*/ + +/// The type of a #SerdValue +typedef enum { + SERD_NOTHING, ///< Sentinel for unknown datatypes or errors + SERD_BOOL, ///< xsd:boolean (bool) + SERD_DOUBLE, ///< xsd:double (double) + SERD_FLOAT, ///< xsd:float (float) + SERD_LONG, ///< xsd:long (int64_t) + SERD_INT, ///< xsd:integer (int32_t) + SERD_SHORT, ///< xsd:short (int16_t) + SERD_BYTE, ///< xsd:byte (int8_t) + SERD_ULONG, ///< xsd:unsignedLong (uint64_t) + SERD_UINT, ///< xsd:unsignedInt (uint32_t) + SERD_USHORT, ///< xsd:unsignedShort (uint16_t) + SERD_UBYTE, ///< xsd:unsignedByte (uint8_t) +} SerdValueType; + +/// The data of a #SerdValue (the actual machine-native primitive) +typedef union { + bool as_bool; + double as_double; + float as_float; + int64_t as_long; + int32_t as_int; + int16_t as_short; + int8_t as_byte; + uint64_t as_ulong; + uint32_t as_uint; + uint16_t as_ushort; + uint8_t as_ubyte; +} SerdValueData; + +/// A primitive value with a type tag +typedef struct { + SerdValueType type; + SerdValueData data; +} SerdValue; + +/// Convenience constructor to make a #SERD_NOTHING (non-)value +SERD_CONST_API +SerdValue +serd_nothing(void); + +/// Convenience constructor to make a #SERD_BOOL value +SERD_CONST_API +SerdValue +serd_bool(bool v); + +/// Convenience constructor to make a #SERD_DOUBLE value +SERD_CONST_API +SerdValue +serd_double(double v); + +/// Convenience constructor to make a #SERD_FLOAT value +SERD_CONST_API +SerdValue +serd_float(float v); + +/// Convenience constructor to make a #SERD_LONG value +SERD_CONST_API +SerdValue +serd_long(int64_t v); + +/// Convenience constructor to make a #SERD_INT value +SERD_CONST_API +SerdValue +serd_int(int32_t v); + +/// Convenience constructor to make a #SERD_SHORT value +SERD_CONST_API +SerdValue +serd_short(int16_t v); + +/// Convenience constructor to make a #SERD_BYTE value +SERD_CONST_API +SerdValue +serd_byte(int8_t v); + +/// Convenience constructor to make a #SERD_ULONG value +SERD_CONST_API +SerdValue +serd_ulong(uint64_t v); + +/// Convenience constructor to make a #SERD_UINT value +SERD_CONST_API +SerdValue +serd_uint(uint32_t v); + +/// Convenience constructor to make a #SERD_USHORT value +SERD_CONST_API +SerdValue +serd_ushort(uint16_t v); + +/// Convenience constructor to make a #SERD_UBYTE value +SERD_CONST_API +SerdValue +serd_ubyte(uint8_t v); + +/** + @} @defgroup serd_node_construction Construction This is the low-level node construction API, which can be used to construct @@ -864,18 +974,15 @@ serd_node_construct_literal(size_t buf_size, SerdStringView meta); /** - Construct a canonical xsd:boolean literal. - - The constructed node will be either "true" or "false", with datatype - xsd:boolean. + Construct a canonical literal for a primitive value. - This is a convenience wrapper for serd_node_construct_literal() that - constructs a node directly from a `bool`. + The constructed node will be a typed literal in canonical form for the xsd + datatype corresponding to the value. */ SerdWriteResult -serd_node_construct_boolean(size_t buf_size, - void* SERD_NULLABLE buf, - bool value); +serd_node_construct_value(size_t buf_size, + void* SERD_NULLABLE buf, + SerdValue value); /** Construct a canonical xsd:decimal literal. @@ -895,38 +1002,6 @@ serd_node_construct_decimal(size_t buf_size, void* SERD_NULLABLE buf, double value); -/** - Construct a canonical xsd:double literal. - - The constructed node will be an xsd:double literal, like "1.23E45", with - datatype xsd:double. A canonical xsd:double is always in scientific - notation. - - This is a convenience wrapper for serd_node_construct_literal() that - constructs a node directly from a `double`. -*/ -SerdWriteResult -serd_node_construct_double(size_t buf_size, - void* SERD_NULLABLE buf, - double value); - -/** - Construct a canonical xsd:float literal. - - The constructed node will be an xsd:float literal, like "1.23E45", with - datatype xsd:float. A canonical xsd:float is always in scientific notation. - - Uses identical formatting to serd_node_construct_double(), except with at - most 9 significant digits (under 14 characters total). - - This is a convenience wrapper for serd_node_construct_literal() that - constructs a node directly from a `float`. -*/ -SerdWriteResult -serd_node_construct_float(size_t buf_size, - void* SERD_NULLABLE buf, - float value); - /** Construct a canonical xsd:integer literal. @@ -1069,17 +1144,17 @@ serd_new_literal(SerdAllocator* SERD_NULLABLE allocator, SerdStringView meta); /** - Create a new canonical xsd:boolean node. + Create a new canonical value node. - This is a wrapper for serd_node_construct_boolean() that allocates a new - node on the heap. + This is a wrapper for serd_node_construct_value() that allocates a new node + on the heap. @return A newly allocated node that must be freed with serd_node_free(), or null. */ SERD_API SerdNode* SERD_ALLOCATED -serd_new_boolean(SerdAllocator* SERD_NULLABLE allocator, bool b); +serd_new_value(SerdAllocator* SERD_NULLABLE allocator, SerdValue value); /** Create a new canonical xsd:decimal literal. @@ -1094,32 +1169,6 @@ SERD_API SerdNode* SERD_ALLOCATED serd_new_decimal(SerdAllocator* SERD_NULLABLE allocator, double d); -/** - Create a new canonical xsd:double literal. - - This is a wrapper for serd_node_construct_double() that allocates a new - node on the heap. - - @return A newly allocated node that must be freed with serd_node_free(), or - null. -*/ -SERD_API -SerdNode* SERD_ALLOCATED -serd_new_double(SerdAllocator* SERD_NULLABLE allocator, double d); - -/** - Create a new canonical xsd:float literal. - - This is a wrapper for serd_node_construct_float() that allocates a new - node on the heap. - - @return A newly allocated node that must be freed with serd_node_free(), or - null. -*/ -SERD_API -SerdNode* SERD_ALLOCATED -serd_new_float(SerdAllocator* SERD_NULLABLE allocator, float f); - /** Create a new canonical xsd:integer literal. @@ -1153,49 +1202,39 @@ serd_new_base64(SerdAllocator* SERD_NULLABLE allocator, */ /** - Return the value of `node` as a boolean. + Return the primitive value of `node`. - This will work for booleans, and numbers of any datatype if they are 0 or - 1. + This will return a typed value if the node can be read as one, or a value + with type #SERD_NOTHING otherwise. - @return The value of `node` as a `bool`, or `false` on error. + @return The value of `node` as a #SerdValue, if possible. */ SERD_API -bool -serd_get_boolean(const SerdNode* SERD_NONNULL node); +SerdValue +serd_get_value(const SerdNode* SERD_NONNULL node); /** - Return the value of `node` as a double. + Return the value of `node` as a specific type of number. - This will coerce numbers of any datatype to double, if the value fits. + This is like serd_get_number(), but will coerce the value of the node to the + requrested type if possible. - @return The value of `node` as a `double`, or NaN on error. -*/ -SERD_API -double -serd_get_double(const SerdNode* SERD_NONNULL node); + @param node The node to interpret as a number. -/** - Return the value of `node` as a float. + @param type The desired numeric datatype of the result. - This will coerce numbers of any datatype to float, if the value fits. + @param lossy Whether lossy conversions can be used. If this is false, then + this function only succeeds if the value could be converted back to the + original datatype of the node without loss. Otherwise, precision may be + reduced or values may be truncated to fit the result. - @return The value of `node` as a `float`, or NaN on error. + @return The value of `node` as a #SerdValue, or nothing. */ SERD_API -float -serd_get_float(const SerdNode* SERD_NONNULL node); - -/** - Return the value of `node` as a long (signed 64-bit integer). - - This will coerce numbers of any datatype to long, if the value fits. - - @return The value of `node` as a `int64_t`, or 0 on error. -*/ -SERD_API -int64_t -serd_get_integer(const SerdNode* SERD_NONNULL node); +SerdValue +serd_get_value_as(const SerdNode* SERD_NONNULL node, + SerdValueType type, + bool lossy); /** Return the maximum size of a decoded base64 node in bytes. @@ -1426,14 +1465,14 @@ serd_nodes_literal(SerdNodes* SERD_NONNULL nodes, SerdStringView meta); /** - Make a canonical xsd:boolean node. + Make a canonical value node. - A new node will be constructed with serd_node_construct_boolean() if an + A new node will be constructed with serd_node_construct_value() if an equivalent one is not already in the set. */ SERD_API const SerdNode* SERD_ALLOCATED -serd_nodes_boolean(SerdNodes* SERD_NONNULL nodes, bool value); +serd_nodes_value(SerdNodes* SERD_NONNULL nodes, SerdValue value); /** Make a canonical xsd:decimal node. @@ -1445,26 +1484,6 @@ SERD_API const SerdNode* SERD_ALLOCATED serd_nodes_decimal(SerdNodes* SERD_NONNULL nodes, double value); -/** - Make a canonical xsd:double node. - - A new node will be constructed with serd_node_construct_double() if an - equivalent one is not already in the set. -*/ -SERD_API -const SerdNode* SERD_ALLOCATED -serd_nodes_double(SerdNodes* SERD_NONNULL nodes, double value); - -/** - Make a canonical xsd:float node. - - A new node will be constructed with serd_node_construct_float() if an - equivalent one is not already in the set. -*/ -SERD_API -const SerdNode* SERD_ALLOCATED -serd_nodes_float(SerdNodes* SERD_NONNULL nodes, float value); - /** Make a canonical xsd:integer node. -- cgit v1.2.1