Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/numeric-glib-1.0.vapi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@
[CCode (cprefix = "numeric_", cheader_filename = "numeric.h")]
namespace Numeric
{
[Compact]
[CCode (cname = "NumericTypeInfo")]
public class TypeInfo
{
public GLib.Type type;
public string name;
public size_t width;
public GLib.ByteOrder byte_order;
}

public unowned Numeric.TypeInfo get_type_info (GLib.Type type);
public unowned Numeric.TypeInfo get_type_info_from_name (string name);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions should be defined within the TypeInfo class as static.


[IntegerType (rank = 12, width = 16)]
[CCode (get_value_function = "numeric_value_get_int128", set_value_function = "numeric_value_set_int128")]
public struct int128 {}
Expand Down
148 changes: 132 additions & 16 deletions src/numeric-types.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@

#include "numeric-types.h"

#include <glib.h>
#include <string.h>

#define DEFINE_NUMERIC(type) \
G_DEFINE_BOXED_TYPE (numeric_##type, \
numeric_##type, \
numeric_##type##_copy, \
numeric_##type##_free) \
G_DEFINE_BOXED_TYPE_WITH_CODE (numeric_##type, \
numeric_##type, \
numeric_##type##_copy, \
numeric_##type##_free, \
numeric_type_register_static (g_define_type_id, G_STRINGIFY(type), sizeof (numeric_##type), G_BYTE_ORDER)) \
\
numeric_##type * \
numeric_##type##_copy (numeric_##type *num) \
Expand Down Expand Up @@ -54,17 +56,6 @@ numeric_value_set_##type (GValue *val, numeric_##type x) \
g_value_set_boxed (val, ptr); \
}

DEFINE_NUMERIC (int128)
DEFINE_NUMERIC (uint128)
DEFINE_NUMERIC (float80)
DEFINE_NUMERIC (float128)
DEFINE_NUMERIC (decimal32)
DEFINE_NUMERIC (decimal64)
DEFINE_NUMERIC (decimal128)
DEFINE_NUMERIC (complex)
DEFINE_NUMERIC (complex80)
DEFINE_NUMERIC (complex128)

#define DEFINE_NUMERIC_WITH_BYTESWAP(type,gtype,stype,routine,order) \
DEFINE_NUMERIC (type) \
numeric_##type \
Expand Down Expand Up @@ -93,6 +84,117 @@ numeric_##type##_to_##gtype (numeric_##type num) \
return data.v_##gtype; \
}

GArray *TYPE_TABLE = NULL;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this declaration static.


void
numeric_type_register_static (GType type,
const gchar *name,
gsize width,
gint byte_order)
{
if (TYPE_TABLE == NULL)
{
TYPE_TABLE = g_array_new (FALSE, FALSE, sizeof (NumericTypeInfo));
}

/* make sure we don't register the same type twice */
gint i;
for (i = 0; i < TYPE_TABLE->len; i++)
{
NumericTypeInfo* ti = &g_array_index (TYPE_TABLE, NumericTypeInfo, i);
if (ti->type == type)
return;
}

NumericTypeInfo ti = {
.type = type,
.name = g_strdup (name),
.width = width,
.byte_order = byte_order};

g_array_append_val (TYPE_TABLE,
ti);
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if we could enumerate these types at runtime so that the we could be forward compatibly if new types are defined in GLib.


const NumericTypeInfo *
numeric_get_type_info (GType type)
{
gint i;
for (i = 0; i < TYPE_TABLE->len; i++)
{
NumericTypeInfo* ti = &g_array_index (TYPE_TABLE, NumericTypeInfo, i);
if (ti->type == type)
{
return ti;
}
}

g_return_val_if_reached (NULL);
}

const NumericTypeInfo *
numeric_get_type_info_from_name (const gchar *name)
{
gint i;
for (i = 0; i < TYPE_TABLE->len; i++)
{
const NumericTypeInfo* ti = &g_array_index (TYPE_TABLE, NumericTypeInfo, i);
if (g_strcmp0 (ti->name, name) == 0)
{
return ti;
}
}

g_return_val_if_reached (NULL);
}

/**
* numeric_type_get_name:
* Obtain the number of bytes occupied by @numeric_type.
*/
const gchar *
numeric_type_get_name (GType numeric_type)
{
const NumericTypeInfo *type_info;
type_info = numeric_get_type_info (numeric_type);
return type_info->name;
}

/**
* numeric_type_get_width:
* Obtain the number of bytes occupied by @numeric_type.
*/
gsize
numeric_type_get_width (GType numeric_type)
{
const NumericTypeInfo *type_info;
type_info = numeric_get_type_info (numeric_type);
return type_info->width;
}

/**
* numeric_type_get_byte_order:
* Obtain the byte order of @numeric_type.
*/
gint
numeric_type_get_byte_order (GType numeric_type)
{
const NumericTypeInfo *type_info;
type_info = numeric_get_type_info (numeric_type);
return type_info->byte_order;
}

DEFINE_NUMERIC (int128)
DEFINE_NUMERIC (uint128)
DEFINE_NUMERIC (float80)
DEFINE_NUMERIC (float128)
DEFINE_NUMERIC (decimal32)
DEFINE_NUMERIC (decimal64)
DEFINE_NUMERIC (decimal128)
DEFINE_NUMERIC (complex)
DEFINE_NUMERIC (complex80)
DEFINE_NUMERIC (complex128)

DEFINE_NUMERIC_WITH_BYTESWAP (int_le, int, gint, GINT, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (int_be, int, gint, GINT, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint_le, uint, guint, GUINT, LE)
Expand All @@ -112,11 +214,25 @@ DEFINE_NUMERIC_WITH_BYTESWAP (double_be, double, gint32, GINT64, BE)

#if HAVE_LIBDFP
extern void register_printf_dfp (void);
#endif

__attribute__ ((constructor))
static void
numeric_types_init (void)
{
// register all GLib numerical types
numeric_type_register_static (G_TYPE_CHAR, "char", sizeof (gchar), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_UCHAR, "uchar", sizeof (guchar), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_INT, "int", sizeof (gint), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_UINT, "uint", sizeof (guint), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_LONG, "long", sizeof (glong), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_ULONG, "ulong", sizeof (gulong), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_INT64, "int64", sizeof (gint64), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_UINT64, "uint64", sizeof (guint64), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_FLOAT, "float", sizeof (gfloat), G_BYTE_ORDER);
numeric_type_register_static (G_TYPE_DOUBLE, "double", sizeof (gdouble), G_BYTE_ORDER);
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here is that we cannot redefine these types. We can either have a numeric boxed counterpart or look into switching from boxed types to fundamental types for our definitions.

The quickfix would be to define these "fundamental" types lazily in numeric_get_type_info.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 quick points: Would life be made easier if not using macros but hard code and/or generate the definitions with a code generator?

I remember the get_type() functions always generate the type the first time. Is that what you gain by moving to a fundamental type? If adding a fundamental type. I would suggest considering GNumericScalar as an umbrella type for all of the types.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually doing just that! G_DEFINE_BOXED_TYPE_WITH_CODE inserts arbitrary code inside the _get_type definition allowing us to perform any kind of initialization and registration of transformations.

The issue I'm facing with GLib fundamental types is that we cannot redefine that piece of code and thus registering the NumericTypeInfo counterpart we will need for introspection and byteswapping.


#if HAVE_LIBDFP
register_printf_dfp ();
}
#endif
}
26 changes: 26 additions & 0 deletions src/numeric-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@

G_BEGIN_DECLS

/**
* @type: Registered GType for this numerical type
* @name: Name
* @width: Size in bytes
* @byte_order: Byte order
*/
typedef struct _NumericTypeInfo
{
GType type;
const gchar *name;
gsize width;
gint byte_order;
} NumericTypeInfo;

void numeric_type_register_static (GType type,
const gchar *name,
gsize width,
gint byte_order);

const NumericTypeInfo * numeric_get_type_info (GType type);
const NumericTypeInfo * numeric_get_type_info_from_name (const gchar *name);

const gchar * numeric_type_get_name (GType numeric_type);
gsize numeric_type_get_width (GType numeric_type);
gint numeric_type_get_byte_order (GType numeric_type);

#define DEFINE_NUMERIC_PROTOTYPE(type,ctype) \
typedef ctype numeric_##type; \
GType numeric_##type##_get_type (void) G_GNUC_CONST; \
Expand Down
14 changes: 14 additions & 0 deletions tests/numeric-c-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stdio.h>

#include <glib.h>
#include <assert.h>

#if HAVE_LIBDFP
#include <dfp/stdlib.h>
Expand All @@ -28,11 +29,22 @@

#include <numeric.h>

void
test_glib_types (void)
{
g_assert_cmpstr (numeric_type_get_name (G_TYPE_INT), ==, "int");
g_assert_cmpstr (numeric_type_get_name (G_TYPE_UINT), ==, "uint");
}

void
test_decimal128 (void)
{
numeric_decimal128 a;

g_assert_cmpstr (numeric_type_get_name (NUMERIC_TYPE_DECIMAL128), ==, "decimal128");
assert (numeric_type_get_width (NUMERIC_TYPE_DECIMAL128) == 16);
assert (numeric_type_get_byte_order (NUMERIC_TYPE_DECIMAL128) == G_BYTE_ORDER);

#if HAVE_LIBDFP
a = strtod128 ("0.1", NULL);
#else
Expand All @@ -55,7 +67,9 @@ main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);

g_test_add_func ("/glib-types", test_glib_types);
g_test_add_func ("/decimal128", test_decimal128);


return g_test_run ();
}
5 changes: 5 additions & 0 deletions tests/numeric-test.vala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public int main (string[] args)
{
Test.init (ref args);

Test.add_func ("/type_info", () => {
unowned Numeric.TypeInfo ti = Numeric.get_type_info_from_name ("float128");
assert (ti.byte_order == ByteOrder.HOST);
});

Test.add_func ("/size", () => {
assert (sizeof (int128) == 16);
assert (sizeof (uint128) == 16);
Expand Down