Home | History | Annotate | Line # | Download | only in base
      1 /*
      2  * Copyright (c) 2021 Apple Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     https://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ref_count.h"
     18 
     19 #include "dns_assert_macros.h"
     20 #include "mdns_strict.h"
     21 
     22 //======================================================================================================================
     23 // MARK: - Object Kind Definition
     24 
     25 const struct ref_count_kind_s ref_count_kind = {
     26 	.superkind		= NULL,
     27 	.name			= "ref_count_obj",
     28 	.init			= NULL,
     29 	.compare		= NULL,
     30 	.finalize		= NULL
     31 };
     32 
     33 //======================================================================================================================
     34 // MARK: - Object Public Methods
     35 
     36 ref_count_obj_t
     37 ref_count_obj_alloc(const size_t size)
     38 {
     39 	return mdns_calloc(1, size);
     40 }
     41 
     42 //======================================================================================================================
     43 
     44 void
     45 ref_count_obj_init(const ref_count_obj_t me, const ref_count_kind_t new_kind)
     46 {
     47 	me->kind = new_kind;
     48 	for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) {
     49 		if (kind->init != NULL) {
     50 			kind->init(me);
     51 		}
     52 	}
     53 }
     54 
     55 //======================================================================================================================
     56 
     57 ref_count_obj_t
     58 ref_count_obj_retain(const ref_count_obj_t me)
     59 {
     60 	me->ref_count++;
     61 	return me;
     62 }
     63 
     64 //======================================================================================================================
     65 
     66 static void
     67 _ref_count_obj_finalize(const ref_count_obj_t me);
     68 
     69 void
     70 ref_count_obj_release(const ref_count_obj_t me)
     71 {
     72 	me->ref_count--;
     73 	if (me->ref_count == 0) {
     74 		_ref_count_obj_finalize(me);
     75 	}
     76 }
     77 
     78 //======================================================================================================================
     79 
     80 compare_result_t
     81 ref_count_obj_compare(const ref_count_obj_t me, const ref_count_obj_t other, const bool check_equality_only)
     82 {
     83 	if (me == other) {
     84 		return compare_result_equal;
     85 	}
     86 
     87 	if (me->kind != other->kind) {
     88 		if (check_equality_only) {
     89 			// Two objects that do not have the same kind is not equal.
     90 			return compare_result_notequal;
     91 		} else {
     92 			// There is no way to know the exact order of two different kinds of objects.
     93 			return compare_result_unknown;
     94 		}
     95 	}
     96 
     97 	compare_result_t result = compare_result_unknown;
     98 	for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) {
     99 		if (kind->compare != NULL) {
    100 			result = kind->compare(me, other, check_equality_only);
    101 			// If the specified comparator returns COMPARE_RESULT_UNKNOWN, it means that the current comparator of the
    102 			// kind can not determine the compare result. Therefore, we continue to the super kind trying to compare
    103 			// the two objects.
    104 			if (result != compare_result_unknown) {
    105 				break;
    106 			}
    107 		}
    108 	}
    109 
    110 	return result;
    111 }
    112 
    113 //======================================================================================================================
    114 
    115 static inline bool
    116 _continue_searching(const sort_order_t order, const compare_result_t compare_result)
    117 {
    118 	bool continue_searching;
    119 
    120 	if (order == sort_order_ascending) {
    121 		if (compare_result == compare_result_less) {
    122 			continue_searching = true;
    123 		} else {
    124 			continue_searching = false;
    125 		}
    126 	} else {
    127 		if (compare_result == compare_result_greater) {
    128 			continue_searching = true;
    129 		} else {
    130 			continue_searching = false;
    131 		}
    132 	}
    133 	return continue_searching;
    134 }
    135 
    136 void
    137 ref_count_objs_sort(ref_count_obj_t * const us, const size_t count, const sort_order_t order)
    138 {
    139 	// Insertion sort.
    140 	// Reason: Usually, the number of the reference counted objects to be sorted will be a small number, and the array
    141 	// will almost be in order. Therefore, insertion sort is a reasonable choice.
    142 
    143 	if (count <= 1) {
    144 		return;
    145 	}
    146 
    147 	for (size_t i = 0; i < count - 1; i++) {
    148 		size_t j = i + 1;
    149 		const ref_count_obj_t me_to_insert = us[j];
    150 
    151 		compare_result_t compare_result = ref_count_obj_compare(me_to_insert, us[j - 1], false);
    152 		bool continue_searching = _continue_searching(order, compare_result);
    153 
    154 		while (continue_searching) {
    155 			us[j] = us[j - 1];
    156 			j--;
    157 			if (j == 0) {
    158 				break;
    159 			}
    160 			compare_result = ref_count_obj_compare(me_to_insert, us[j - 1], false);
    161 			continue_searching = _continue_searching(order, compare_result);
    162 		}
    163 
    164 		us[j] = me_to_insert;
    165 	}
    166 }
    167 
    168 //======================================================================================================================
    169 // MARK: - Object Private Methods
    170 
    171 static void
    172 _ref_count_obj_finalize(const ref_count_obj_t me)
    173 {
    174 	// Release the resource allocated for the specific kind.
    175 	for (ref_count_kind_t kind = me->kind; kind != NULL; kind = kind->superkind) {
    176 		if (kind->finalize != NULL) {
    177 			kind->finalize(me);
    178 		}
    179 	}
    180 
    181 	// Release the memory associated with the object itself.
    182 	ref_count_obj_t me_to_deallocate = me;
    183 	mdns_free(me_to_deallocate);
    184 }
    185