foobar2000 SDK  2015-01-14
metadb_handle_list.cpp
Go to the documentation of this file.
1 #include "foobar2000.h"
2 #include <shlwapi.h>
3 
4 namespace {
5 
6  wchar_t * makeSortString(const char * in) {
7  wchar_t * out = new wchar_t[pfc::stringcvt::estimate_utf8_to_wide(in) + 1];
8  out[0] = ' ';//StrCmpLogicalW bug workaround.
10  return out;
11  }
12 
13  struct custom_sort_data {
14  wchar_t * text;
15  t_size index;
16  };
17 }
18 
19 template<int direction>
20 static int custom_sort_compare(const custom_sort_data & elem1, const custom_sort_data & elem2 ) {
21  int ret = direction * StrCmpLogicalW(elem1.text,elem2.text);
22  if (ret == 0) ret = pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index);
23  return ret;
24 }
25 
26 
27 template<int direction>
28 static int _cdecl _custom_sort_compare(const void * v1, const void * v2) {
29  return custom_sort_compare<direction>(*reinterpret_cast<const custom_sort_data*>(v1),*reinterpret_cast<const custom_sort_data*>(v2));
30 }
32 {
34  if (static_api_ptr_t<titleformat_compiler>()->compile(script,spec))
35  sort_by_format(p_list,script,p_hook);
36 }
37 
39 {
41  if (static_api_ptr_t<titleformat_compiler>()->compile(script,spec))
42  sort_by_format_get_order(p_list,order,script,p_hook);
43 }
44 
46 {
47  const t_size count = p_list.get_count();
48  pfc::array_t<t_size> order; order.set_size(count);
49  sort_by_format_get_order(p_list,order.get_ptr(),p_script,p_hook,direction);
50  p_list.reorder(order.get_ptr());
51 }
52 
53 namespace {
54 
55  class tfhook_sort : public titleformat_hook {
56  public:
57  tfhook_sort() {
58  m_API->seed((unsigned)__rdtsc());
59  }
60  bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag) {
61  return false;
62  }
63  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) {
64  if (stricmp_utf8_ex(p_name, p_name_length, "rand", ~0) == 0) {
65  t_size param_count = p_params->get_param_count();
66  t_uint32 val;
67  if (param_count == 1) {
68  t_uint32 mod = (t_uint32)p_params->get_param_uint(0);
69  if (mod > 0) {
70  val = m_API->genrand(mod);
71  } else {
72  val = 0;
73  }
74  } else {
75  val = m_API->genrand(0xFFFFFFFF);
76  }
78  p_found_flag = true;
79  return true;
80  } else {
81  return false;
82  }
83  }
84  private:
86  };
87 
88  class tfthread : public pfc::thread {
89  public:
90  tfthread(pfc::counter * walk, metadb_handle_list_cref items,custom_sort_data * out,titleformat_object::ptr script,titleformat_hook * hook) : m_walk(walk), m_items(items), m_out(out), m_script(script), m_hook(hook) {}
91  ~tfthread() {waitTillDone();}
92 
93 
94 
95  void threadProc() {
96  TRACK_CALL_TEXT("metadb_handle sort helper thread");
97 
98  tfhook_sort myHook;
99  titleformat_hook_impl_splitter hookSplitter(&myHook, m_hook);
100  titleformat_hook * const hookPtr = m_hook ? pfc::implicit_cast<titleformat_hook*>(&hookSplitter) : &myHook;
101 
102  pfc::string8_fastalloc temp; temp.prealloc(512);
103  const t_size total = m_items.get_size();
104  for(;;) {
105  const t_size index = (*m_walk)++;
106  if (index >= total) break;
107  m_out[index].index = index;
108  m_items[index]->format_title(hookPtr,temp,m_script,0);
109  m_out[index].text = makeSortString(temp);
110  }
111  }
112  private:
113  pfc::counter * const m_walk;
114  metadb_handle_list_cref m_items;
115  custom_sort_data * const m_out;
116  titleformat_object::ptr const m_script;
117  titleformat_hook * const m_hook;
118  };
119 }
120 
122 {
123 // pfc::hires_timer timer; timer.start();
124 
125  const t_size count = p_list.get_count();
126  pfc::array_t<custom_sort_data> data; data.set_size(count);
127 
128  {
129  pfc::counter counter(0);
131  PFC_ASSERT( threads.get_size() > 0 );
132  for(t_size walk = 0; walk < threads.get_size(); ++walk) {
133  threads[walk].new_t(&counter,p_list,data.get_ptr(),p_script,p_hook);
134  }
135  for(t_size walk = 1; walk < threads.get_size(); ++walk) threads[walk]->start();
136  threads[0]->threadProc();
137  for(t_size walk = 1; walk < threads.get_size(); ++walk) threads[walk]->waitTillDone();
138  }
139 // console::formatter() << "metadb_handle sort: prepared in " << pfc::format_time_ex(timer.query(),6);
140 
141  pfc::sort_t(data, p_direction > 0 ? custom_sort_compare<1> : custom_sort_compare<-1>,count);
142  //qsort(data.get_ptr(),count,sizeof(custom_sort_data),p_direction > 0 ? _custom_sort_compare<1> : _custom_sort_compare<-1>);
143 
144 
145 // console::formatter() << "metadb_handle sort: sorted in " << pfc::format_time_ex(timer.query(),6);
146 
147  for(t_size n=0;n<count;n++)
148  {
149  order[n]=data[n].index;
150  delete[] data[n].text;
151  }
152 
153 // console::formatter() << "metadb_handle sort: finished in " << pfc::format_time_ex(timer.query(),6);
154 }
155 
157 {
158  const t_size count = p_list.get_count();
159  pfc::array_t<t_size> order; order.set_size(count);
161  p_list.reorder(order.get_ptr());
162 }
163 
165 {
166  const t_size count = p_list.get_count();
167  t_size n;
169  data.set_size(count);
171 
173  temp.prealloc(512);
174  for(n=0;n<count;n++)
175  {
176  metadb_handle_ptr item;
177  p_list.get_item_ex(item,n);
178  if (!api->get_relative_path(item,temp)) temp = "";
179  data[n].index = n;
180  data[n].text = makeSortString(temp);
181  //data[n].subsong = item->get_subsong_index();
182  }
183 
184  pfc::sort_t(data,custom_sort_compare<1>,count);
185  //qsort(data.get_ptr(),count,sizeof(custom_sort_data),(int (__cdecl *)(const void *elem1, const void *elem2 ))custom_sort_compare);
186 
187  for(n=0;n<count;n++)
188  {
189  order[n]=data[n].index;
190  delete[] data[n].text;
191  }
192 }
193 
195 {
196  t_size count = p_list.get_count();
197  if (count>0)
198  {
199  bit_array_bittable mask(count);
200  pfc::array_t<t_size> order; order.set_size(count);
201  order_helper::g_fill(order);
202 
203  p_list.sort_get_permutation_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,order.get_ptr());
204 
205  t_size n;
206  bool found = false;
207  for(n=0;n<count-1;n++)
208  {
209  if (p_list.get_item(order[n])==p_list.get_item(order[n+1]))
210  {
211  found = true;
212  mask.set(order[n+1],true);
213  }
214  }
215 
216  if (found) p_list.remove_mask(mask);
217  }
218 }
219 
221 {
222  t_size count = p_list.get_count();
223  if (count>0)
224  {
225  sort_by_pointer(p_list);
226  bool b_found = false;
227  t_size n;
228  for(n=0;n<count-1;n++)
229  {
230  if (p_list.get_item(n)==p_list.get_item(n+1))
231  {
232  b_found = true;
233  break;
234  }
235  }
236 
237  if (b_found)
238  {
239  bit_array_bittable mask(count);
240  t_size n;
241  for(n=0;n<count-1;n++)
242  {
243  if (p_list.get_item(n)==p_list.get_item(n+1))
244  mask.set(n+1,true);
245  }
246  p_list.remove_mask(mask);
247  }
248  }
249 }
250 
252 {
254 }
255 
256 
258 {
259  //it seems MSVC71 /GL does something highly retarded here
260  //p_list.sort_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>);
261  p_list.sort();
262 }
263 
265 {
266  t_size blah;
267  if (p_list.bsearch_t(pfc::compare_t<metadb_handle_ptr,metadb_handle_ptr>,val,blah)) return blah;
268  else return ~0;
269 }
270 
271 
273 {
274  t_size found_1, found_2;
275  const t_size count_1 = p_list_1.get_count(), count_2 = p_list_2.get_count();
276  t_size ptr_1, ptr_2;
277 
278  found_1 = found_2 = 0;
279  ptr_1 = ptr_2 = 0;
280  while(ptr_1 < count_1 || ptr_2 < count_2)
281  {
282  while(ptr_1 < count_1 && (ptr_2 == count_2 || p_list_1[ptr_1] < p_list_2[ptr_2]))
283  {
284  found_1++;
285  t_size ptr_1_new = ptr_1 + 1;
286  while(ptr_1_new < count_1 && p_list_1[ptr_1_new] == p_list_1[ptr_1]) ptr_1_new++;
287  ptr_1 = ptr_1_new;
288  }
289  while(ptr_2 < count_2 && (ptr_1 == count_1 || p_list_2[ptr_2] < p_list_1[ptr_1]))
290  {
291  found_2++;
292  t_size ptr_2_new = ptr_2 + 1;
293  while(ptr_2_new < count_2 && p_list_2[ptr_2_new] == p_list_2[ptr_2]) ptr_2_new++;
294  ptr_2 = ptr_2_new;
295  }
296  while(ptr_1 < count_1 && ptr_2 < count_2 && p_list_1[ptr_1] == p_list_2[ptr_2]) {ptr_1++; ptr_2++;}
297  }
298 
299 
300 
301  p_list_1_specific.set_count(found_1);
302  p_list_2_specific.set_count(found_2);
303  if (found_1 > 0 || found_2 > 0)
304  {
305  found_1 = found_2 = 0;
306  ptr_1 = ptr_2 = 0;
307 
308  while(ptr_1 < count_1 || ptr_2 < count_2)
309  {
310  while(ptr_1 < count_1 && (ptr_2 == count_2 || p_list_1[ptr_1] < p_list_2[ptr_2]))
311  {
312  p_list_1_specific[found_1++] = p_list_1[ptr_1];
313  t_size ptr_1_new = ptr_1 + 1;
314  while(ptr_1_new < count_1 && p_list_1[ptr_1_new] == p_list_1[ptr_1]) ptr_1_new++;
315  ptr_1 = ptr_1_new;
316  }
317  while(ptr_2 < count_2 && (ptr_1 == count_1 || p_list_2[ptr_2] < p_list_1[ptr_1]))
318  {
319  p_list_2_specific[found_2++] = p_list_2[ptr_2];
320  t_size ptr_2_new = ptr_2 + 1;
321  while(ptr_2_new < count_2 && p_list_2[ptr_2_new] == p_list_2[ptr_2]) ptr_2_new++;
322  ptr_2 = ptr_2_new;
323  }
324  while(ptr_1 < count_1 && ptr_2 < count_2 && p_list_1[ptr_1] == p_list_2[ptr_2]) {ptr_1++; ptr_2++;}
325  }
326 
327  }
328 }
329 
331 {
332  double ret = 0;
333  t_size n, m = p_list.get_count();
334  for(n=0;n<m;n++)
335  {
336  double temp = p_list.get_item(n)->get_length();
337  if (temp > 0) ret += temp;
338  }
339  return ret;
340 }
341 
343 {
344  sort_by_format(p_list,"%path_sort%",NULL);
345 }
346 
347 
350 // metadb_handle_list list(p_list);
351 // list.sort_t(metadb::path_compare_metadb_handle);
352 
353  t_filesize ret = 0;
354  t_size n, m = p_list.get_count();
355  for(n=0;n<m;n++) {
356  bool isNew;
357  metadb_handle_ptr h; p_list.get_item_ex(h, n);
358  beenHere.add_ex( h->get_path(), isNew);
359  if (isNew) {
360  t_filesize t = h->get_filesize();
361  if (t == filesize_invalid) {
362  if (!skipUnknown) return filesize_invalid;
363  } else {
364  ret += t;
365  }
366  }
367  }
368  return ret;
369 }
370 
372  foundUnknown = false;
373  metadb_handle_list list(p_list);
375 
376  t_filesize ret = 0;
377  t_size n, m = list.get_count();
378  for(n=0;n<m;n++) {
379  if (n==0 || metadb::path_compare(list[n-1]->get_path(),list[n]->get_path())) {
380  t_filesize t = list[n]->get_filesize();
381  if (t == filesize_invalid) {
382  foundUnknown = true;
383  } else {
384  ret += t;
385  }
386  }
387  }
388  return ret;
389 }
390 
392  const t_size total = list.get_count();
393  if (total == 0) return false;
394  const char * path = list[0]->get_path();
395  for(t_size walk = 1; walk < total; ++walk) {
396  if (metadb::path_compare(path, list[walk]->get_path()) != 0) return false;
397  }
398  pathOut = path;
399  return true;
400 }
bool extract_single_path(metadb_handle_list_cref list, const char *&path)
void sort_by_relative_path_get_order(metadb_handle_list_cref p_list, t_size *order)
virtual void sort(sort_callback &p_callback)=0
static int custom_sort_compare(const custom_sort_data &elem1, const custom_sort_data &elem2)
int sgn_t(const T &p_val)
Definition: primitives.h:669
const t_item * get_ptr() const
Definition: array.h:213
static int _cdecl _custom_sort_compare(const void *v1, const void *v2)
void remove_duplicates(pfc::list_base_t< metadb_handle_ptr > &p_list)
t_size estimate_utf8_to_wide(const char *p_in)
int SHARED_EXPORT stricmp_utf8_ex(const char *p1, t_size len1, const char *p2, t_size len2)
void sort_by_pointer(pfc::list_base_t< metadb_handle_ptr > &p_list)
virtual t_size get_param_count()=0
static void g_fill(t_int *p_order, const t_size p_count)
Definition: order_helper.h:38
Generic variable bit_array implementation. Needs to be initialized with requested array size before ...
t_size getOptimalWorkerThreadCountEx(t_size taskCountLimit)
Definition: threads.cpp:45
void 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)
void remove_mask(const bit_array &mask)
Definition: list.h:212
static const t_filesize filesize_invalid
Invalid/unknown file size constant. Also see: t_filesize.
Definition: filesystem.h:16
void sort_by_path_quick(pfc::list_base_t< metadb_handle_ptr > &p_list)
t_size get_count() const
Definition: list.h:365
t_storage & add_ex(const t_param &p_item, bool &p_isnew)
Definition: avltree.h:476
bool bsearch_t(t_compare p_compare, t_param const &p_param, t_size &p_index) const
Definition: list.h:45
void set_count(t_size p_count)
Definition: list.h:315
IMPORTANT: all classes derived from thread must call waitTillDone() in their destructor, to avoid object destruction during a virtual function call!
Definition: threads.h:11
t_size get_param_uint(t_size index)
Definition: titleformat.cpp:98
size_t t_size
Definition: int_types.h:48
void set_size(t_size p_size)
Definition: array.h:104
virtual t_size get_count() const =0
t_size convert_utf8_to_wide_unchecked(wchar_t *p_out, const char *p_in)
double calc_total_duration(const pfc::list_base_const_t< metadb_handle_ptr > &p_list)
virtual void threadProc()
Definition: threads.h:28
static int path_compare(const char *p1, const char *p2)
Definition: metadb.h:245
t_size bsearch_by_pointer(const pfc::list_base_const_t< metadb_handle_ptr > &p_list, const metadb_handle_ptr &val)
void sort_by_format_get_order(metadb_handle_list_cref p_list, t_size *order, const char *spec, titleformat_hook *p_hook)
void reorder(const t_size *p_data)
Definition: list.h:201
static void sort_t(t_container &p_data, t_compare p_compare, t_size p_count)
Definition: sort.h:162
pfc::sized_int_t< sizeof(size_t) >::t_signed t_ssize
Definition: int_types.h:49
t_uint64 t_filesize
Type used for file size related variables.
Definition: filesystem.h:8
void sort_t(t_compare p_compare)
Definition: list.h:237
virtual bool process_field(titleformat_text_out *p_out, const char *p_name, t_size p_name_length, bool &p_found_flag)=0
t_filesize calc_total_size(metadb_handle_list_cref list, bool skipUnknown=false)
t_ret implicit_cast(t_ret val)
Definition: primitives.h:182
void write_int(const GUID &p_inputtype, t_int64 val)
void sort_t(t_compare p_compare)
Definition: list.h:461
void waitTillDone()
Definition: threads.h:21
void sort_by_relative_path(metadb_handle_list_ref p_list)
void sort_get_permutation_t(t_compare p_compare, t_permutation const &p_permutation) const
Definition: list.h:55
virtual 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)=0
Helper template used to easily access core services. Usage: static_api_ptr_t api; api->doso...
Definition: service.h:533
virtual void get_item_ex(T &p_out, t_size n) const =0
static int path_compare_metadb_handle(const metadb_handle_ptr &p1, const metadb_handle_ptr &p2)
Definition: metadb.h:246
t_filesize calc_total_size_ex(metadb_handle_list_cref list, bool &foundUnknown)
t_size get_size() const
Definition: array.h:130
void sort_by_path(pfc::list_base_t< metadb_handle_ptr > &p_list)
void sort_by_pointer_remove_duplicates(pfc::list_base_t< metadb_handle_ptr > &p_list)
string8_t< pfc::alloc_fast_aggressive > string8_fastalloc
Definition: string_base.h:435
T get_item(t_size n) const
Definition: list.h:16
uint32_t t_uint32
Definition: int_types.h:5
void sort_by_format(metadb_handle_list_ref p_list, const char *spec, titleformat_hook *p_hook)