/* test-perf.vala
 *
 * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
 *
 * Licensed under GPLv2.
 *
 * A simple test app to compare the time it takes to create instances of struct,
 * compact class, class and class deriving from GLib.Object in Vala.
 *
 * Compile using: valac -o test-perf --pkg gstreamer-0.10 test-perf.vala
 *
 */

#include "test.h"
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

typedef struct _Struct Struct;
typedef struct _CompactClass CompactClass;

#define TYPE_CLASS (class_get_type ())
#define CLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLASS, Class))
#define CLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLASS, ClassClass))
#define IS_CLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLASS))
#define IS_CLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLASS))
#define CLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLASS, ClassClass))

typedef struct _Class Class;
typedef struct _ClassClass ClassClass;
typedef struct _ClassPrivate ClassPrivate;

#define TYPE_MINICLASS (miniclass_get_type ())
#define MINICLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MINICLASS, MiniClass))
#define MINICLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MINICLASS, MiniClassClass))
#define IS_MINICLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MINICLASS))
#define IS_MINICLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MINICLASS))
#define MINICLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MINICLASS, MiniClassClass))

typedef struct _MiniClass MiniClass;
typedef struct _MiniClassClass MiniClassClass;
typedef struct _MiniClassPrivate MiniClassPrivate;

#define TYPE_OCLASS (oclass_get_type ())
#define OCLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_OCLASS, OClass))
#define OCLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_OCLASS, OClassClass))
#define IS_OCLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_OCLASS))
#define IS_OCLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_OCLASS))
#define OCLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_OCLASS, OClassClass))

typedef struct _OClass OClass;
typedef struct _OClassClass OClassClass;
typedef struct _OClassPrivate OClassPrivate;

#define TEST_TYPE_PERF (test_perf_get_type ())
#define TEST_PERF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_PERF, TestPerf))
#define TEST_PERF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_PERF, TestPerfClass))
#define TEST_IS_PERF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_PERF))
#define TEST_IS_PERF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_PERF))
#define TEST_PERF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_PERF, TestPerfClass))

typedef struct _TestPerf TestPerf;
typedef struct _TestPerfClass TestPerfClass;
typedef struct _TestPerfPrivate TestPerfPrivate;

struct _Struct {
	guint f1;
	double f2;
};

struct _CompactClass {
	guint f1;
	double f2;
};

struct _Class {
	GTypeInstance parent_instance;
	volatile int ref_count;
	ClassPrivate * priv;
	guint f1;
	double f2;
};

struct _ClassClass {
	GTypeClass parent_class;
	void (*finalize) (Class *self);
};

struct _MiniClass {
	GstMiniObject parent_instance;
	MiniClassPrivate * priv;
	guint f1;
	double f2;
};

struct _MiniClassClass {
	GstMiniObjectClass parent_class;
};

struct _OClass {
	GObject parent_instance;
	OClassPrivate * priv;
	guint f1;
	double f2;
};

struct _OClassClass {
	GObjectClass parent_class;
};

struct _TestPerf {
	GTypeInstance parent_instance;
	volatile int ref_count;
	TestPerfPrivate * priv;
};

struct _TestPerfClass {
	GTypeClass parent_class;
	void (*finalize) (TestPerf *self);
};



static CompactClass* compactclass_new (guint f1, double f2);
static void compactclass_instance_init (CompactClass * self);
static void compactclass_free (CompactClass* self);
enum  {
	CLASS_DUMMY_PROPERTY
};
static Class* class_new (guint f1, double f2);
static gpointer class_parent_class = NULL;
static GType class_get_type (void);
static gpointer class_ref (gpointer instance);
static void class_unref (gpointer instance);
enum  {
	MINICLASS_DUMMY_PROPERTY
};
static MiniClass* miniclass_new (guint f1, double f2);
static gpointer miniclass_parent_class = NULL;
static GType miniclass_get_type (void);
enum  {
	OCLASS_DUMMY_PROPERTY
};
static OClass* oclass_instantiate (guint f1, double f2);
static OClass* oclass_new (void);
static gpointer oclass_parent_class = NULL;
static void oclass_finalize (GObject * obj);
static GType oclass_get_type (void);
struct _TestPerfPrivate {
	Class* aclass;
	CompactClass* acompactclass;
	OClass* aoclass;
	GTimer* timer;
};

#define TEST_PERF_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_PERF, TestPerfPrivate))
enum  {
	TEST_PERF_DUMMY_PROPERTY
};
static void test_perf_test_struct (TestPerf* self);
static void test_perf_test_class (TestPerf* self);
static void test_perf_test_compact_class (TestPerf* self);
static void test_perf_test_mini_class (TestPerf* self);
static void test_perf_test_oclass (TestPerf* self);
static gint test_perf_main (char** args, int args_length1);
static TestPerf* test_perf_new (void);
static gpointer test_perf_parent_class = NULL;
static GType test_perf_get_type (void);
static gpointer test_perf_ref (gpointer instance);
static void test_perf_unref (gpointer instance);
static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func);

static const guint TEST_PERF_NUM_INSTANCES = ((guint) (1048576));


static CompactClass* compactclass_new (guint f1, double f2) {
	CompactClass* self;
	self = g_slice_new0 (CompactClass);
	compactclass_instance_init (self);
	self->f1 = f1;
	self->f2 = f2;
	return self;
}


static void compactclass_instance_init (CompactClass * self) {
}


static void compactclass_free (CompactClass* self) {
	g_slice_free (CompactClass, self);
}


static Class* class_new (guint f1, double f2) {
	Class* self;
	self = ((Class*) (g_type_create_instance (TYPE_CLASS)));
	self->f1 = f1;
	self->f2 = f2;
	return self;
}


static void class_class_init (ClassClass * klass) {
	class_parent_class = g_type_class_peek_parent (klass);
}


static void class_instance_init (Class * self) {
	self->ref_count = 1;
}


static GType class_get_type (void) {
	static GType class_type_id = 0;
	if (class_type_id == 0) {
		static const GTypeInfo g_define_type_info = { sizeof (ClassClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) class_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Class), 0, (GInstanceInitFunc) class_instance_init };
		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
		class_type_id = g_type_register_fundamental (g_type_fundamental_next (), "Class", &g_define_type_info, &g_define_type_fundamental_info, 0);
	}
	return class_type_id;
}


static gpointer class_ref (gpointer instance) {
	Class* self;
	self = instance;
	g_atomic_int_inc (&self->ref_count);
	return instance;
}


static void class_unref (gpointer instance) {
	Class* self;
	self = instance;
	if (g_atomic_int_dec_and_test (&self->ref_count)) {
		g_type_free_instance (((GTypeInstance *) (self)));
	}
}


static MiniClass* miniclass_new (guint f1, double f2) {
	MiniClass* self;
	self = ((MiniClass*) (g_type_create_instance (TYPE_MINICLASS)));
	self->f1 = f1;
	self->f2 = f2;
	return self;
}


static void miniclass_class_init (MiniClassClass * klass) {
	miniclass_parent_class = g_type_class_peek_parent (klass);
}


static void miniclass_instance_init (MiniClass * self) {
}


static GType miniclass_get_type (void) {
	static GType miniclass_type_id = 0;
	if (miniclass_type_id == 0) {
		static const GTypeInfo g_define_type_info = { sizeof (MiniClassClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) miniclass_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (MiniClass), 0, (GInstanceInitFunc) miniclass_instance_init };
		miniclass_type_id = g_type_register_static (GST_TYPE_MINI_OBJECT, "MiniClass", &g_define_type_info, 0);
	}
	return miniclass_type_id;
}


static OClass* oclass_instantiate (guint f1, double f2) {
	OClass* obj;
	obj = oclass_new ();
	obj->f1 = f1;
	obj->f2 = f2;
	return obj;
}


static OClass* oclass_new (void) {
	OClass * self;
	self = g_object_newv (TYPE_OCLASS, 0, NULL);
	return self;
}


static void oclass_class_init (OClassClass * klass) {
	oclass_parent_class = g_type_class_peek_parent (klass);
	G_OBJECT_CLASS (klass)->finalize = oclass_finalize;
}


static void oclass_instance_init (OClass * self) {
}


static void oclass_finalize (GObject * obj) {
	OClass * self;
	self = OCLASS (obj);
	G_OBJECT_CLASS (oclass_parent_class)->finalize (obj);
}


