/* * Copyright (c) 2021 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. */ #include "ref_count.h" #include "dns_assert_macros.h" #include "mdns_strict.h" //====================================================================================================================== // MARK: - Object Kind Definition const struct ref_count_kind_s ref_count_kind = { .superkind = NULL, .name = "ref_count_obj", .init = NULL, .compare = NULL, .finalize = NULL }; //====================================================================================================================== // MARK: - Object Public Methods ref_count_obj_t ref_count_obj_alloc(const size_t size) { return mdns_calloc(1, size); } //====================================================================================================================== void ref_count_obj_init(const ref_count_obj_t me, const ref_count_kind_t new_kind) { me->kind = new_kind; for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) { if (kind->init != NULL) { kind->init(me); } } } //====================================================================================================================== ref_count_obj_t ref_count_obj_retain(const ref_count_obj_t me) { me->ref_count++; return me; } //====================================================================================================================== static void _ref_count_obj_finalize(const ref_count_obj_t me); void ref_count_obj_release(const ref_count_obj_t me) { me->ref_count--; if (me->ref_count == 0) { _ref_count_obj_finalize(me); } } //====================================================================================================================== compare_result_t ref_count_obj_compare(const ref_count_obj_t me, const ref_count_obj_t other, const bool check_equality_only) { if (me == other) { return compare_result_equal; } if (me->kind != other->kind) { if (check_equality_only) { // Two objects that do not have the same kind is not equal. return compare_result_notequal; } else { // There is no way to know the exact order of two different kinds of objects. return compare_result_unknown; } } compare_result_t result = compare_result_unknown; for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) { if (kind->compare != NULL) { result = kind->compare(me, other, check_equality_only); // If the specified comparator returns COMPARE_RESULT_UNKNOWN, it means that the current comparator of the // kind can not determine the compare result. Therefore, we continue to the super kind trying to compare // the two objects. if (result != compare_result_unknown) { break; } } } return result; } //====================================================================================================================== static inline bool _continue_searching(const sort_order_t order, const compare_result_t compare_result) { bool continue_searching; if (order == sort_order_ascending) { if (compare_result == compare_result_less) { continue_searching = true; } else { continue_searching = false; } } else { if (compare_result == compare_result_greater) { continue_searching = true; } else { continue_searching = false; } } return continue_searching; } void ref_count_objs_sort(ref_count_obj_t * const us, const size_t count, const sort_order_t order) { // Insertion sort. // Reason: Usually, the number of the reference counted objects to be sorted will be a small number, and the array // will almost be in order. Therefore, insertion sort is a reasonable choice. if (count <= 1) { return; } for (size_t i = 0; i < count - 1; i++) { size_t j = i + 1; const ref_count_obj_t me_to_insert = us[j]; compare_result_t compare_result = ref_count_obj_compare(me_to_insert, us[j - 1], false); bool continue_searching = _continue_searching(order, compare_result); while (continue_searching) { us[j] = us[j - 1]; j--; if (j == 0) { break; } compare_result = ref_count_obj_compare(me_to_insert, us[j - 1], false); continue_searching = _continue_searching(order, compare_result); } us[j] = me_to_insert; } } //====================================================================================================================== // MARK: - Object Private Methods static void _ref_count_obj_finalize(const ref_count_obj_t me) { // Release the resource allocated for the specific kind. for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) { if (kind->finalize != NULL) { kind->finalize(me); } } // Release the memory associated with the object itself. ref_count_obj_t me_to_deallocate = me; mdns_free(me_to_deallocate); }