]> gitweb.ps.run Git - onefile/blobdiff - smartptrs.c
add smartptrs.c
[onefile] / smartptrs.c
diff --git a/smartptrs.c b/smartptrs.c
new file mode 100644 (file)
index 0000000..fb483ec
--- /dev/null
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+typedef struct Ptr *Ptr;
+typedef struct Ref *Ref;
+
+typedef struct Ptr
+{
+    Ref ref;
+    Ptr next, prev;
+} *Ptr;
+typedef struct Ref
+{
+    int *data;
+    Ptr head, tail;
+} *Ref;
+
+Ref ref_new(int value)
+{
+    Ref result = malloc(sizeof(struct Ref));
+
+    result->data = malloc(sizeof(int));
+    *result->data = value;
+
+    result->head = result->tail = NULL;
+
+    return result;
+}
+
+Ref ref_move(Ref ref)
+{
+    Ref result = malloc(sizeof(struct Ref));
+
+    result->data = ref->data;
+
+    result->head = ref->head;
+    result->tail = ref->tail;
+
+    for (Ptr p = ref->head; p != NULL; p = p->next)
+    {
+        p->ref = result;
+    }
+    free(ref);
+    return result;
+}
+
+void ref_add_ptr(Ref ref, Ptr ptr)
+{
+    if (ref->head == NULL)
+    {
+        ref->head = ptr;
+        ref->tail = ptr;
+        ptr->next = ptr->prev = NULL;
+        return;
+    }
+    ref->tail->next = ptr;
+    ptr->prev = ref->tail;
+    ptr->next = NULL;
+    ref->tail = ptr;
+}
+
+void ref_remove_ptr(Ref ref, Ptr ptr)
+{
+    for (Ptr p = ref->head; p != NULL; p = p->next)
+    {
+        if (p == ptr)
+        {
+            if (p->prev == NULL)
+                ref->head = p->next;
+            else
+                p->prev->next = p->next;
+
+            if (p->next == NULL)
+                ref->tail = p->prev;
+            else
+                p->next->prev = p->prev;
+
+            return;
+        }
+    }
+}
+
+void ref_free(Ref ref)
+{
+    for (Ptr p = ref->head; p != NULL; p = p->next)
+    {
+        p->ref = NULL;
+    }
+    free(ref->data);
+    free(ref);
+}
+
+Ptr ptr_new(Ref ref)
+{
+    Ptr result = malloc(sizeof(struct Ptr));
+
+    result->ref = ref;
+
+    ref_add_ptr(ref, result);
+
+    return result;
+}
+
+int ptr_get(Ptr ptr)
+{
+    if (ptr->ref != NULL)
+        return *ptr->ref->data;
+    return 0;
+}
+
+void ptr_free(Ptr ptr)
+{
+    if (ptr->ref != NULL)
+        ref_remove_ptr(ptr->ref, ptr);
+    free(ptr);
+}
+
+void test_ref()
+{
+    Ref r1 = ref_new(123);
+
+    Ptr p1 = ptr_new(r1);
+    Ptr p2 = ptr_new(r1);
+    Ptr p3 = ptr_new(r1);
+    Ptr p4 = ptr_new(r1);
+
+    Ref r2 = ref_move(r1);
+
+    int i = ptr_get(p1) + ptr_get(p2) + ptr_get(p3) + ptr_get(p4);
+
+    ptr_free(p1);
+    ptr_free(p2);
+
+    ref_free(r2);
+
+    ptr_free(p3);
+    ptr_free(p4);
+}
+
+void test_reg()
+{
+    int *r1 = malloc(sizeof(int));
+    *r1 = 123;
+
+    int *p1 = r1;
+    int *p2 = r1;
+    int *p3 = r1;
+    int *p4 = r1;
+
+    int i = *p1 + *p2 + *p3 + *p4;
+
+    int *r2 = r1;
+    r1 = NULL;
+
+    free(r2);
+}
+
+int main(int argc, char **argv)
+{
+    const long N = 1000000;
+
+    clock_t start, end;
+
+    start = clock();
+    for (long i = 0; i < N; i++)
+        test_ref();
+    end = clock();
+    printf("ref: %fms\n", ((double)(end - start)) / CLOCKS_PER_SEC * 1000);
+
+    start = clock();
+    for (long i = 0; i < N; i++)
+        test_reg();
+    end = clock();
+    printf("reg: %fms\n", ((double)(end - start)) / CLOCKS_PER_SEC * 1000);
+
+    return 0;
+}