blob: 9099633ebd8ed5d26fe893b752c90113e9fe09e6 [file] [log] [blame] [edit]
/*
* Copyright (c) 2021-2023 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef REF_COUNT_H
#define REF_COUNT_H
//======================================================================================================================
// MARK: - Headers
//#include "dnssec_common.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h> // For offsetof().
#include "general.h"
#include "nullability.h"
#include "dns_assert_macros.h"
//======================================================================================================================
// MARK: - General Object Helpers
#define OBJECT_TYPEDEF_OPAQUE_POINTER(NAME) typedef struct NAME ## _s * NAME ## _t
// Check if structure `struct <NAME>_s` starts with structure `struct <BASE_NAME>_s <BASE_NAME>;` as the first member.
#define OBJECT_BASE_CHECK(NAME, BASE_NAME) \
check_compile_time(offsetof(struct NAME ## _s, base) == 0); \
check_compile_time(sizeof(((struct NAME ## _s *)0)->base) == sizeof(struct BASE_NAME ## _s)); \
extern int8_t _obj_base_type_check[sizeof(&(((NAME ## _t)0)->base) == ((BASE_NAME ## _t)0))] \
#ifndef STRUCT_PTR_DECLARE
#define STRUCT_PTR_DECLARE(STRUCT_NAME) struct STRUCT_NAME ## _s * NULLABLE STRUCT_NAME
#endif
#ifndef STRUCT_ARRAY_PTR_DECLARE
#define STRUCT_ARRAY_PTR_DECLARE(STRUCT_NAME) struct STRUCT_NAME ## _s * NULLABLE * NULLABLE STRUCT_NAME ## s
#endif
typedef enum {
compare_result_less = -1,
compare_result_equal = 0,
compare_result_greater = 1,
compare_result_notequal, // Can ensure that the objects being compared are not equal. Do not know about the exact order.
compare_result_unknown, // Unable to determine the comparison result.
} compare_result_t;
typedef enum {
sort_order_ascending,
sort_order_descending
} sort_order_t;
//======================================================================================================================
// MARK: - Reference Count Object Helper Macros
// The macros below provide a way to define a reference counted object that comes with comparator and finalizer.
// To define a new reference counted object:
// 1. In the definition of the `ref_count_obj_any_t`, add `REF_COUNT_OBJECT_DECLARE_SUPPORTED_FAMILY(<object family name>);`
// to declare that the object family supports reference count and all the methods provided by `ref_count.h` can be
// used by the object family.
// 2. Create a header/source file for the object family, define the retain method, release method and compare method for
// the object family. This step ensures that all the objects under the same family can be retained, released and
// compared, without having to call the underlying ref_count object base. This provides an additional layer of type
// check.
// 3. In the definition of the `ref_count_obj_any_t`, add `REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(<object family name>,
// <object type name>);`. This step ensures that this new reference counted object supports the comparator and the
// finalizer defined by `ref_count.h`.
// 4. Put `REF_COUNT_OBJECT_DEFINE_FULL(<object family name>, <object type name>);` in the .c file of the object.
// 5. Define a structure with name of `struct <object family name>_<object type name>_s` in the .c file of the object.
// The structure should start with `struct ref_count_obj_s base;` so that it can have reference count and object
// property.
// 6. Implement the comparator and the finalizer in the .c file of the object.
//
// Note: If an object family has been defined previously, start from step 3.
// Declare a initializer for the reference counted object.
#define REF_COUNT_OBJECT_DECLARE_INITIALIZER(FAMILY_NAME, NAME) \
static void \
_ ## FAMILY_NAME ## _ ## NAME ## _initialize(FAMILY_NAME ## _ ## NAME ## _t NONNULL object)
//======================================================================================================================
// Declare a comparator for the reference counted object.
#define REF_COUNT_OBJECT_DECLARE_COMPARATOR(FAMILY_NAME, NAME) \
static compare_result_t \
_ ## FAMILY_NAME ## _ ## NAME ## _compare(FAMILY_NAME ## _ ## NAME ## _t NONNULL object1, \
FAMILY_NAME ## _ ## NAME ## _t NONNULL object2, \
bool check_equality_only)
//======================================================================================================================
// Declare a finalizer for the reference counted object.
#define REF_COUNT_OBJECT_DECLARE_FINALIZER(FAMILY_NAME, NAME) \
static void \
_ ## FAMILY_NAME ## _ ## NAME ## _finalize(FAMILY_NAME ## _ ## NAME ## _t NONNULL object)
//======================================================================================================================
// Define a New() function for the reference count object to allocate the memory and initialize the memory.
#define REF_COUNT_OBJECT_DEFINE_NEW_FUNC(FAMILY_NAME, NAME) \
static FAMILY_NAME ## _ ## NAME ## _t \
_ ## FAMILY_NAME ## _ ## NAME ## _new(void) \
{ \
const FAMILY_NAME ## _ ## NAME ## _t obj = (FAMILY_NAME ## _ ## NAME ## _t)ref_count_obj_alloc(sizeof(*obj));\
if (obj == NULL) { \
return NULL; \
} \
\
ref_count_obj_init(obj, &_ ## FAMILY_NAME ## _ ## NAME ## _kind); \
ref_count_obj_retain(obj); \
return obj; \
} \
extern int8_t _dummy_variable_to_enforce_semicolon
//======================================================================================================================
// Define the kind instance of the reference count object.
#define REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE_BASIC(FAMILY_NAME, NAME, ...) \
const struct ref_count_kind_s _ ## FAMILY_NAME ## _ ## NAME ## _kind = { \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN() \
.superkind = &ref_count_kind, \
.name = # FAMILY_NAME "_" # NAME, \
.finalize = _ ## FAMILY_NAME ## _ ## NAME ## _finalize, \
__VA_ARGS__ \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END() \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## NAME, ref_count_obj)
#define REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE(FAMILY_NAME, NAME) \
REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE_BASIC(FAMILY_NAME, NAME, \
.compare = _ ## FAMILY_NAME ## _ ## NAME ## _compare, \
)
#define REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE_WITH_INIT(FAMILY_NAME, NAME) \
REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE_BASIC(FAMILY_NAME, NAME, \
.init = _ ## FAMILY_NAME ## _ ## NAME ## _initialize \
)
//======================================================================================================================
// Define a reference count enabled object.
#define REF_COUNT_OBJECT_DEFINE_FULL(FAMILY_NAME, NAME) \
REF_COUNT_OBJECT_DECLARE_COMPARATOR(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DECLARE_FINALIZER(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DEFINE_NEW_FUNC(FAMILY_NAME, NAME)
#define REF_COUNT_OBJECT_DEFINE_WITH_INIT_WITHOUT_COMPARATOR(FAMILY_NAME, NAME) \
REF_COUNT_OBJECT_DECLARE_INITIALIZER(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DECLARE_FINALIZER(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DEFINE_KIND_INSTANCE_WITH_INIT(FAMILY_NAME, NAME); \
REF_COUNT_OBJECT_DEFINE_NEW_FUNC(FAMILY_NAME, NAME)
//======================================================================================================================
// MARK: - Subkind of Reference Counted Object Helper Macros
// The macros below provide a way to define an object that is a subkind of the reference count object that is defined by
// the macros above.
// Define a new kind type for the reference count object so that its subkind can reference it. `...` are the additional
// members needed for the kind type.
// This is the way how the subkind know what super kind it has.
#define REF_COUNT_OBJECT_DEFINE_KIND_TYPE_FOR_SUBKIND(FAMILY_NAME, NAME, ...) \
typedef const struct FAMILY_NAME ## _ ## NAME ## _kind_s * FAMILY_NAME ## _ ## NAME ## _kind_t; \
struct FAMILY_NAME ## _ ## NAME ## _kind_s { \
struct ref_count_kind_s base; \
FAMILY_NAME ## _ ## NAME ## _init_fields_f NONNULL FAMILY_NAME ## _ ## NAME ## _init_fields; \
__VA_ARGS__ \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## NAME ## _kind, ref_count_kind); \
extern const struct ref_count_kind_s _ ## FAMILY_NAME ## _ ## NAME ## _kind
//======================================================================================================================
// Define the kind instance for the subkind of the reference count object. The reference count object has to exist
// before its subkind can be defined. There are four variations of the helper:
// 1. REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_ABSTRUCT: the subkind does not need to implement comparator and finalizer.
// 2. REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_FINALIZER: the subkind does not need to implement finalizer,
// but it needs to implement comparator.
// 3. REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_COMPARATOR: the subkind does not need to implement
// comparator, but it needs to implement finalizer.
// 4. REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_FULL: the subkind needs to implement both comparator and finalizer.
//
// No comparator subkind use case: it means that the super kind of the subkind already has a comparator and no more
// specific comparator needed.
// No finalizer subkind use case: it means that the subkind does not allocate new memory for its new member when doing
// member initialization. Therefore, there is no need for such subkind to define a finalizer that does nothing.
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_ABSTRUCT(FAMILY_NAME, SUPER, NAME, ...) \
const struct FAMILY_NAME ## _ ## SUPER ## _kind_s _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _kind = { \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN() \
.base = { \
.superkind = &_ ## FAMILY_NAME ## _ ## SUPER ## _kind, \
.name = # FAMILY_NAME "_" # SUPER "_" # NAME, \
}, \
.FAMILY_NAME ## _ ## SUPER ## _init_fields = FAMILY_NAME ## _ ## SUPER ## _init_fields, \
__VA_ARGS__ \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END() \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## SUPER ## _ ## NAME, FAMILY_NAME ## _ ## SUPER)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_FINALIZER(FAMILY_NAME, SUPER, NAME, ...) \
const struct FAMILY_NAME ## _ ## SUPER ## _kind_s _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _kind = { \
.base = { \
.superkind = &_ ## FAMILY_NAME ## _ ## SUPER ## _kind, \
.name = # FAMILY_NAME "_" # SUPER "_" # NAME, \
.compare = _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _compare, \
}, \
.FAMILY_NAME ## _ ## SUPER ## _init_fields = FAMILY_NAME ## _ ## SUPER ## _init_fields, \
__VA_ARGS__ \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## SUPER ## _ ## NAME, FAMILY_NAME ## _ ## SUPER)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_COMPARATOR(FAMILY_NAME, SUPER, NAME, ...) \
const struct FAMILY_NAME ## _ ## SUPER ## _kind_s _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _kind = { \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN() \
.base = { \
.superkind = &_ ## FAMILY_NAME ## _ ## SUPER ## _kind, \
.name = # FAMILY_NAME "_" # SUPER "_" # NAME, \
.finalize = _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _finalize \
}, \
.FAMILY_NAME ## _ ## SUPER ## _init_fields = FAMILY_NAME ## _ ## SUPER ## _init_fields, \
__VA_ARGS__ \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END() \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## SUPER ## _ ## NAME, FAMILY_NAME ## _ ## SUPER)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_FULL(FAMILY_NAME, SUPER, NAME, ...) \
const struct FAMILY_NAME ## _ ## SUPER ## _kind_s _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _kind = { \
.base = { \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_BEGIN() \
.superkind = &_ ## FAMILY_NAME ## _ ## SUPER ## _kind, \
.name = # FAMILY_NAME "_" # SUPER "_" # NAME, \
.compare = _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _compare, \
.finalize = _ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _finalize \
MDNS_CLANG_IGNORE_INCOMPATIBLE_FUNCTION_POINTER_TYPES_STRICT_WARNING_END() \
}, \
.FAMILY_NAME ## _ ## SUPER ## _init_fields = FAMILY_NAME ## _ ## SUPER ## _init_fields, \
__VA_ARGS__ \
}; \
OBJECT_BASE_CHECK(FAMILY_NAME ## _ ## SUPER ## _ ## NAME, FAMILY_NAME ## _ ## SUPER)
//======================================================================================================================
// Define a New() function for the subkind of reference count object to allocate the memory and initialize the memory.
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_NEW_FUNC(FAMILY_NAME, SUPER, NAME) \
static FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _t \
_ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _new(void) \
{ \
const FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _t obj = (FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _t)ref_count_obj_alloc(sizeof(*obj));\
if (obj == NULL) { \
return NULL; \
} \
\
ref_count_obj_init(obj, &_ ## FAMILY_NAME ## _ ## SUPER ## _ ## NAME ## _kind.base); \
ref_count_obj_retain(obj); \
return obj; \
} \
extern int8_t _dummy_variable_to_enforce_semicolon
//======================================================================================================================
// Define a subkind object of the reference counted object, based on whether the subkind needs the comparator and
// the finalizer. `...` are the additional member that the kind type of reference counted object needs to initialize
// for this subkind.
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_FULL(FAMILY_NAME, SUPER, NAME, ...) \
REF_COUNT_OBJECT_DECLARE_COMPARATOR(FAMILY_NAME, SUPER ## _ ## NAME); \
REF_COUNT_OBJECT_DECLARE_FINALIZER(FAMILY_NAME, SUPER ## _ ## NAME); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_FULL(FAMILY_NAME, SUPER, NAME, __VA_ARGS__); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_NEW_FUNC(FAMILY_NAME, SUPER, NAME)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_WITHOUT_COMPARATOR(FAMILY_NAME, SUPER, NAME, ...) \
REF_COUNT_OBJECT_DECLARE_FINALIZER(FAMILY_NAME, SUPER ## _ ## NAME); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_COMPARATOR(FAMILY_NAME, SUPER, NAME, __VA_ARGS__); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_NEW_FUNC(FAMILY_NAME, SUPER, NAME)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_WITHOUT_FINALIZER(FAMILY_NAME, SUPER, NAME, ...) \
REF_COUNT_OBJECT_DECLARE_COMPARATOR(FAMILY_NAME, SUPER ## _ ## NAME); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_WITHOUT_FINALIZER(FAMILY_NAME, SUPER, NAME, __VA_ARGS__); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_NEW_FUNC(FAMILY_NAME, SUPER, NAME)
#define REF_COUNT_OBJECT_SUBKIND_DEFINE_ABSTRUCT(FAMILY_NAME, SUPER, NAME, ...) \
REF_COUNT_OBJECT_SUBKIND_DEFINE_KIND_INSTANCE_ABSTRUCT(FAMILY_NAME, SUPER, NAME, __VA_ARGS__); \
REF_COUNT_OBJECT_SUBKIND_DEFINE_NEW_FUNC(FAMILY_NAME, SUPER, NAME)
//======================================================================================================================
// MARK: - Reference Counted Object Declaration
#define REF_COUNT_OBJECT_DECLARE_SUPPORTED_FAMILY(FAMILY_NAME) STRUCT_PTR_DECLARE(FAMILY_NAME)
#define REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(FAMILY_NAME, NAME) STRUCT_PTR_DECLARE(FAMILY_NAME ## _ ## NAME)
#define REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(FAMILY_NAME, SUPER, NAME) REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(FAMILY_NAME, SUPER ## _ ## NAME)
#define REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_FAMILY(FAMILY_NAME) STRUCT_ARRAY_PTR_DECLARE(FAMILY_NAME)
#define REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(FAMILY_NAME, NAME) STRUCT_ARRAY_PTR_DECLARE(FAMILY_NAME ## _ ## NAME)
#define REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(FAMILY_NAME, SUPER, NAME) REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(FAMILY_NAME, SUPER ## _ ## NAME)
typedef union {
// The universal reference count enabled object.
STRUCT_PTR_DECLARE(ref_count_obj);
// -------- The DNS Object families --------
REF_COUNT_OBJECT_DECLARE_SUPPORTED_FAMILY(dns_obj);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_obj, domain_name);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_obj, rr);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, cname); // CNAME RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, soa); // SOA RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, srv); // SRV RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, nsec); // NSEC RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, ds); // DS RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, rrsig); // RRSIG RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, dnskey); // DNSKEY RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dns_obj, rr, nsec3); // NSEC3 RR
// -------- The DNSSEC Object families --------
REF_COUNT_OBJECT_DECLARE_SUPPORTED_FAMILY(dnssec_obj);
// The validation task manager object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, validation_manager);
// The callback context object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, context);
// The trust anchor object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, trust_anchor);
// The trust anchor manager object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, trust_anchor_manager);
// The domain name object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, domain_name);
// The resource record set object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, rrset);
// The resource record validator object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, rr_validator);
// The denial of existence object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, denial_of_existence);
// The resource record and its subkind object in the DNSSEC Object families.
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, rr);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, cname); // CNAME RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, soa); // SOA RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, srv); // SRV RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, nsec); // NSEC RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, ds); // DS RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, rrsig); // RRSIG RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, dnskey); // DNSKEY RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, nsec3); // NSEC3 RR
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, resource_record_member);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dnssec_obj, dns_question_member);
// -------- The DNS Push Object families --------
REF_COUNT_OBJECT_DECLARE_SUPPORTED_FAMILY(dns_push_obj);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_push_obj, context);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_push_obj, discovered_service_manager);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_push_obj, dns_question_member);
REF_COUNT_OBJECT_DECLARE_SUPPORTED_OBJECT(dns_push_obj, resource_record_member);
} ref_count_obj_any_t __attribute__((__transparent_union__));
typedef union {
// The universal reference count enabled objects array.
STRUCT_ARRAY_PTR_DECLARE(ref_count_obj);
// -------- The DNSSEC Object array families --------
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_FAMILY(dnssec_obj);
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(dnssec_obj, domain_name); // domain names array
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(dnssec_obj, rr); // RRs array
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, nsec); // NSEC RRs array
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, dnskey); // DNSKEY RRs array
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT_SUBKIND(dnssec_obj, rr, nsec3); // NSEC3 RRs array
// -------- The DNS Object families --------
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_FAMILY(dns_obj);
REF_COUNT_OBJECT_ARRAY_DECLARE_SUPPORTED_OBJECT(dns_obj, domain_name); // domain names array
} ref_count_objs_any_t __attribute__((__transparent_union__));
//======================================================================================================================
// MARK: - The Reference Count Structure Base
typedef void
(*ref_count_init_f)(ref_count_obj_any_t object);
typedef compare_result_t
(*ref_count_compare_f)(ref_count_obj_any_t object1, ref_count_obj_any_t object2, bool check_equality_only);
typedef void
(*ref_count_finalize_f)(ref_count_obj_any_t object);
typedef const struct ref_count_kind_s *ref_count_kind_t;
struct ref_count_kind_s {
ref_count_kind_t NULLABLE superkind; // Points to the kind instance of the super kind.
const char * NONNULL name; // The name of the current kind. Just for information purpose.
ref_count_init_f NULLABLE init; // The memory initialization method, most of time it will be NULL.
ref_count_compare_f NULLABLE compare; // The comparator of the kind.
ref_count_finalize_f NULLABLE finalize; // The finalizer of the kind.
};
// Note the difference between memory initialization and member(field) initialization, memory initialization will
// initialize the allocated memory to a default value, for example, zero. However, member(field) initialization will
// initialize the specific object's member to a meaningful value. Most of time, memory initialization is unnecessary
// since we are using calloc() to reset the allocated memory to zero, the memory initialization has been finished and no
// need to explicitly define an initializer. However, under some cases where zero is a meaningful value, for example,
// socket value 0. We have to explicitly define the memory initialization method so that the member can be set to an
// invalid value, such as -1 for socket. We need the member to have a INVALID value because the finalizer needs to know
// if it needs to do some clean up. If the member has an INVALID value, the finalizer does not need to free any resource
// possibly related to it. This allow us to release the object immediately after allocating memory for it, even before
// initializing its member. (the member initialization).
extern const struct ref_count_kind_s ref_count_kind; // ref_count_kind is defined in ref_count.c
typedef struct ref_count_obj_s * ref_count_obj_t;
struct ref_count_obj_s {
uint32_t ref_count;
ref_count_kind_t NONNULL kind;
};
//======================================================================================================================
// MARK: - Object Methods
/*!
* @brief
* Allocate the memory for the reference counted object.
*
* @param size
* The size of the object to be allocated.
*
* @result
* The memory allocated for the object, or <code>NULL</code> if the memory allocation fails.
*/
ref_count_obj_t NULLABLE
ref_count_obj_alloc(size_t size);
/*!
* @brief
* Set the object's kind and do memory initialization. Under most of cases, memory initialization will not be performed. (zero initialization is already finished by
* <code>ref_count_obj_alloc()(</code>).
*
* @param ref_count_object
* The newly allocated reference counted object.
*
* @param new_kind
* The kind of this newly allocated reference counted object.
*
* @discussion
* Any newly allocated object has to call this function to set its kind.
*/
void
ref_count_obj_init(ref_count_obj_any_t ref_count_object, ref_count_kind_t NONNULL new_kind);
/*!
* @brief
* Retain a reference counted object by increasing the reference count by one.
*
* @param ref_count_object
* The supported reference counted object contained in <code>ref_count_obj_any_t</code> union.
*
* @result
* The retained reference counted object.
*/
ref_count_obj_t NONNULL
ref_count_obj_retain(ref_count_obj_any_t ref_count_object);
/*!
* @brief
* Release a reference counted object by increasing the reference count by one. If the reference count becomes zero after releasing, the object will be
* finalized.
*
* @param ref_count_object
* The supported reference counted object contained in <code>ref_count_obj_any_t</code> union.
*/
void
ref_count_obj_release(ref_count_obj_any_t ref_count_object);
/*!
* @brief
* Compare two reference counted objects, based on the definition of the comparator of the object.
*
* @param ref_count_object1
* The supported reference counted object contained in <code>ref_count_obj_any_t</code> union.
*
* @param ref_count_object2
* The supported reference counted object contained in <code>ref_count_obj_any_t</code> union.
*
* @param check_equality_only
* Indicate whether the caller only wants to know if the two objects are equal or not. The comparison will be faster when it is true.
*
* @result
* <code>compare_result_less</code> if <code>ref_count_object1</code> is less than <code>ref_count_object2</code>.
* <code>compare_result_equal</code> if <code>ref_count_object1</code> is equal to <code>ref_count_object2</code>.
* <code>compare_result_greater</code> if <code>ref_count_object1</code> is greater than <code>ref_count_object2</code>.
* <code>compare_result_notequal</code> if two objects can be compared and they are not equal, but the specific order of the two objects cannot be determined.
* <code>compare_result_unknown</code> if two objects have different kind or no any comparator available to determine the comparison result, or any unexpected
* cases defined by the comparator.
*
* @discussion
* If the kind of the two objects has no comparator defined, the comparator of the super kind will be used to determine their equality. Such process will
* continue until one available comparator is found or the root kind (NULL) is reached. If no comparator is available for the current kind, the result will be
* <code>compare_result_unknown</code>.
*/
compare_result_t
ref_count_obj_compare(ref_count_obj_any_t ref_count_object1, ref_count_obj_any_t ref_count_object2, bool check_equality_only);
/*!
* @brief
* Sort the reference counted objects array by the ascending or descending order.
*
* @param ref_count_objects
* The reference counted object array to be sorted.
*
* @param count
* The number of objects in the array.
*
* @param order
* The order of the sorted array, it can be
* <code>sort_order_ascending</code> for the ascending order.
* <code>sort_order_descending</code> for the descending order.
*
* @discussion
* The object has to have a comparator that can determine the specific order of the two objects that have the same kind, in order to be sortable. If no
* comparator is available or the comparator can only determine the equality of the objects, the array will be returned untouched.
*/
void
ref_count_objs_sort(ref_count_objs_any_t ref_count_objects, size_t count, sort_order_t order);
#endif // REF_COUNT_H