summaryrefslogtreecommitdiff
path: root/src/runtime/c/gu/variant.c
diff options
context:
space:
mode:
authorkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
committerkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
commit2eee382a62a909d5a3f2f5eda94f30fe68fd5335 (patch)
treeb0b0d513535895f244214aebf6358e172b8dce6d /src/runtime/c/gu/variant.c
parentb9728357126f8b9a6311cca17d9f0dcc2a7bfb9b (diff)
initial import of the C runtime
Diffstat (limited to 'src/runtime/c/gu/variant.c')
-rw-r--r--src/runtime/c/gu/variant.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/runtime/c/gu/variant.c b/src/runtime/c/gu/variant.c
new file mode 100644
index 000000000..62fdb92c1
--- /dev/null
+++ b/src/runtime/c/gu/variant.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010 University of Helsinki.
+ *
+ * This file is part of libgu.
+ *
+ * Libgu is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * Libgu is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libgu. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "variant.h"
+#include "bits.h"
+
+enum {
+ GU_VARIANT_ALIGNMENT = sizeof(uintptr_t)
+};
+
+void*
+gu_alloc_variant(uint8_t tag, size_t size,
+ size_t align, GuVariant* variant_out, GuPool* pool)
+{
+ align = gu_max(align, GU_VARIANT_ALIGNMENT);
+ if (((size_t)tag) > GU_VARIANT_ALIGNMENT - 2) {
+ uint8_t* alloc = gu_malloc_aligned(pool, align + size, align);
+ alloc[align - 1] = tag;
+ void* p = &alloc[align];
+ variant_out->p = (uintptr_t)p;
+ return p;
+ }
+ void* p = gu_malloc_aligned(pool, size, align);
+ variant_out->p = ((uintptr_t)p) | (tag + 1);
+ return p;
+}
+
+GuVariant
+gu_make_variant(uint8_t tag, size_t size, size_t align, const void* init,
+ GuPool* pool)
+{
+ GuVariant v;
+ void* data = gu_alloc_variant(tag, size, align, &v, pool);
+ memcpy(data, init, size);
+ return v;
+}
+
+int
+gu_variant_tag(GuVariant variant)
+{
+ if (gu_variant_is_null(variant)) {
+ return GU_VARIANT_NULL;
+ }
+ int u = variant.p % GU_VARIANT_ALIGNMENT;
+ if (u == 0) {
+ uint8_t* mem = (uint8_t*)variant.p;
+ return mem[-1];
+ }
+ return u - 1;
+}
+
+void*
+gu_variant_data(GuVariant variant)
+{
+ if (gu_variant_is_null(variant)) {
+ return NULL;
+ }
+ return (void*)gu_align_backward(variant.p, GU_VARIANT_ALIGNMENT);
+}
+
+GuVariantInfo gu_variant_open(GuVariant variant)
+{
+ GuVariantInfo info = {
+ .tag = gu_variant_tag(variant),
+ .data = gu_variant_data(variant)
+ };
+ return info;
+}
+
+int
+gu_variant_intval(GuVariant variant)
+{
+ int u = variant.p % GU_VARIANT_ALIGNMENT;
+ if (u == 0) {
+ int* mem = (int*)variant.p;
+ return *mem;
+ }
+ return (variant.p / GU_VARIANT_ALIGNMENT);
+}
+
+const GuVariant gu_null_variant = { (GuWord) NULL };
+
+GU_DEFINE_KIND(GuVariant, repr);
+GU_DEFINE_KIND(GuVariantAsPtr, repr);