static GType oclass_get_type (void) {
	static GType oclass_type_id = 0;
	if (oclass_type_id == 0) {
		static const GTypeInfo g_define_type_info = { sizeof (OClassClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) oclass_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (OClass), 0, (GInstanceInitFunc) oclass_instance_init };
		oclass_type_id = g_type_register_static (G_TYPE_OBJECT, "OClass", &g_define_type_info, 0);
	}
	return oclass_type_id;
}


static void test_perf_test_struct (TestPerf* self) {
	Struct* _tmp0;
	gint structs_length1;
	Struct* structs;
	g_return_if_fail (TEST_IS_PERF (self));
	_tmp0 = NULL;
	structs = (_tmp0 = g_new0 (Struct, TEST_PERF_NUM_INSTANCES), structs_length1 = TEST_PERF_NUM_INSTANCES, _tmp0);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		for (; i < TEST_PERF_NUM_INSTANCES; i++) {
			structs[i].f1 = ((guint) (0));
			structs[i].f2 = 0.0;
		}
	}
	g_print ("%f seconds taken in creating %u structs.\n", g_timer_elapsed (self->priv->timer, NULL), TEST_PERF_NUM_INSTANCES);
	structs = (g_free (structs), NULL);
}


static void test_perf_test_class (TestPerf* self) {
	Class** _tmp0;
	gint classes_length1;
	Class** classes;
	g_return_if_fail (TEST_IS_PERF (self));
	_tmp0 = NULL;
	classes = (_tmp0 = g_new0 (Class*, TEST_PERF_NUM_INSTANCES + 1), classes_length1 = TEST_PERF_NUM_INSTANCES, _tmp0);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		for (; i < TEST_PERF_NUM_INSTANCES; i++) {
			Class* _tmp1;
			_tmp1 = NULL;
			classes[i] = (_tmp1 = class_new (((guint) (0)), 0.0), (classes[i] == NULL ? NULL : (classes[i] = (class_unref (classes[i]), NULL))), _tmp1);
		}
	}
	g_print ("%f seconds taken in creating %u instances.\n", g_timer_elapsed (self->priv->timer, NULL), TEST_PERF_NUM_INSTANCES);
	classes = (_vala_array_free (classes, classes_length1, ((GDestroyNotify) (class_unref))), NULL);
}


static void test_perf_test_compact_class (TestPerf* self) {
	CompactClass** _tmp0;
	gint classes_length1;
	CompactClass** classes;
	g_return_if_fail (TEST_IS_PERF (self));
	_tmp0 = NULL;
	classes = (_tmp0 = g_new0 (CompactClass*, TEST_PERF_NUM_INSTANCES + 1), classes_length1 = TEST_PERF_NUM_INSTANCES, _tmp0);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		for (; i < TEST_PERF_NUM_INSTANCES; i++) {
			CompactClass* _tmp1;
			_tmp1 = NULL;
			classes[i] = (_tmp1 = compactclass_new (((guint) (0)), 0.0), (classes[i] == NULL ? NULL : (classes[i] = (compactclass_free (classes[i]), NULL))), _tmp1);
		}
	}
	g_print ("%f seconds taken in creating %u instances (compact).\n", g_timer_elapsed (self->priv->timer, NULL), TEST_PERF_NUM_INSTANCES);
	classes = (_vala_array_free (classes, classes_length1, ((GDestroyNotify) (compactclass_free))), NULL);
}


static void test_perf_test_mini_class (TestPerf* self) {
	MiniClass** _tmp0;
	gint classes_length1;
	MiniClass** classes;
	g_return_if_fail (TEST_IS_PERF (self));
	_tmp0 = NULL;
	classes = (_tmp0 = g_new0 (MiniClass*, TEST_PERF_NUM_INSTANCES + 1), classes_length1 = TEST_PERF_NUM_INSTANCES, _tmp0);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		for (; i < TEST_PERF_NUM_INSTANCES; i++) {
			MiniClass* _tmp1;
			_tmp1 = NULL;
			classes[i] = (_tmp1 = miniclass_new (((guint) (0)), 0.0), (classes[i] == NULL ? NULL : (classes[i] = (gst_mini_object_unref (classes[i]), NULL))), _tmp1);
		}
	}
	g_print ("%f seconds taken in creating %u instances (GstMiniObject).\n", g_timer_elapsed (self->priv->timer, NULL), TEST_PERF_NUM_INSTANCES);
	classes = (_vala_array_free (classes, classes_length1, ((GDestroyNotify) (gst_mini_object_unref))), NULL);
}


