Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/SDK/metadb_handle_list.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 "foobar2000-sdk-pch.h" | |
| 2 #include "foosort.h" | |
| 3 #include "threadPool.h" | |
| 4 #include "foosortstring.h" | |
| 5 #include <vector> | |
| 6 #include "titleformat.h" | |
| 7 #include "library_manager.h" | |
| 8 #include "genrand.h" | |
| 9 | |
| 10 namespace { | |
| 11 | |
| 12 struct custom_sort_data_multi { | |
| 13 static constexpr unsigned numLocal = 4; | |
| 14 void setup(size_t count) { | |
| 15 if (count > numLocal) texts2 = std::make_unique< fb2k::sortString_t[] >( count - numLocal ); | |
| 16 } | |
| 17 fb2k::sortString_t& operator[] (size_t which) { | |
| 18 return which < numLocal ? texts1[which] : texts2[which - numLocal]; | |
| 19 } | |
| 20 const fb2k::sortString_t& operator[] (size_t which) const { | |
| 21 return which < numLocal ? texts1[which] : texts2[which - numLocal]; | |
| 22 } | |
| 23 | |
| 24 fb2k::sortString_t texts1[numLocal]; | |
| 25 std::unique_ptr< fb2k::sortString_t[] > texts2; | |
| 26 size_t index; | |
| 27 }; | |
| 28 struct custom_sort_data { | |
| 29 fb2k::sortString_t text; | |
| 30 size_t index; | |
| 31 }; | |
| 32 template<int direction> | |
| 33 static int custom_sort_compare(const custom_sort_data& elem1, const custom_sort_data& elem2) { | |
| 34 int ret = direction * fb2k::sortStringCompare(elem1.text, elem2.text); | |
| 35 if (ret == 0) ret = pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index); | |
| 36 return ret; | |
| 37 } | |
| 38 | |
| 39 } | |
| 40 | |
| 41 void metadb_handle_list_helper::sort_by_format(metadb_handle_list_ref p_list,const char * spec,titleformat_hook * p_hook) | |
| 42 { | |
| 43 service_ptr_t<titleformat_object> script; | |
| 44 if (titleformat_compiler::get()->compile(script,spec)) | |
| 45 sort_by_format(p_list,script,p_hook); | |
| 46 } | |
| 47 | |
| 48 void metadb_handle_list_helper::sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const char * spec,titleformat_hook * p_hook) | |
| 49 { | |
| 50 service_ptr_t<titleformat_object> script; | |
| 51 if (titleformat_compiler::get()->compile(script,spec)) | |
| 52 sort_by_format_get_order(p_list,order,script,p_hook); | |
| 53 } | |
| 54 | |
| 55 void metadb_handle_list_helper::sort_by_format(metadb_handle_list_ref p_list,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook, int direction) | |
| 56 { | |
| 57 const t_size count = p_list.get_count(); | |
| 58 pfc::array_t<t_size> order; order.set_size(count); | |
| 59 sort_by_format_get_order(p_list,order.get_ptr(),p_script,p_hook,direction); | |
| 60 p_list.reorder(order.get_ptr()); | |
| 61 } | |
| 62 | |
| 63 namespace { | |
| 64 | |
| 65 class tfhook_sort : public titleformat_hook { | |
| 66 public: | |
| 67 tfhook_sort() { | |
| 68 m_API->seed(); | |
| 69 } | |
| 70 bool process_field(titleformat_text_out *,const char *,t_size,bool &) override { | |
| 71 return false; | |
| 72 } | |
| 73 bool process_function(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag) override { | |
| 74 if (stricmp_utf8_ex(p_name, p_name_length, "rand", SIZE_MAX) == 0) { | |
| 75 t_size param_count = p_params->get_param_count(); | |
| 76 t_uint32 val; | |
| 77 if (param_count == 1) { | |
| 78 t_uint32 mod = (t_uint32)p_params->get_param_uint(0); | |
| 79 if (mod > 0) { | |
| 80 val = m_API->genrand(mod); | |
| 81 } else { | |
| 82 val = 0; | |
| 83 } | |
| 84 } else { | |
| 85 val = m_API->genrand(0xFFFFFFFF); | |
| 86 } | |
| 87 p_out->write_int(titleformat_inputtypes::unknown, val); | |
| 88 p_found_flag = true; | |
| 89 return true; | |
| 90 } else { | |
| 91 return false; | |
| 92 } | |
| 93 } | |
| 94 private: | |
| 95 genrand_service::ptr m_API = genrand_service::get(); | |
| 96 }; | |
| 97 } | |
| 98 | |
| 99 void metadb_handle_list_helper::sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook,int p_direction) | |
| 100 { | |
| 101 sort_by_format_get_order_v2(p_list, order, p_script, p_hook, p_direction, fb2k::noAbort ); | |
| 102 } | |
| 103 | |
| 104 void metadb_handle_list_helper::sort_by_relative_path(metadb_handle_list_ref p_list) | |
| 105 { | |
| 106 const t_size count = p_list.get_count(); | |
| 107 pfc::array_t<t_size> order; order.set_size(count); | |
| 108 sort_by_relative_path_get_order(p_list,order.get_ptr()); | |
| 109 p_list.reorder(order.get_ptr()); | |
| 110 } | |
| 111 | |
| 112 void metadb_handle_list_helper::sort_by_relative_path_get_order(metadb_handle_list_cref p_list,t_size* order) | |
| 113 { | |
| 114 const t_size count = p_list.get_count(); | |
| 115 t_size n; | |
| 116 std::vector<custom_sort_data> data; | |
| 117 data.resize(count); | |
| 118 auto api = library_manager::get(); | |
| 119 | |
| 120 pfc::string8_fastalloc temp; | |
| 121 temp.prealloc(512); | |
| 122 for(n=0;n<count;n++) | |
| 123 { | |
| 124 metadb_handle_ptr item; | |
| 125 p_list.get_item_ex(item,n); | |
| 126 if (!api->get_relative_path(item,temp)) temp = ""; | |
| 127 data[n].index = n; | |
| 128 data[n].text = fb2k::makeSortString(temp); | |
| 129 //data[n].subsong = item->get_subsong_index(); | |
| 130 } | |
| 131 | |
| 132 pfc::sort_t(data,custom_sort_compare<1>,count); | |
| 133 //qsort(data.get_ptr(),count,sizeof(custom_sort_data),(int (__cdecl *)(const void *elem1, const void *elem2 ))custom_sort_compare); | |
| 134 | |
| 135 for(n=0;n<count;n++) | |
| 136 { | |
| 137 order[n]=data[n].index; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 void metadb_handle_list_helper::remove_duplicates(metadb_handle_list_ref p_list) | |
| 142 { | |
| 143 t_size count = p_list.get_count(); | |
| 144 if (count>0) | |
| 145 { | |
| 146 pfc::bit_array_bittable mask(count); | |
| 147 pfc::array_t<t_size> order; order.set_size(count); | |
| 148 order_helper::g_fill(order); | |
| 149 | |
| 150 p_list.sort_get_permutation_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,order.get_ptr()); | |
| 151 | |
| 152 t_size n; | |
| 153 bool found = false; | |
| 154 for(n=0;n<count-1;n++) | |
| 155 { | |
| 156 if (p_list.get_item(order[n])==p_list.get_item(order[n+1])) | |
| 157 { | |
| 158 found = true; | |
| 159 mask.set(order[n+1],true); | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 if (found) p_list.remove_mask(mask); | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 void metadb_handle_list_helper::sort_by_pointer_remove_duplicates(metadb_handle_list_ref p_list) | |
| 168 { | |
| 169 const t_size count = p_list.get_count(); | |
| 170 if (count>0) | |
| 171 { | |
| 172 sort_by_pointer(p_list); | |
| 173 bool b_found = false; | |
| 174 for(size_t n=0;n<count-1;n++) | |
| 175 { | |
| 176 if (p_list.get_item(n)==p_list.get_item(n+1)) | |
| 177 { | |
| 178 b_found = true; | |
| 179 break; | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 if (b_found) | |
| 184 { | |
| 185 pfc::bit_array_bittable mask(count); | |
| 186 for(size_t n=0;n<count-1;n++) | |
| 187 { | |
| 188 if (p_list.get_item(n)==p_list.get_item(n+1)) | |
| 189 mask.set(n+1,true); | |
| 190 } | |
| 191 p_list.remove_mask(mask); | |
| 192 } | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 void metadb_handle_list_helper::sort_by_path_quick(metadb_handle_list_ref p_list) | |
| 197 { | |
| 198 p_list.sort_t(metadb::path_compare_metadb_handle); | |
| 199 } | |
| 200 | |
| 201 | |
| 202 void metadb_handle_list_helper::sort_by_pointer(metadb_handle_list_ref p_list) | |
| 203 { | |
| 204 p_list.sort(); | |
| 205 } | |
| 206 | |
| 207 t_size metadb_handle_list_helper::bsearch_by_pointer(metadb_handle_list_cref p_list,const metadb_handle_ptr & val) | |
| 208 { | |
| 209 t_size blah; | |
| 210 if (p_list.bsearch_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,val,blah)) return blah; | |
| 211 else return SIZE_MAX; | |
| 212 } | |
| 213 | |
| 214 | |
| 215 void metadb_handle_list_helper::sorted_by_pointer_extract_difference(metadb_handle_list const & p_list_1,metadb_handle_list const & p_list_2,metadb_handle_list & p_list_1_specific,metadb_handle_list & p_list_2_specific) | |
| 216 { | |
| 217 t_size found_1, found_2; | |
| 218 const t_size count_1 = p_list_1.get_count(), count_2 = p_list_2.get_count(); | |
| 219 t_size ptr_1, ptr_2; | |
| 220 | |
| 221 found_1 = found_2 = 0; | |
| 222 ptr_1 = ptr_2 = 0; | |
| 223 while(ptr_1 < count_1 || ptr_2 < count_2) | |
| 224 { | |
| 225 while(ptr_1 < count_1 && (ptr_2 == count_2 || p_list_1[ptr_1] < p_list_2[ptr_2])) | |
| 226 { | |
| 227 found_1++; | |
| 228 t_size ptr_1_new = ptr_1 + 1; | |
| 229 while(ptr_1_new < count_1 && p_list_1[ptr_1_new] == p_list_1[ptr_1]) ptr_1_new++; | |
| 230 ptr_1 = ptr_1_new; | |
| 231 } | |
| 232 while(ptr_2 < count_2 && (ptr_1 == count_1 || p_list_2[ptr_2] < p_list_1[ptr_1])) | |
| 233 { | |
| 234 found_2++; | |
| 235 t_size ptr_2_new = ptr_2 + 1; | |
| 236 while(ptr_2_new < count_2 && p_list_2[ptr_2_new] == p_list_2[ptr_2]) ptr_2_new++; | |
| 237 ptr_2 = ptr_2_new; | |
| 238 } | |
| 239 while(ptr_1 < count_1 && ptr_2 < count_2 && p_list_1[ptr_1] == p_list_2[ptr_2]) {ptr_1++; ptr_2++;} | |
| 240 } | |
| 241 | |
| 242 | |
| 243 | |
| 244 p_list_1_specific.set_count(found_1); | |
| 245 p_list_2_specific.set_count(found_2); | |
| 246 if (found_1 > 0 || found_2 > 0) | |
| 247 { | |
| 248 found_1 = found_2 = 0; | |
| 249 ptr_1 = ptr_2 = 0; | |
| 250 | |
| 251 while(ptr_1 < count_1 || ptr_2 < count_2) | |
| 252 { | |
| 253 while(ptr_1 < count_1 && (ptr_2 == count_2 || p_list_1[ptr_1] < p_list_2[ptr_2])) | |
| 254 { | |
| 255 p_list_1_specific[found_1++] = p_list_1[ptr_1]; | |
| 256 t_size ptr_1_new = ptr_1 + 1; | |
| 257 while(ptr_1_new < count_1 && p_list_1[ptr_1_new] == p_list_1[ptr_1]) ptr_1_new++; | |
| 258 ptr_1 = ptr_1_new; | |
| 259 } | |
| 260 while(ptr_2 < count_2 && (ptr_1 == count_1 || p_list_2[ptr_2] < p_list_1[ptr_1])) | |
| 261 { | |
| 262 p_list_2_specific[found_2++] = p_list_2[ptr_2]; | |
| 263 t_size ptr_2_new = ptr_2 + 1; | |
| 264 while(ptr_2_new < count_2 && p_list_2[ptr_2_new] == p_list_2[ptr_2]) ptr_2_new++; | |
| 265 ptr_2 = ptr_2_new; | |
| 266 } | |
| 267 while(ptr_1 < count_1 && ptr_2 < count_2 && p_list_1[ptr_1] == p_list_2[ptr_2]) {ptr_1++; ptr_2++;} | |
| 268 } | |
| 269 | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 double metadb_handle_list_helper::calc_total_duration_v2(metadb_handle_list_cref p_list, unsigned maxThreads, abort_callback & aborter) { | |
| 274 const size_t count = p_list.get_count(); | |
| 275 size_t numThreads = pfc::getOptimalWorkerThreadCountEx( pfc::min_t<size_t>(maxThreads, count / 2000 )); | |
| 276 if (numThreads == 1) { | |
| 277 double ret = 0; | |
| 278 for (size_t n = 0; n < count; n++) | |
| 279 { | |
| 280 double temp = p_list.get_item(n)->get_length(); | |
| 281 if (temp > 0) ret += temp; | |
| 282 } | |
| 283 return ret; | |
| 284 } | |
| 285 | |
| 286 pfc::array_t<double> sums; sums.resize(numThreads); sums.fill_null(); | |
| 287 | |
| 288 { | |
| 289 pfc::refcounter walk = 0, walkSums = 0; | |
| 290 | |
| 291 auto worker = [&] { | |
| 292 double ret = 0; | |
| 293 for (;;) { | |
| 294 size_t idx = walk++; | |
| 295 if (idx >= count || aborter.is_set()) break; | |
| 296 | |
| 297 double temp = p_list.get_item(idx)->get_length(); | |
| 298 if (temp > 0) ret += temp; | |
| 299 } | |
| 300 sums[walkSums++] = ret; | |
| 301 }; | |
| 302 | |
| 303 fb2k::cpuThreadPool::runMultiHelper(worker, numThreads); | |
| 304 } | |
| 305 aborter.check(); | |
| 306 double ret = 0; | |
| 307 for (size_t walk = 0; walk < numThreads; ++walk) ret += sums[walk]; | |
| 308 return ret; | |
| 309 } | |
| 310 | |
| 311 pfc::string8 metadb_handle_list_helper::format_total_size(metadb_handle_list_cref p_list) { | |
| 312 pfc::string8 temp; | |
| 313 bool unknown = false; | |
| 314 t_filesize val = metadb_handle_list_helper::calc_total_size_ex(p_list,unknown); | |
| 315 if (unknown) temp << "> "; | |
| 316 temp << pfc::format_file_size_short(val); | |
| 317 return temp; | |
| 318 } | |
| 319 | |
| 320 double metadb_handle_list_helper::calc_total_duration(metadb_handle_list_cref p_list) | |
| 321 { | |
| 322 double ret = 0; | |
| 323 for (auto handle : p_list) { | |
| 324 double temp = handle->get_length(); | |
| 325 if (temp > 0) ret += temp; | |
| 326 } | |
| 327 return ret; | |
| 328 } | |
| 329 | |
| 330 void metadb_handle_list_helper::sort_by_path(metadb_handle_list_ref p_list) | |
| 331 { | |
| 332 sort_by_format(p_list,"%path_sort%",NULL); | |
| 333 } | |
| 334 | |
| 335 void metadb_handle_list_helper::sort_by_format_v2(metadb_handle_list_ref p_list, const service_ptr_t<titleformat_object> & script, titleformat_hook * hook, int direction, abort_callback & aborter) { | |
| 336 pfc::array_t<size_t> order; order.set_size( p_list.get_count() ); | |
| 337 sort_by_format_get_order_v2( p_list, order.get_ptr(), script, hook, direction, aborter ); | |
| 338 p_list.reorder( order.get_ptr() ); | |
| 339 } | |
| 340 | |
| 341 void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_cref p_list, size_t * order, const service_ptr_t<titleformat_object> & p_script, titleformat_hook * p_hook, int p_direction, abort_callback & aborter) { | |
| 342 sorter_t s = { p_script, p_direction, p_hook }; | |
| 343 size_t total = p_list.get_count(); | |
| 344 for (size_t walk = 0; walk < total; ++walk) order[walk] = walk; | |
| 345 sort_by_format_get_order_v3(p_list, order, &s, 1, aborter); | |
| 346 } | |
| 347 | |
| 348 void metadb_handle_list_helper::sort_by_format_get_order_v3(metadb_handle_list_cref p_list, size_t* order,sorter_t const* sorters, size_t nSorters, abort_callback& aborter) { | |
| 349 // pfc::hires_timer timer; timer.start(); | |
| 350 | |
| 351 typedef custom_sort_data_multi data_t; | |
| 352 | |
| 353 const t_size count = p_list.get_count(); | |
| 354 if (count == 0) return; | |
| 355 | |
| 356 PFC_ASSERT(pfc::permutation_is_valid(order, count)); | |
| 357 | |
| 358 auto data = std::make_unique< data_t[] >(count); | |
| 359 | |
| 360 #if FOOBAR2000_TARGET_VERSION >= 81 | |
| 361 bool need_info = false; | |
| 362 for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { | |
| 363 auto& s = sorters[iSorter]; | |
| 364 PFC_ASSERT(s.direction == -1 || s.direction == 1); | |
| 365 if (s.obj->requires_metadb_info_()) { | |
| 366 need_info = true; break; | |
| 367 } | |
| 368 } | |
| 369 if (need_info) { | |
| 370 // FB2K_console_formatter() << "sorting with queryMultiParallelEx_<>"; | |
| 371 struct qmpc_context { | |
| 372 qmpc_context() { | |
| 373 temp.prealloc(512); | |
| 374 } | |
| 375 tfhook_sort myHook; | |
| 376 pfc::string8 temp; | |
| 377 }; | |
| 378 metadb_v2::get()->queryMultiParallelEx_< qmpc_context >(p_list, [&](size_t idx, metadb_v2::rec_t const& rec, qmpc_context& ctx) { | |
| 379 aborter.check(); | |
| 380 auto& out = data[idx]; | |
| 381 out.setup(nSorters); | |
| 382 out.index = order[idx]; | |
| 383 | |
| 384 auto h = p_list[idx]; | |
| 385 | |
| 386 for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { | |
| 387 auto& s = sorters[iSorter]; | |
| 388 if (s.hook) { | |
| 389 titleformat_hook_impl_splitter hookSplitter(&ctx.myHook, s.hook); | |
| 390 h->formatTitle_v2_(rec, &hookSplitter, ctx.temp, s.obj, nullptr); | |
| 391 } else { | |
| 392 h->formatTitle_v2_(rec, &ctx.myHook, ctx.temp, s.obj, nullptr); | |
| 393 } | |
| 394 out[iSorter] = fb2k::makeSortString(ctx.temp); | |
| 395 } | |
| 396 }); | |
| 397 } else { | |
| 398 // FB2K_console_formatter() << "sorting with blank metadb info"; | |
| 399 auto api = fb2k::cpuThreadPool::get(); | |
| 400 pfc::counter walk = 0; | |
| 401 api->runMulti_([&] { | |
| 402 pfc::string8 temp; | |
| 403 const metadb_v2_rec_t rec = {}; | |
| 404 tfhook_sort myHook; | |
| 405 for (;;) { | |
| 406 aborter.check(); | |
| 407 size_t idx = walk++; | |
| 408 if (idx >= count) return; | |
| 409 | |
| 410 auto& out = data[idx]; | |
| 411 out.setup(nSorters); | |
| 412 out.index = order[idx]; | |
| 413 | |
| 414 for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { | |
| 415 auto& s = sorters[iSorter]; | |
| 416 if (s.hook) { | |
| 417 titleformat_hook_impl_splitter hookSplitter(&myHook, s.hook); | |
| 418 p_list[idx]->formatTitle_v2_(rec, &hookSplitter, temp, s.obj, nullptr); | |
| 419 } else { | |
| 420 p_list[idx]->formatTitle_v2_(rec, &myHook, temp, s.obj, nullptr); | |
| 421 } | |
| 422 | |
| 423 out[iSorter] = fb2k::makeSortString(temp); | |
| 424 } | |
| 425 } | |
| 426 }, api->numRunsSanity((count + 1999) / 2000)); | |
| 427 | |
| 428 } | |
| 429 #else | |
| 430 { | |
| 431 pfc::counter counter(0); | |
| 432 | |
| 433 auto work = [&] { | |
| 434 tfhook_sort myHook; | |
| 435 | |
| 436 pfc::string8_fastalloc temp; temp.prealloc(512); | |
| 437 for (;; ) { | |
| 438 const t_size index = (counter)++; | |
| 439 if (index >= count || aborter.is_set()) break; | |
| 440 | |
| 441 auto& out = data[index]; | |
| 442 out.setup(nSorters); | |
| 443 out.index = order[index]; | |
| 444 | |
| 445 for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { | |
| 446 auto& s = sorters[iSorter]; | |
| 447 if (s.hook) { | |
| 448 titleformat_hook_impl_splitter hookSplitter(&myHook, s.hook); | |
| 449 p_list[index]->format_title(&hookSplitter, temp, s.obj, 0); | |
| 450 } else { | |
| 451 p_list[index]->format_title(&myHook, temp, s.obj, 0); | |
| 452 } | |
| 453 | |
| 454 out[iSorter] = fb2k::makeSortString(temp); | |
| 455 } | |
| 456 } | |
| 457 }; | |
| 458 | |
| 459 size_t nThreads = pfc::getOptimalWorkerThreadCountEx(count / 128); | |
| 460 if (nThreads == 1) { | |
| 461 work(); | |
| 462 } else { | |
| 463 fb2k::cpuThreadPool::runMultiHelper(work, nThreads); | |
| 464 } | |
| 465 } | |
| 466 #endif | |
| 467 aborter.check(); | |
| 468 // console::formatter() << "metadb_handle sort: prepared in " << pfc::format_time_ex(timer.query(),6); | |
| 469 | |
| 470 | |
| 471 { | |
| 472 auto compare = [&](data_t const& elem1, data_t const& elem2) -> int { | |
| 473 for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { | |
| 474 int v = fb2k::sortStringCompare(elem1[iSorter], elem2[iSorter]); | |
| 475 if (v) return v * sorters[iSorter].direction; | |
| 476 } | |
| 477 | |
| 478 return pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index); | |
| 479 }; | |
| 480 | |
| 481 typedef decltype(data) container_t; | |
| 482 typedef decltype(compare) compare_t; | |
| 483 pfc::sort_callback_impl_simple_wrap_t<container_t, compare_t> cb(data, compare); | |
| 484 | |
| 485 size_t concurrency = pfc::getOptimalWorkerThreadCountEx(count / 4096); | |
| 486 fb2k::sort(cb, count, concurrency, aborter); | |
| 487 } | |
| 488 | |
| 489 //qsort(data.get_ptr(),count,sizeof(custom_sort_data),p_direction > 0 ? _custom_sort_compare<1> : _custom_sort_compare<-1>); | |
| 490 | |
| 491 | |
| 492 // console::formatter() << "metadb_handle sort: sorted in " << pfc::format_time_ex(timer.query(),6); | |
| 493 | |
| 494 for (t_size n = 0; n < count; n++) | |
| 495 { | |
| 496 order[n] = data[n].index; | |
| 497 } | |
| 498 | |
| 499 // FB2K_console_formatter() << "metadb_handle sort: finished in " << pfc::format_time_ex(timer.query(),6); | |
| 500 | |
| 501 } | |
| 502 | |
| 503 t_filesize metadb_handle_list_helper::calc_total_size(metadb_handle_list_cref p_list, bool skipUnknown) { | |
| 504 pfc::avltree_t< const char*, metadb::path_comparator > beenHere; | |
| 505 // metadb_handle_list list(p_list); | |
| 506 // list.sort_t(metadb::path_compare_metadb_handle); | |
| 507 | |
| 508 t_filesize ret = 0; | |
| 509 t_size n, m = p_list.get_count(); | |
| 510 for(n=0;n<m;n++) { | |
| 511 bool isNew; | |
| 512 metadb_handle_ptr h; p_list.get_item_ex(h, n); | |
| 513 beenHere.add_ex( h->get_path(), isNew); | |
| 514 if (isNew) { | |
| 515 t_filesize t = h->get_filesize(); | |
| 516 if (t == filesize_invalid) { | |
| 517 if (!skipUnknown) return filesize_invalid; | |
| 518 } else { | |
| 519 ret += t; | |
| 520 } | |
| 521 } | |
| 522 } | |
| 523 return ret; | |
| 524 } | |
| 525 | |
| 526 t_filesize metadb_handle_list_helper::calc_total_size_ex(metadb_handle_list_cref p_list, bool & foundUnknown) { | |
| 527 foundUnknown = false; | |
| 528 metadb_handle_list list(p_list); | |
| 529 list.sort_t(metadb::path_compare_metadb_handle); | |
| 530 | |
| 531 t_filesize ret = 0; | |
| 532 t_size n, m = list.get_count(); | |
| 533 for(n=0;n<m;n++) { | |
| 534 if (n==0 || metadb::path_compare(list[n-1]->get_path(),list[n]->get_path())) { | |
| 535 t_filesize t = list[n]->get_filesize(); | |
| 536 if (t == filesize_invalid) { | |
| 537 foundUnknown = true; | |
| 538 } else { | |
| 539 ret += t; | |
| 540 } | |
| 541 } | |
| 542 } | |
| 543 return ret; | |
| 544 } | |
| 545 | |
| 546 bool metadb_handle_list_helper::extract_folder_path(metadb_handle_list_cref list, pfc::string_base & folderOut) { | |
| 547 const t_size total = list.get_count(); | |
| 548 if (total == 0) return false; | |
| 549 pfc::string_formatter temp, folder; | |
| 550 folder = list[0]->get_path(); | |
| 551 folder.truncate_to_parent_path(); | |
| 552 for(size_t walk = 1; walk < total; ++walk) { | |
| 553 temp = list[walk]->get_path(); | |
| 554 temp.truncate_to_parent_path(); | |
| 555 if (metadb::path_compare(folder, temp) != 0) return false; | |
| 556 } | |
| 557 folderOut = folder; | |
| 558 return true; | |
| 559 } | |
| 560 bool metadb_handle_list_helper::extract_single_path(metadb_handle_list_cref list, const char * &pathOut) { | |
| 561 const t_size total = list.get_count(); | |
| 562 if (total == 0) return false; | |
| 563 const char * path = list[0]->get_path(); | |
| 564 for(t_size walk = 1; walk < total; ++walk) { | |
| 565 if (metadb::path_compare(path, list[walk]->get_path()) != 0) return false; | |
| 566 } | |
| 567 pathOut = path; | |
| 568 return true; | |
| 569 } |
