add refcnt util

This commit is contained in:
falsycat 2023-11-29 08:36:05 +09:00
parent cb9e6439c5
commit 90b2ede984
3 changed files with 87 additions and 0 deletions

View File

@ -6,10 +6,12 @@ target_sources(nf7util
array.h
log.h
malloc.h
refcnt.h
signal.h
)
target_tests(nf7util
array.test.c
refcnt.test.c
)
target_link_libraries(nf7util
PRIVATE

42
util/refcnt.h Normal file
View File

@ -0,0 +1,42 @@
// No copyright
#pragma once
#include <assert.h>
#include <stdatomic.h>
#include "util/malloc.h"
#define NF7_REFCNT_DECL(ATTR, T) \
ATTR void T##_ref(struct T*); \
ATTR bool T##_unref(struct T*); \
static_assert(true)
#define NF7_REFCNT_IMPL(ATTR, T, DELETER) \
ATTR void T##_ref(struct T* this) { \
++this->refcnt; \
} \
ATTR bool T##_unref(struct T* this) { \
assert(0 < this->refcnt); \
if (0 == --this->refcnt) { \
{DELETER}; \
return true; \
} \
return false; \
} \
static_assert(true)
#define NF7_REFCNT_IMPL_ATOMIC(ATTR, T, DELETER) \
ATTR void T##_ref(struct T* this) { \
atomic_fetch_add(&this->refcnt, 1); \
} \
ATTR bool T##_unref(struct T* this) { \
assert(0 < this->refcnt); \
if (1 == atomic_fetch_sub(&this->refcnt, 1)) { \
{DELETER}; \
return true; \
} \
return false; \
} \
static_assert(true)

43
util/refcnt.test.c Normal file
View File

@ -0,0 +1,43 @@
// No copyright
#include "util/refcnt.h"
#include <stdatomic.h>
#include <stdint.h>
#include "test/common.h"
struct mystruct {
bool deleted;
uint64_t refcnt;
};
NF7_REFCNT_IMPL(static inline, mystruct, {this->deleted = true;});
struct mystruct_atomic {
bool deleted;
atomic_uint_least64_t refcnt;
};
NF7_REFCNT_IMPL_ATOMIC(static inline, mystruct_atomic, {this->deleted = true;});
NF7_TEST(nf7_util_refcnt_test_delete) {
struct mystruct sut = {0};
mystruct_ref(&sut);
mystruct_ref(&sut);
return
nf7_test_expect(!mystruct_unref(&sut)) &&
nf7_test_expect(!sut.deleted) &&
nf7_test_expect(mystruct_unref(&sut)) &&
nf7_test_expect(sut.deleted);
}
NF7_TEST(nf7_util_refcnt_test_atomic_delete) {
struct mystruct_atomic sut = {0};
mystruct_atomic_ref(&sut);
mystruct_atomic_ref(&sut);
return
nf7_test_expect(!mystruct_atomic_unref(&sut)) &&
nf7_test_expect(!sut.deleted) &&
nf7_test_expect(mystruct_atomic_unref(&sut)) &&
nf7_test_expect(sut.deleted);
}