Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add registry for numerical type size and endianness #17

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
189 changes: 154 additions & 35 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) \
#define DEFINE_NUMERIC(type,byte_order) \
G_DEFINE_BOXED_TYPE_WITH_CODE (numeric_##type, \
numeric_##type, \
numeric_##type##_copy, \
numeric_##type##_free, \
numeric_type_register_static_simple (g_define_type_id, G_STRINGIFY(type), sizeof (numeric_##type), byte_order)) \
\
numeric_##type * \
numeric_##type##_copy (numeric_##type *num) \
Expand Down Expand Up @@ -54,19 +56,8 @@ 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) \
#define DEFINE_NUMERIC_WITH_BYTESWAP(type,byte_order,gtype,stype,routine,order) \
DEFINE_NUMERIC (type,byte_order) \
numeric_##type \
numeric_##type##_from_##gtype (g##gtype num) \
{ \
Expand All @@ -93,30 +84,158 @@ numeric_##type##_to_##gtype (numeric_##type num) \
return data.v_##gtype; \
}

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)
DEFINE_NUMERIC_WITH_BYTESWAP (uint_be, uint, guint, GUINT, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (long_le, long, glong, GLONG, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (long_be, long, glong, GLONG, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (ulong_le, ulong, gulong, GLONG, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (ulong_be, ulong, gulong, GLONG, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (int64_le, int64, gint64, GINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (int64_be, int64, gint64, GINT64, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint64_le, uint64, guint64, GUINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint64_be, uint64, guint64, GUINT64, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (float_le, float, gint32, GINT32, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (float_be, float, gint32, GINT32, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (double_le, double, gint32, GINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (double_be, double, gint32, GINT64, BE)
static GArray *TYPE_TABLE = NULL;

static void
numeric_type_info_init (NumericTypeInfo *type_info,
GType type,
const gchar *name,
gsize width,
gint byte_order)
{
type_info->type = type,
type_info->name = g_strdup (name);
type_info->width = width;
type_info->byte_order = byte_order;
}

static void
numeric_type_info_clear (NumericTypeInfo *type_info)
{
g_free (type_info->name);
}

/**
*
*/
void numeric_type_register_static (GType type,
const gchar *name,
const NumericTypeInfo *type_info)
{
if (TYPE_TABLE == NULL)
{
TYPE_TABLE = g_array_new (FALSE, FALSE, sizeof (NumericTypeInfo));
g_array_set_clear_func (TYPE_TABLE, (GDestroyNotify) numeric_type_info_clear);
}

/* 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_info->type)
return;
}

g_array_append_vals (TYPE_TABLE, type_info, 1);
}

void
numeric_type_register_static_simple (GType type,
const gchar *name,
gsize width,
gint byte_order)
{
NumericTypeInfo ti;

numeric_type_info_init (&ti, type, name, width, byte_order);

numeric_type_register_static (type, name, &ti);
}

/*
* GLib numerical types already have existing definitions for *_get_type(),
* preventing us from registering their numeric_{type}_get_type() counterpart
* lazily.
*/
static void
register_glib_numerical_types ()
{
numeric_type_register_static_simple (G_TYPE_CHAR, "char", sizeof (gchar), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_UCHAR, "uchar", sizeof (guchar), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_INT, "int", sizeof (gint), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_UINT, "uint", sizeof (guint), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_LONG, "long", sizeof (glong), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_ULONG, "ulong", sizeof (gulong), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_INT64, "int64", sizeof (gint64), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_UINT64, "uint64", sizeof (guint64), G_BYTE_ORDER);
numeric_type_register_static_simple (G_TYPE_FLOAT, "float", sizeof (gfloat), G_BYTE_ORDER);
numeric_type_register_static_simple (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.

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)
{
register_glib_numerical_types ();

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)
{
register_glib_numerical_types ();

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);
}

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

DEFINE_NUMERIC_WITH_BYTESWAP (int_le, G_LITTLE_ENDIAN, int, gint, GINT, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (int_be, G_BIG_ENDIAN, int, gint, GINT, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint_le, G_LITTLE_ENDIAN, uint, guint, GUINT, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint_be, G_BIG_ENDIAN, uint, guint, GUINT, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (long_le, G_LITTLE_ENDIAN, long, glong, GLONG, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (long_be, G_BIG_ENDIAN, long, glong, GLONG, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (ulong_le, G_LITTLE_ENDIAN, ulong, gulong, GLONG, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (ulong_be, G_BIG_ENDIAN, ulong, gulong, GLONG, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (int64_le, G_LITTLE_ENDIAN, int64, gint64, GINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (int64_be, G_BIG_ENDIAN, int64, gint64, GINT64, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint64_le, G_LITTLE_ENDIAN, uint64, guint64, GUINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (uint64_be, G_BIG_ENDIAN, uint64, guint64, GUINT64, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (float_le, G_LITTLE_ENDIAN, float, gint32, GINT32, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (float_be, G_BIG_ENDIAN, float, gint32, GINT32, BE)
DEFINE_NUMERIC_WITH_BYTESWAP (double_le, G_LITTLE_ENDIAN, double, gint32, GINT64, LE)
DEFINE_NUMERIC_WITH_BYTESWAP (double_be, G_BIG_ENDIAN, double, gint32, GINT64, BE)
Copy link
Owner Author

Choose a reason for hiding this comment

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

I think we're almost good now. I will incorporate your piece of code (if license permit?) to perform generic byte swapping.

Copy link
Contributor

Choose a reason for hiding this comment

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

No problem. There is a minimal version of numpy 'dtype' in bigfile, included some macros for casting and striding. Feel free to recycle any pieces there.


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

__attribute__ ((constructor))
static void
numeric_types_init (void)
{
#if HAVE_LIBDFP
arteymix marked this conversation as resolved.
Show resolved Hide resolved
register_printf_dfp ();
}
#endif
}
28 changes: 28 additions & 0 deletions src/numeric-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,34 @@

G_BEGIN_DECLS

/**
* Type information for a given registered numeric type.
*
* @type: Registered GType for this numerical type
* @name: Name
* @width: Size in bytes
* @byte_order: Byte order
*/
typedef struct _NumericTypeInfo
{
GType type;
gchar *name;
gsize width;
gint byte_order;
} NumericTypeInfo;

void numeric_type_register_static (GType type,
const gchar *name,
const NumericTypeInfo *type_info);

void numeric_type_register_static_simple (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);

#define DEFINE_NUMERIC_PROTOTYPE(type,ctype) \
typedef ctype numeric_##type; \
GType numeric_##type##_get_type (void) G_GNUC_CONST; \
Expand Down
15 changes: 15 additions & 0 deletions tests/numeric-c-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,24 @@

#include <numeric.h>

void
test_glib_types (void)
{
g_assert_cmpstr (numeric_get_type_info (G_TYPE_INT)->name, ==, "int");
g_assert_cmpstr (numeric_get_type_info (G_TYPE_UINT)->name, ==, "uint");
}

void
test_decimal128 (void)
{
numeric_decimal128 a;

const NumericTypeInfo *ti = numeric_get_type_info (NUMERIC_TYPE_DECIMAL128);

g_assert_cmpstr (ti->name, ==, "decimal128");
g_assert_cmpint (ti->width, ==, 16);
g_assert (ti->byte_order == G_BYTE_ORDER);

#if HAVE_LIBDFP
a = strtod128 ("0.1", NULL);
#else
Expand All @@ -55,7 +68,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 ();
}
10 changes: 10 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 All @@ -43,6 +48,11 @@ public int main (string[] args)
});

Test.add_func ("/float_be", () => {
unowned Numeric.TypeInfo ti = get_type_info (typeof (float_be));

assert (ti.name == "float_be");
assert (ti.byte_order == ByteOrder.BIG_ENDIAN);

var a = Value (typeof (float));
a.set_float (5.0f);

Expand Down