Skip to content

Instantly share code, notes, and snippets.

@BuonOmo
Last active September 12, 2022 08:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BuonOmo/a4467a2701920625d40f4461749ef0f1 to your computer and use it in GitHub Desktop.
Save BuonOmo/a4467a2701920625d40f4461749ef0f1 to your computer and use it in GitHub Desktop.
Simple shared pointer lib in C
#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment