
#include <glib.h>
#include <glib-object.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>


#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;
typedef struct _TestParamSpecPerf TestParamSpecPerf;

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

struct _OClassClass {
	GObjectClass parent_class;
};

/*class MiniClass : Gst.MiniObject {
    public uint f1;
    public double f2;

    MiniClass (uint f1, double f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
}*/
struct _TestPerf {
	GTypeInstance parent_instance;
	volatile int ref_count;
	TestPerfPrivate * priv;
};

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

struct _TestPerfPrivate {
	OClass* aoclass;
	GTimer* timer;
};

struct _TestParamSpecPerf {
	GParamSpec parent_instance;
};


static gpointer oclass_parent_class = NULL;
static gpointer test_perf_parent_class = NULL;

GType oclass_get_type (void);
enum  {
	OCLASS_DUMMY_PROPERTY
};
OClass* oclass_new (void);
OClass* oclass_construct (GType object_type);
OClass* oclass_instantiate (guint f1, double f2);
OClass* oclass_new (void);
static void oclass_finalize (GObject* obj);
gpointer test_perf_ref (gpointer instance);
void test_perf_unref (gpointer instance);
GParamSpec* test_param_spec_perf (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags);
void test_value_set_perf (GValue* value, gpointer v_object);
gpointer test_value_get_perf (const GValue* value);
GType test_perf_get_type (void);
#define TEST_PERF_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_PERF, TestPerfPrivate))
enum  {
	TEST_PERF_DUMMY_PROPERTY
};
#define TEST_PERF_NUM_INSTANCES ((guint) 10000000)
void test_perf_test_oclass (TestPerf* self);
TestPerf* test_perf_new (void);
TestPerf* test_perf_construct (GType object_type);
gint test_perf_main (char** args, int args_length1);
TestPerf* test_perf_new (void);
static void test_perf_finalize (TestPerf* obj);
static void _vala_array_destroy (gpointer array, gint array_length, GDestroyNotify destroy_func);
static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func);



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


OClass* oclass_construct (GType object_type) {
	OClass * self;
	self = g_object_newv (object_type, 0, NULL);
	return self;
}


OClass* oclass_new (void) {
	return oclass_construct (TYPE_OCLASS);
}


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


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, NULL };
		oclass_type_id = g_type_register_static (G_TYPE_OBJECT, "OClass", &g_define_type_info, 0);
	}
	return oclass_type_id;
}


/*    public void test_mini_class () {
        MiniClass[] classes = new MiniClass[NUM_INSTANCES];
 Reset timer
        this.timer.start ();
        for (int i = 0; i < NUM_INSTANCES; i++) {
            classes[i] = new MiniClass (0, 0.0);
        }
        print ("%f seconds taken in creating %u instances (GstMiniObject).\n",
               timer.elapsed (),
               NUM_INSTANCES);
    }*/
void test_perf_test_oclass (TestPerf* self) {
	OClass** _tmp0_;
	gint classes_size;
	gint classes_length1;
	OClass** classes;
	g_return_if_fail (self != NULL);
	_tmp0_ = NULL;
	classes = (_tmp0_ = g_new0 (OClass*, TEST_PERF_NUM_INSTANCES + 1), classes_length1 = TEST_PERF_NUM_INSTANCES, classes_size = classes_length1, _tmp0_);
	/* Reset timer*/
	g_timer_start (self->priv->timer);
	{
		gint i;
		i = 0;
		{
			gboolean _tmp1_;
			_tmp1_ = TRUE;
			while (TRUE) {
				OClass* _tmp2_;
				if (!_tmp1_) {
					i++;
				}
				_tmp1_ = FALSE;
				if (!(i < TEST_PERF_NUM_INSTANCES)) {
					break;
				}
				_tmp2_ = NULL;
				classes[i] = (_tmp2_ = oclass_instantiate ((guint) 0, 0.0), (classes[i] == NULL) ? NULL : (classes[i] = (g_object_unref (classes[i]), NULL)), _tmp2_);
			}
		}
	}
	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);
}


gint test_perf_main (char** args, int args_length1) {
	gint result;
	TestPerf* perf;
	guint i;
	perf = test_perf_new ();
	i = 0U;
	{
		gboolean _tmp0_;
		i = (guint) 0;
		_tmp0_ = TRUE;
		while (TRUE) {
			if (!_tmp0_) {
				i++;
			}
			_tmp0_ = FALSE;
			if (!(i < 5)) {
				break;
			}
			if (i < 2) {
				g_print ("Don't count these:\n");
			} else {
				g_print ("Useful results:\n");
			}
			/*        perf.test_mini_class ();*/
			test_perf_test_oclass (perf);
		}
	}
	result = 0;
	(perf == NULL) ? NULL : (perf = (test_perf_unref (perf), NULL));
	return result;
}


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