static void test_perf_test_oclass (TestPerf* self) {
	OClass** _tmp0;
	gint classes_length1;
	OClass** classes;
	g_return_if_fail (TEST_IS_PERF (self));
	_tmp0 = NULL;
	classes = (_tmp0 = g_new0 (OClass*, TEST_PERF_NUM_INSTANCES + 1), classes_length1 = TEST_PERF_NUM_INSTANCES, _tmp0);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		for (; i < TEST_PERF_NUM_INSTANCES; i++) {
			OClass* _tmp1;
			_tmp1 = NULL;
			classes[i] = (_tmp1 = oclass_instantiate (((guint) (0)), 0.0), (classes[i] == NULL ? NULL : (classes[i] = (g_object_unref (classes[i]), NULL))), _tmp1);
		}
	}
	g_print ("%f seconds taken in creating %u instances (GObject).\n", g_timer_elapsed (self->priv->timer, NULL), TEST_PERF_NUM_INSTANCES);
	classes = (_vala_array_free (classes, classes_length1, ((GDestroyNotify) (g_object_unref))), NULL);
}


static gint test_perf_main (char** args, int args_length1) {
	TestPerf* perf;
	gint _tmp0;
	perf = test_perf_new ();
	test_perf_test_struct (perf);
	test_perf_test_compact_class (perf);
	test_perf_test_class (perf);
	test_perf_test_mini_class (perf);
	test_perf_test_oclass (perf);
	return (_tmp0 = 0, (perf == NULL ? NULL : (perf = (test_perf_unref (perf), NULL))), _tmp0);
}


int main (int argc, char ** argv) {
	g_type_init ();
	return test_perf_main (argv, argc);
}


static TestPerf* test_perf_new (void) {
	TestPerf* self;
	self = ((TestPerf*) (g_type_create_instance (TEST_TYPE_PERF)));
	return self;
}


static void test_perf_class_init (TestPerfClass * klass) {
	test_perf_parent_class = g_type_class_peek_parent (klass);
	g_type_class_add_private (klass, sizeof (TestPerfPrivate));
}


static void test_perf_instance_init (TestPerf * self) {
	self->priv = TEST_PERF_GET_PRIVATE (self);
	self->priv->aclass = class_new (((guint) (0)), 0.0);
	self->priv->acompactclass = compactclass_new (((guint) (0)), 0.0);
	self->priv->aoclass = oclass_instantiate (((guint) (0)), 0.0);
	self->priv->timer = g_timer_new ();
	self->ref_count = 1;
}


static GType test_perf_get_type (void) {
	static GType test_perf_type_id = 0;
	if (test_perf_type_id == 0) {
		static const GTypeInfo g_define_type_info = { sizeof (TestPerfClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) test_perf_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (TestPerf), 0, (GInstanceInitFunc) test_perf_instance_init };
		static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
		test_perf_type_id = g_type_register_fundamental (g_type_fundamental_next (), "TestPerf", &g_define_type_info, &g_define_type_fundamental_info, 0);
	}
	return test_perf_type_id;
}


static gpointer test_perf_ref (gpointer instance) {
	TestPerf* self;
	self = instance;
	g_atomic_int_inc (&self->ref_count);
	return instance;
}


static void test_perf_unref (gpointer instance) {
	TestPerf* self;
	self = instance;
	if (g_atomic_int_dec_and_test (&self->ref_count)) {
		g_type_free_instance (((GTypeInstance *) (self)));
	}
}


static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) {
	if (array != NULL && destroy_func != NULL) {
		int i;
		if (array_length >= 0)
		for (i = 0; i < array_length; i = i + 1) {
			if (((gpointer*) (array))[i] != NULL)
			destroy_func (((gpointer*) (array))[i]);
		}
		else
		for (i = 0; ((gpointer*) (array))[i] != NULL; i = i + 1) {
			destroy_func (((gpointer*) (array))[i]);
		}
	}
	g_free (array);
}




