Mercurial > foo_out_sdl
comparison foosdk/sdk/pfc/sort.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "pfc-lite.h" | |
| 2 #include "sort.h" | |
| 3 #include "sort2.h" | |
| 4 #include "bit_array_impl.h" | |
| 5 #include "ref_counter.h" | |
| 6 | |
| 7 #if defined(_M_IX86) || defined(_M_IX64) | |
| 8 #include <intrin.h> | |
| 9 #define PFC_HAVE_RDTSC | |
| 10 #endif | |
| 11 | |
| 12 namespace pfc { | |
| 13 | |
| 14 void swap_void(void * item1,void * item2,t_size width) | |
| 15 { | |
| 16 unsigned char * ptr1 = (unsigned char*)item1, * ptr2 = (unsigned char*)item2; | |
| 17 t_size n; | |
| 18 unsigned char temp; | |
| 19 for(n=0;n<width;n++) | |
| 20 { | |
| 21 temp = *ptr2; | |
| 22 *ptr2 = *ptr1; | |
| 23 *ptr1 = temp; | |
| 24 ptr1++; | |
| 25 ptr2++; | |
| 26 } | |
| 27 } | |
| 28 | |
| 29 void reorder(reorder_callback & p_callback,const t_size * p_order,t_size p_count) | |
| 30 { | |
| 31 t_size done_size = bit_array_bittable::g_estimate_size(p_count); | |
| 32 pfc::array_hybrid_t<unsigned char,1024> done; | |
| 33 done.set_size(done_size); | |
| 34 pfc::memset_t(done,(unsigned char)0); | |
| 35 t_size n; | |
| 36 for(n=0;n<p_count;n++) | |
| 37 { | |
| 38 t_size next = p_order[n]; | |
| 39 if (next!=n && !bit_array_bittable::g_get(done,n)) | |
| 40 { | |
| 41 t_size prev = n; | |
| 42 do | |
| 43 { | |
| 44 PFC_ASSERT(!bit_array_bittable::g_get(done,next)); | |
| 45 PFC_ASSERT(next>n); | |
| 46 PFC_ASSERT(n<p_count); | |
| 47 p_callback.swap(prev,next); | |
| 48 bit_array_bittable::g_set(done,next,true); | |
| 49 prev = next; | |
| 50 next = p_order[next]; | |
| 51 } while(next!=n); | |
| 52 //bit_array_bittable::g_set(done,n,true); | |
| 53 } | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 void reorder_void(void * data,t_size width,const t_size * order,t_size num,void (*swapfunc)(void * item1,void * item2,t_size width)) | |
| 58 { | |
| 59 unsigned char * base = (unsigned char *) data; | |
| 60 t_size done_size = bit_array_bittable::g_estimate_size(num); | |
| 61 pfc::array_hybrid_t<unsigned char,1024> done; | |
| 62 done.set_size(done_size); | |
| 63 pfc::memset_t(done,(unsigned char)0); | |
| 64 t_size n; | |
| 65 for(n=0;n<num;n++) | |
| 66 { | |
| 67 t_size next = order[n]; | |
| 68 if (next!=n && !bit_array_bittable::g_get(done,n)) | |
| 69 { | |
| 70 t_size prev = n; | |
| 71 do | |
| 72 { | |
| 73 PFC_ASSERT(!bit_array_bittable::g_get(done,next)); | |
| 74 PFC_ASSERT(next>n); | |
| 75 PFC_ASSERT(n<num); | |
| 76 swapfunc(base+width*prev,base+width*next,width); | |
| 77 bit_array_bittable::g_set(done,next,true); | |
| 78 prev = next; | |
| 79 next = order[next]; | |
| 80 } while(next!=n); | |
| 81 //bit_array_bittable::g_set(done,n,true); | |
| 82 } | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 namespace { | |
| 87 | |
| 88 class sort_callback_impl_legacy : public sort_callback | |
| 89 { | |
| 90 public: | |
| 91 sort_callback_impl_legacy( | |
| 92 void * p_base,t_size p_width, | |
| 93 int (*p_comp)(const void *, const void *), | |
| 94 void (*p_swap)(void *, void *, t_size) | |
| 95 ) : | |
| 96 m_base((char*)p_base), m_width(p_width), | |
| 97 m_comp(p_comp), m_swap(p_swap) | |
| 98 { | |
| 99 } | |
| 100 | |
| 101 | |
| 102 int compare(t_size p_index1, t_size p_index2) const | |
| 103 { | |
| 104 return m_comp(m_base + p_index1 * m_width, m_base + p_index2 * m_width); | |
| 105 } | |
| 106 | |
| 107 void swap(t_size p_index1, t_size p_index2) | |
| 108 { | |
| 109 m_swap(m_base + p_index1 * m_width, m_base + p_index2 * m_width, m_width); | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 char * m_base; | |
| 114 t_size m_width; | |
| 115 int (*m_comp)(const void *, const void *); | |
| 116 void (*m_swap)(void *, void *, t_size); | |
| 117 }; | |
| 118 } | |
| 119 | |
| 120 void sort_void_ex ( | |
| 121 void *base, | |
| 122 t_size num, | |
| 123 t_size width, | |
| 124 int (*comp)(const void *, const void *), | |
| 125 void (*swap)(void *, void *, t_size) ) | |
| 126 { | |
| 127 sort_callback_impl_legacy cb(base,width,comp,swap); | |
| 128 sort(cb,num); | |
| 129 } | |
| 130 | |
| 131 static void squaresort(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) { | |
| 132 const t_size max = p_base + p_count; | |
| 133 for(t_size walk = p_base + 1; walk < max; ++walk) { | |
| 134 for(t_size prev = p_base; prev < walk; ++prev) { | |
| 135 p_callback.swap_check(prev,walk); | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 | |
| 141 inline static void __sort_2elem_helper(pfc::sort_callback & p_callback,t_size & p_elem1,t_size & p_elem2) { | |
| 142 if (p_callback.compare(p_elem1,p_elem2) > 0) pfc::swap_t(p_elem1,p_elem2); | |
| 143 } | |
| 144 | |
| 145 | |
| 146 #ifdef PFC_HAVE_RDTSC | |
| 147 static inline t_uint64 uniqueVal() {return __rdtsc();} | |
| 148 #else | |
| 149 static counter uniqueValCounter; | |
| 150 static counter::t_val uniqueVal() { | |
| 151 return ++uniqueValCounter; | |
| 152 } | |
| 153 #endif | |
| 154 | |
| 155 static t_size myrand(t_size count) { | |
| 156 const uint64_t rm = (uint64_t)RAND_MAX + 1; | |
| 157 uint64_t m = 1; | |
| 158 uint64_t v = 0; | |
| 159 for(;;) { | |
| 160 v += rand() * m; | |
| 161 m *= rm; | |
| 162 if (m >= count) break; | |
| 163 } | |
| 164 v ^= uniqueVal(); | |
| 165 return (t_size)(v % count); | |
| 166 } | |
| 167 | |
| 168 inline static t_size __pivot_helper(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) { | |
| 169 PFC_ASSERT(p_count > 2); | |
| 170 | |
| 171 //t_size val1 = p_base, val2 = p_base + (p_count / 2), val3 = p_base + (p_count - 1); | |
| 172 | |
| 173 t_size val1 = myrand(p_count), val2 = myrand(p_count-1), val3 = myrand(p_count-2); | |
| 174 if (val2 >= val1) val2++; | |
| 175 if (val3 >= val1) val3++; | |
| 176 if (val3 >= val2) val3++; | |
| 177 | |
| 178 val1 += p_base; val2 += p_base; val3 += p_base; | |
| 179 | |
| 180 __sort_2elem_helper(p_callback,val1,val2); | |
| 181 __sort_2elem_helper(p_callback,val1,val3); | |
| 182 __sort_2elem_helper(p_callback,val2,val3); | |
| 183 | |
| 184 return val2; | |
| 185 } | |
| 186 | |
| 187 static void newsort(pfc::sort_callback & p_callback,t_size const p_base,t_size const p_count) { | |
| 188 if (p_count <= 4) { | |
| 189 squaresort(p_callback,p_base,p_count); | |
| 190 return; | |
| 191 } | |
| 192 | |
| 193 t_size pivot = __pivot_helper(p_callback,p_base,p_count); | |
| 194 | |
| 195 { | |
| 196 const t_size target = p_base + p_count - 1; | |
| 197 if (pivot != target) { | |
| 198 p_callback.swap(pivot,target); pivot = target; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 | |
| 203 t_size partition = p_base; | |
| 204 { | |
| 205 bool asdf = false; | |
| 206 for(t_size walk = p_base; walk < pivot; ++walk) { | |
| 207 const int comp = p_callback.compare(walk,pivot); | |
| 208 bool trigger = false; | |
| 209 if (comp == 0) { | |
| 210 trigger = asdf; | |
| 211 asdf = !asdf; | |
| 212 } else if (comp < 0) { | |
| 213 trigger = true; | |
| 214 } | |
| 215 if (trigger) { | |
| 216 if (partition != walk) p_callback.swap(partition,walk); | |
| 217 partition++; | |
| 218 } | |
| 219 } | |
| 220 } | |
| 221 if (pivot != partition) { | |
| 222 p_callback.swap(pivot,partition); pivot = partition; | |
| 223 } | |
| 224 | |
| 225 newsort(p_callback,p_base,pivot-p_base); | |
| 226 newsort(p_callback,pivot+1,p_count-(pivot+1-p_base)); | |
| 227 } | |
| 228 | |
| 229 void sort(pfc::sort_callback & p_callback,t_size p_num) { | |
| 230 srand((unsigned int)(uniqueVal() ^ p_num)); | |
| 231 newsort(p_callback,0,p_num); | |
| 232 } | |
| 233 | |
| 234 | |
| 235 void sort_void(void * base,t_size num,t_size width,int (*comp)(const void *, const void *) ) | |
| 236 { | |
| 237 sort_void_ex(base,num,width,comp,swap_void); | |
| 238 } | |
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 sort_callback_stabilizer::sort_callback_stabilizer(sort_callback & p_chain,t_size p_count) | |
| 244 : m_chain(p_chain) | |
| 245 { | |
| 246 m_order.set_size(p_count); | |
| 247 t_size n; | |
| 248 for(n=0;n<p_count;n++) m_order[n] = n; | |
| 249 } | |
| 250 | |
| 251 int sort_callback_stabilizer::compare(t_size p_index1, t_size p_index2) const | |
| 252 { | |
| 253 int ret = m_chain.compare(p_index1,p_index2); | |
| 254 if (ret == 0) ret = pfc::sgn_t((t_ssize)m_order[p_index1] - (t_ssize)m_order[p_index2]); | |
| 255 return ret; | |
| 256 } | |
| 257 | |
| 258 void sort_callback_stabilizer::swap(t_size p_index1, t_size p_index2) | |
| 259 { | |
| 260 m_chain.swap(p_index1,p_index2); | |
| 261 pfc::swap_t(m_order[p_index1],m_order[p_index2]); | |
| 262 } | |
| 263 | |
| 264 | |
| 265 void sort_stable(sort_callback & p_callback,t_size p_count) | |
| 266 { | |
| 267 sort_callback_stabilizer cb(p_callback,p_count); | |
| 268 sort(cb,p_count); | |
| 269 } | |
| 270 | |
| 271 | |
| 272 | |
| 273 permutation_t make_identitiy(size_t count) { | |
| 274 permutation_t ret; ret.set_size_discard(count); | |
| 275 for (size_t walk = 0; walk < count; ++walk) { | |
| 276 ret[walk] = walk; | |
| 277 } | |
| 278 return ret; | |
| 279 } | |
| 280 | |
| 281 } | |
| 282 |
