|
#ifndef SHARED_PTR_H |
|
#define SHARED_PTR_H |
|
|
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <stdatomic.h> |
|
|
|
#ifdef TEST |
|
#include <assert.h> |
|
#include <string.h> |
|
#define streq(a, b) (!strcmp((a), (b))) |
|
#endif |
|
|
|
/* API */ |
|
|
|
typedef struct shared_ptr shared_ptr; |
|
|
|
shared_ptr* sp_new(void **obj, void (*free_fn)(void *)); |
|
shared_ptr* sp_copy(const shared_ptr *sp); |
|
void sp_free(shared_ptr *sp); |
|
void* sp_get(const shared_ptr *sp); |
|
|
|
/* Implementation */ |
|
|
|
#ifdef TEST |
|
int malloc_count = 0; |
|
int free_count = 0; |
|
|
|
void *_malloc(size_t size) { |
|
malloc_count++; |
|
return malloc(size); |
|
} |
|
|
|
void _free(void *ptr) { |
|
free_count++; |
|
free(ptr); |
|
} |
|
|
|
#define malloc _malloc |
|
#define free _free |
|
#endif |
|
|
|
typedef struct obj { |
|
char *content; |
|
} obj; |
|
|
|
typedef struct inner_ptr { |
|
_Atomic int count; |
|
void *obj; |
|
void (*free_fn)(void *); |
|
} inner_ptr; |
|
|
|
struct shared_ptr { |
|
inner_ptr *ptr; |
|
}; |
|
|
|
shared_ptr* sp_new(void **obj, void (*free_fn)(void *)) { |
|
shared_ptr *sp = (shared_ptr*)malloc(sizeof(shared_ptr)); |
|
sp->ptr = (inner_ptr*)malloc(sizeof(inner_ptr)); |
|
sp->ptr->count = 1; |
|
sp->ptr->obj = *obj; |
|
sp->ptr->free_fn = free_fn; |
|
*obj = NULL; |
|
return sp; |
|
} |
|
|
|
shared_ptr* sp_copy(const shared_ptr *sp) { |
|
atomic_fetch_add(&sp->ptr->count, 1); |
|
shared_ptr *new_sp = (shared_ptr*)malloc(sizeof(shared_ptr)); |
|
new_sp->ptr = sp->ptr; |
|
return new_sp; |
|
} |
|
|
|
void sp_free(shared_ptr *sp) { |
|
if (atomic_fetch_sub(&sp->ptr->count, 1) == 1) { |
|
sp->ptr->free_fn(sp->ptr->obj); |
|
free(sp->ptr); |
|
} |
|
free(sp); |
|
} |
|
|
|
void* sp_get(const shared_ptr *sp) { |
|
return sp->ptr->obj; |
|
} |
|
|
|
/* Example */ |
|
|
|
#ifdef TEST |
|
int main(int argc, char const *argv[]) |
|
{ |
|
obj *o = malloc(sizeof(struct obj)); |
|
char *str = "Hello World"; |
|
o->content = str; |
|
|
|
shared_ptr *sp = sp_new((void **)&o, free); |
|
assert(o == NULL); |
|
assert(streq(str, ((obj*)(sp_get(sp)))->content)); |
|
|
|
shared_ptr *sp2 = sp_copy(sp); |
|
|
|
assert(streq(str, ((obj*)(sp_get(sp2)))->content)); |
|
assert(streq(str, ((obj*)(sp_get(sp)))->content)); |
|
|
|
sp_free(sp2); |
|
|
|
assert(streq(str, ((obj*)(sp_get(sp)))->content)); |
|
|
|
sp_free(sp); |
|
|
|
assert(malloc_count == free_count); |
|
|
|
printf("tests passed\n"); |
|
|
|
return 0; |
|
} |
|
#endif |
|
|
|
#endif // SHARED_PTR_H |