28 # if __STDC_VERSION__ < 201100L
32 #ifdef P99_TP_NEED_INTEGER
33 # if UINTPTR_MAX == UINT32_MAX
34 typedef uint64_t p00_tp_glue;
36 # if defined(UINT128_MAX)
37 typedef uint128_t p00_tp_glue;
43 P99_CONSTANT(
int, p00_tp_bits,
sizeof(p00_tp_glue)*CHAR_BIT);
47 p00_tp_glue p00_tp_p2i(
void *
p, uintptr_t t) {
48 return (((p00_tp_glue)t)<<p00_tp_shift)|(uintptr_t)
p;
51 #define P00_TP_GLUE_INITIALIZER(VAL, TIC) ((((p00_tp_glue)VAL)<<p00_tp_shift)|((uintptr_t){(TIC)}))
55 void * p00_tp_i2p(p00_tp_glue
v) {
56 return (
void*)(uintptr_t)
v;
60 uintptr_t p00_tp_i2i(p00_tp_glue
v) {
61 return v >> p00_tp_shift;
72 #define P00_TP_GLUE_INITIALIZER(VAL, TIC) { .p00_tag = (TIC), .p00_val = (VAL), }
75 p00_tp_glue p00_tp_p2i(
void * p00_val, uintptr_t p00_tag) {
76 return (p00_tp_glue) { .p00_tag = p00_tag, .p00_val = p00_val, };
80 void * p00_tp_i2p(p00_tp_glue p00_sta) {
81 return p00_sta.p00_val;
85 uintptr_t p00_tp_i2i(p00_tp_glue p00_sta) {
86 return p00_sta.p00_tag;
120 P99_WEAK(p00_tp_tack) _Atomic(uintptr_t)
volatile p00_tp_tack;
123 uintptr_t p00_tp_tick_get(
void) {
124 enum { p00_bits =
sizeof(uintptr_t)*CHAR_BIT/2, };
125 register uintptr_t
const p00_mask = (UINTPTR_MAX >> p00_bits);
128 uintptr_t p00_tack = 0;
130 p00_tack = atomic_fetch_add_explicit(&p00_tp_tack, 1u, memory_order_acq_rel);
131 p00_tack &= p00_mask;
133 *p00_ret = (p00_tack << p00_bits);
139 p00_tp_glue
volatile* p00_tp_glue_init(p00_tp_glue
volatile* el,
void *
p) {
141 *el = (p00_tp_glue)P00_TP_GLUE_INITIALIZER(
p, p00_tp_tick_get());
156 _Atomic(p00_tp_glue)
volatile p00_val;
183 p00_tp_glue p00_next;
187 # define P00_TP_INITIALIZER(VAL) { \
188 .p00_val = ATOMIC_VAR_INIT(0), \
193 bool p00_tp_cmpxchg(_Atomic(p00_tp_glue)
volatile*
const p00_p, p00_tp_glue
volatile*
const p00_prev, p00_tp_glue p00_new) {
195 bool ret = atomic_compare_exchange_weak_explicit(p00_p, p00_prev, p00_new, memory_order_acq_rel, memory_order_consume);
201 p00_tp_glue p00_tp_get(
register p99_tp volatile*
const p00_tp) {
202 register p00_tp_glue p00_ret
204 ? atomic_load_explicit(&p00_tp->p00_val, memory_order_consume)
205 : (p00_tp_glue)P00_TP_GLUE_INITIALIZER((
void*)0, p00_tp_tick_get());
208 p00_tp_glue p00_ter = p00_ret;
209 register p00_tp_glue p00_rep = P00_TP_GLUE_INITIALIZER(p00_tp->p00_init, p00_tp_tick_get());
210 if (p00_tp_cmpxchg(&p00_tp->p00_val, &p00_ter, p00_rep))
222 p00_tp_glue p99_tp_xchg(
p99_tp volatile* p00_tp,
void* p00_val) {
225 ? atomic_load_explicit(&p00_tp->p00_val, memory_order_consume)
226 : (p00_tp_glue)P00_TP_GLUE_INITIALIZER((
void*)0, p00_tp_tick_get());
228 register p00_tp_glue p00_rep = P00_TP_GLUE_INITIALIZER(p00_val, p00_tp_tick_get());
229 while (!p00_tp_cmpxchg(&p00_tp->p00_val, &p00_ret, p00_rep));
233 p00_ret = (p00_tp_glue)P00_TP_GLUE_INITIALIZER(p00_tp->p00_init, p00_tp_tick_get());
244 p99_tp_state p99_tp_state_initializer(
register p99_tp volatile*
const p00_tp,
register void*
const p00_p) {
246 .p00_val = p00_tp_get(p00_tp),
247 .p00_next = P00_TP_GLUE_INITIALIZER(p00_p, p00_tp_tick_get()),
253 void * p99_tp_state_get(
register p99_tp_state volatile*
const p00_state) {
254 return P99_LIKELY(p00_state) ? p00_tp_i2p(p00_state->p00_val) : 0;
258 void * p99_tp_get(
register p99_tp volatile*
const p00_tp) {
259 return p00_tp_i2p(p00_tp_get(p00_tp));
263 void p99_tp_state_set(
register p99_tp_state volatile*
const p00_state,
register void*
const p00_p) {
264 if (
P99_LIKELY(p00_state)) p00_state->p00_next = p00_tp_p2i(p00_p, p00_tp_i2i(p00_state->p00_next));
268 bool p99_tp_state_commit(
register p99_tp_state volatile*
const p00_state) {
270 ? p00_tp_cmpxchg(&p00_state->p00_tp->p00_val, &p00_state->p00_val, p00_state->p00_next)
275 bool p99_tp_state_check(
register p99_tp_state volatile*
const p00_state) {
277 ? p00_tp_cmpxchg(&p00_state->p00_tp->p00_val, &p00_state->p00_val, p00_state->p00_val)
281 # define P99_TP(T) P99_PASTE2(p00_tp_, T)
282 # define P99_TP_STATE(T) P99_PASTE2(p00_tp_glue_, T)
285 # define P99_TP_DECLARE(T) \
286 typedef union P99_TP(T) P99_TP(T); \
287 typedef union P99_TP_STATE(T) P99_TP_STATE(T); \
291 P99_TP_STATE(T)* p00_mud; \
292 max_align_t p00_align; \
294 union P99_TP_STATE(T) { \
295 p99_tp_state p00_st; \
297 P99_TP(T)* p00_mud; \
298 max_align_t p00_align; \
301 # define P99_TP_TYPE(TP) __typeof__(*(TP)->p00_dum)
302 # define P99_TP_TYPE_STATE(TP) __typeof__(*(TP)->p00_mud)
303 # define P99_TP_STATE_TYPE(TPS) __typeof__(*(TPS)->p00_dum)
306 # define P99_TP_INITIALIZER(VAL) { .p00_tp = P00_TP_INITIALIZER(VAL), }
309 void p00_tp_init(
register p99_tp volatile*
const p00_el,
register void*
const p00_val) {
311 memset((
void*)&p00_el->p00_val, 0,
sizeof p00_el->p00_val);
312 atomic_init(&p00_el->p00_val, p00_tp_p2i(p00_val, p00_tp_tick_get()));
316 # define p99_tp_init(EL, VAL) \
318 register __typeof__(EL) const p00_el = (EL); \
319 if (P99_LIKELY(p00_el)) p00_tp_init(&p00_el->p00_tp, (VAL)); \
331 #define P99_TP_STATE_INITIALIZER(TP, P) \
333 P99_MACRO_VAR(p00_tp, (TP)); \
336 register P99_TP_TYPE(p00_tp)* const p00_p = (P); \
337 register P99_TP_TYPE_STATE(p00_tp) const p00_r = { \
340 ? p99_tp_state_initializer(&p00_tp->p00_tp, p00_p) \
341 : (p99_tp_state)P99_INIT, \
350 #define P99_TP_XCHG(TP, VAL) \
352 P99_MACRO_VAR(p00_tp, (TP)); \
355 register P99_TP_TYPE(p00_tp)* const p00_val = (VAL); \
356 register P99_TP_TYPE(p00_tp)* const p00_r \
357 = p00_tp ? p00_tp_i2p(p99_tp_xchg(&p00_tp->p00_tp, p00_val)) : 0; \
364 #define P99_TP_GET(TP) \
366 P99_MACRO_VAR(p00_tp, (TP)); \
369 register P99_TP_TYPE(p00_tp)* const p00_r \
370 = p00_tp ? p99_tp_get(&p00_tp->p00_tp) : 0; \
381 #define P99_TP_STATE_GET(TPS) \
383 P99_MACRO_VAR(p00_tps, (TPS)); \
386 register P99_TP_STATE_TYPE(p00_tps)* const p00_r \
387 = p00_tps ? p99_tp_state_get(&p00_tps->p00_st) : 0; \
396 #define P99_TP_STATE_SET(TPS, P) \
398 P99_MACRO_VAR(p00_tps, (TPS)); \
401 register P99_TP_STATE_TYPE(p00_tps)*const p00_p = (P); \
402 if (p00_tps) p99_tp_state_set(&p00_tps->p00_st, p00_p); \
411 #define P99_TP_STATE_COMMIT(TPS) \
413 P99_MACRO_VAR(p00_tps, (TPS)); \
414 register bool const p00_r \
415 = p00_tps ? p99_tp_state_commit(&p00_tps->p00_st) : false; \
426 #define P99_TP_STATE_CHECK(TPS) \
428 P99_MACRO_VAR(p00_tps, (TPS)); \
429 register bool const p00_r \
430 = p00_tps ? p99_tp_state_check(&(p00_tps)->p00_st) : false; \
435 #define P99_REF_ACCOUNT(REF) \
437 P99_MACRO_VAR(p00_ref, (REF)); \
440 register __typeof__(p00_ref) const p00_r = p00_ref; \
441 if (p00_r) atomic_fetch_add_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel); \
445 #define P99_TP_REF_ACCOUNT(TP, REF) \
447 P99_MACRO_VAR(p00_tp, (TP)); \
450 register P99_TP_TYPE(p00_tp)* const p00_r = (REF); \
451 if (p00_r) atomic_fetch_add_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel); \
455 #define P99_REF_DISCOUNT(REF, DELETE) \
457 P99_MACRO_VAR(p00_ref, (REF)); \
458 register void (*const p00_d)(__typeof__(*p00_ref) const*) \
462 register __typeof__(*p00_ref)*const p00_r = p00_ref; \
463 if (p00_r && (atomic_fetch_sub_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel) == 1)) \
468 #define P99_TP_REF_INITIALIZER(VAL, ACCOUNT) P99_TP_INITIALIZER(P99_GENERIC_NULLPTR_CONSTANT(VAL, (void*)0, ACCOUNT(VAL)))
470 #define P00_TP_REF_INIT2(TP, VAL) \
472 P99_MACRO_VAR(p00_tp, (TP)); \
475 register P99_TP_TYPE(p00_tp)* const p00_val = (VAL); \
476 p99_tp_init(p00_tp, P99_REF_ACCOUNT(p00_val)); \
480 #define P00_TP_REF_INIT1(TP) p99_tp_init(TP, 0)
482 #define P99_TP_REF_INIT(...) \
483 P99_IF_LT(P99_NARG(__VA_ARGS__), 2) \
484 (P00_TP_REF_INIT1(__VA_ARGS__)) \
485 (P00_TP_REF_INIT2(__VA_ARGS__))
487 #define P99_TP_REF_REPLACE(TP, SP, DELETE) \
488 P99_REF_DISCOUNT(P99_TP_XCHG((TP), P99_REF_ACCOUNT(SP)), (DELETE))
490 #define P99_TP_REF_MV(TP, SP, DELETE) \
491 P99_REF_DISCOUNT(P99_TP_XCHG((TP), P99_TP_XCHG((SP), 0)), (DELETE))
493 #define P99_TP_REF_DESTROY(TP, DELETE) \
494 (void)P99_REF_DISCOUNT(P99_TP_XCHG((TP), 0), (DELETE))
533 #define P99_TP_REF_DECLARE(T) \
534 typedef struct T ## _ref T ## _ref; \
542 #define P99_TP_REF_DECLARE(T) \
543 P99_POINTER_TYPE(T); \
544 P99_TP_DECLARE(P99_PASTE2(T, _ptr)); \
546 typedef P99_TP(P99_PASTE2(T, _ptr)) P99_PASTE2(T, _ref)
550 #define P99_TP_REF_DEFINE(T) \
551 P99_INSTANTIATE(T*, P99_PASTE2(T, _account), T*); \
552 P99_INSTANTIATE(T*, P99_PASTE2(T, _discount), T*); \
553 P99_INSTANTIATE(P99_PASTE2(T, _ref)*, P99_PASTE2(T, _ref_init), P99_PASTE2(T, _ref)*, T*); \
554 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_init_defarg_1), void); \
555 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_get), P99_PASTE2(T, _ref) volatile*); \
556 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_replace), P99_PASTE2(T, _ref) volatile*, T*); \
557 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_mv), P99_PASTE2(T, _ref) volatile*, \
558 P99_PASTE2(T, _ref) volatile*); \
559 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_assign), P99_PASTE2(T, _ref) volatile*, \
560 P99_PASTE2(T, _ref) volatile*); \
561 P99_INSTANTIATE(void, P99_PASTE2(T, _ref_destroy), P99_PASTE2(T, _ref)*)
565 #define P99_TP_REF_FUNCTIONS(T) \
568 inline T* P99_PASTE2(T, _account)(T*){} \
572 inline T* P99_PASTE2(T, _discount)(T*){} \
576 inline P99_PASTE2(T, _ref)* P99_PASTE2(T, _ref_init)(P99_PASTE2(T, _ref)*, T*){} \
580 inline T* P99_PASTE2(T, _ref_init_defarg_1)(void){} \
584 inline T* P99_PASTE2(T, _ref_get)(P99_PASTE2(T, _ref) volatile*){} \
588 inline T* P99_PASTE2(T, _ref_replace)(P99_PASTE2(T, _ref) volatile*, T*){} \
593 inline T* P99_PASTE2(T, _ref_mv)(P99_PASTE2(T, _ref) volatile*, \
594 P99_PASTE2(T, _ref) volatile*){} \
599 inline T* P99_PASTE2(T, _ref_assign)(P99_PASTE2(T, _ref) volatile*, \
600 P99_PASTE2(T, _ref) volatile*){} \
604 inline void P99_PASTE2(T, _ref_destroy)(P99_PASTE2(T, _ref)*) {} \
605 P99_MACRO_END(P99_TP_REF_FUNCTIONS)
609 #define P99_TP_REF_FUNCTIONS(T) \
613 P99_PASTE2(T, _account)(T* p00_el) { \
614 return P99_REF_ACCOUNT(p00_el); \
619 P99_PASTE2(T, _discount)(T* p00_el) { \
620 return P99_REF_DISCOUNT(p00_el, P99_PASTE2(T, _delete)); \
624 P99_PASTE2(T, _ref)* P99_PASTE2(T, _ref_init)(P99_PASTE2(T, _ref)* el, T* p00_v) { \
625 return P99_TP_REF_INIT(el, p00_v); \
629 T* P99_PASTE2(T, _ref_init_defarg_1)(void) { \
634 T* P99_PASTE2(T, _ref_get)(P99_PASTE2(T, _ref) volatile* p00_ref) { \
635 return P99_TP_GET(p00_ref); \
639 T* P99_PASTE2(T, _ref_replace)(P99_PASTE2(T, _ref) volatile* p00_tar, T* p00_sou) { \
640 return P99_TP_REF_REPLACE(p00_tar, p00_sou, P99_PASTE2(T, _delete)); \
644 T* P99_PASTE2(T, _ref_mv)(P99_PASTE2(T, _ref) volatile* p00_tar, \
645 P99_PASTE2(T, _ref) volatile* p00_sou) { \
646 return P99_TP_REF_MV(p00_tar, p00_sou, P99_PASTE2(T, _delete)); \
650 T* P99_PASTE2(T, _ref_assign)(P99_PASTE2(T, _ref) volatile* p00_tar, \
651 P99_PASTE2(T, _ref) volatile* p00_sou) { \
652 return P99_TP_REF_REPLACE(p00_tar, P99_TP_GET(p00_sou), P99_PASTE2(T, _delete)); \
656 void P99_PASTE2(T, _ref_destroy)(P99_PASTE2(T, _ref)* p00_ref) { \
657 P99_TP_REF_DESTROY(p00_ref, P99_PASTE2(T, _delete)); \
660 P99_MACRO_END(P99_TP_REF_FUNCTIONS)