blob: 511a463eaf33a3f90c127e03339cdd74f1993fea [file] [edit]
/*
* 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);
}