/*class MiniClass : Gst.MiniObject {
    public uint f1;
    public double f2;

    MiniClass (uint f1, double f2) {
        this.f1 = f1;
        this.f2 = f2;
    }
}*/
TestPerf* test_perf_construct (GType object_type) {
	TestPerf* self;
	self = (TestPerf*) g_type_create_instance (object_type);
	return self;
}


TestPerf* test_perf_new (void) {
	return test_perf_construct (TEST_TYPE_PERF);
}


static void test_value_perf_init (GValue* value) {
	value->data[0].v_pointer = NULL;
}


static void test_value_perf_free_value (GValue* value) {
	if (value->data[0].v_pointer) {
		test_perf_unref (value->data[0].v_pointer);
	}
}


static void test_value_perf_copy_value (const GValue* src_value, GValue* dest_value) {
	if (src_value->data[0].v_pointer) {
		dest_value->data[0].v_pointer = test_perf_ref (src_value->data[0].v_pointer);
	} else {
		dest_value->data[0].v_pointer = NULL;
	}
}


static gpointer test_value_perf_peek_pointer (const GValue* value) {
	return value->data[0].v_pointer;
}


static gchar* test_value_perf_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
	if (collect_values[0].v_pointer) {
		TestPerf* object;
		object = collect_values[0].v_pointer;
		if (object->parent_instance.g_class == NULL) {
			return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		} else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
			return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
		}
		value->data[0].v_pointer = test_perf_ref (object);
	} else {
		value->data[0].v_pointer = NULL;
	}
	return NULL;
}


static gchar* test_value_perf_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
	TestPerf** object_p;
	object_p = collect_values[0].v_pointer;
	if (!object_p) {
		return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
	}
	if (!value->data[0].v_pointer) {
		*object_p = NULL;
	} else if (collect_flags && G_VALUE_NOCOPY_CONTENTS) {
		*object_p = value->data[0].v_pointer;
	} else {
		*object_p = test_perf_ref (value->data[0].v_pointer);
	}
	return NULL;
}


GParamSpec* test_param_spec_perf (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) {
	TestParamSpecPerf* spec;
	g_return_val_if_fail (g_type_is_a (object_type, TEST_TYPE_PERF), NULL);
	spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
	G_PARAM_SPEC (spec)->value_type = object_type;
	return G_PARAM_SPEC (spec);
}


gpointer test_value_get_perf (const GValue* value) {
	g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TEST_TYPE_PERF), NULL);
	return value->data[0].v_pointer;
}


void test_value_set_perf (GValue* value, gpointer v_object) {
	TestPerf* old;
	g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TEST_TYPE_PERF));
	old = value->data[0].v_pointer;
	if (v_object) {
		g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TEST_TYPE_PERF));
		g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
		value->data[0].v_pointer = v_object;
		test_perf_ref (value->data[0].v_pointer);
	} else {
		value->data[0].v_pointer = NULL;
	}
	if (old) {
		test_perf_unref (old);
	}
}


static void test_perf_class_init (TestPerfClass * klass) {
	test_perf_parent_class = g_type_class_peek_parent (klass);
	TEST_PERF_CLASS (klass)->finalize = test_perf_finalize;
	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->aoclass = oclass_instantiate ((guint) 0, 0.0);
	self->priv->timer = g_timer_new ();
	self->ref_count = 1;
}


static void test_perf_finalize (TestPerf* obj) {
	TestPerf * self;
	self = TEST_PERF (obj);
	(self->priv->aoclass == NULL) ? NULL : (self->priv->aoclass = (g_object_unref (self->priv->aoclass), NULL));
	(self->priv->timer == NULL) ? NULL : (self->priv->timer = (g_timer_destroy (self->priv->timer), NULL));
}


GType test_perf_get_type (void) {
	static GType test_perf_type_id = 0;
	if (test_perf_type_id == 0) {
		static const GTypeValueTable g_define_type_value_table = { test_value_perf_init, test_value_perf_free_value, test_value_perf_copy_value, test_value_perf_peek_pointer, "p", test_value_perf_collect_value, "p", test_value_perf_lcopy_value };
		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, &g_define_type_value_table };
		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;
}


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


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


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


static void _vala_array_free (gpointer array, gint array_length, GDestroyNotify destroy_func) {
	_vala_array_destroy (array, array_length, destroy_func);
	g_free (array);
}




