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