/* * 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 #include #include // 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 _s` starts with structure `struct _s ;` 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();` // 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(, // );`. 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(, );` in the .c file of the object. // 5. Define a structure with name of `struct __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 NULL 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 * ref_count_obj_alloc()(). * * @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 ref_count_obj_any_t 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 ref_count_obj_any_t 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 ref_count_obj_any_t union. * * @param ref_count_object2 * The supported reference counted object contained in ref_count_obj_any_t 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 * compare_result_less if ref_count_object1 is less than ref_count_object2. * compare_result_equal if ref_count_object1 is equal to ref_count_object2. * compare_result_greater if ref_count_object1 is greater than ref_count_object2. * compare_result_notequal if two objects can be compared and they are not equal, but the specific order of the two objects cannot be determined. * compare_result_unknown 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 * compare_result_unknown. */ 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 * sort_order_ascending for the ascending order. * sort_order_descending 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