1
0

nde_itemRecord.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /*
  2. ** Copyright © 2003-2014 Winamp SA
  3. **
  4. ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
  5. ** liable for any damages arising from the use of this software.
  6. **
  7. ** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
  8. ** alter it and redistribute it freely, subject to the following restrictions:
  9. **
  10. ** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
  11. ** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  12. **
  13. ** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  14. **
  15. ** 3. This notice may not be removed or altered from any source distribution.
  16. **
  17. */
  18. #include <windows.h>
  19. #include "../../General/gen_ml/ml.h"
  20. #include "../nde/nde.h"
  21. #include "../nu/sort.h"
  22. void freeRecord(itemRecord *p)
  23. {
  24. if (p)
  25. {
  26. free(p->title);
  27. free( p->artist );
  28. free( p->ext );
  29. free(p->comment);
  30. free(p->album);
  31. free(p->genre);
  32. free(p->filename);
  33. if (p->extended_info)
  34. {
  35. for (size_t x = 0; p->extended_info[x]; x ++)
  36. free(p->extended_info[x]);
  37. free(p->extended_info);
  38. p->extended_info = 0;
  39. }
  40. }
  41. }
  42. void freeRecordList(itemRecordList *obj)
  43. {
  44. if (obj)
  45. {
  46. emptyRecordList(obj);
  47. _aligned_free(obj->Items);
  48. obj->Items=0;
  49. obj->Alloc=obj->Size=0;
  50. }
  51. }
  52. void emptyRecordList(itemRecordList *obj)
  53. {
  54. if (obj)
  55. {
  56. itemRecord *p=obj->Items;
  57. while (obj->Size-->0)
  58. {
  59. freeRecord(p);
  60. p++;
  61. }
  62. obj->Size=0;
  63. }
  64. }
  65. void allocRecordList(itemRecordList *obj, int newsize, int granularity)
  66. {
  67. if (newsize < obj->Alloc || newsize < obj->Size) return;
  68. int old_Alloc = obj->Alloc;
  69. obj->Alloc=newsize+granularity;
  70. itemRecord *data = (itemRecord*)_aligned_realloc(obj->Items, sizeof(itemRecord) * obj->Alloc, 16);
  71. if (!data)
  72. {
  73. data = (itemRecord*)_aligned_malloc(sizeof(itemRecord) * obj->Alloc, 16);
  74. if (data)
  75. {
  76. memcpy(data, obj->Items, sizeof(itemRecord) * old_Alloc);
  77. _aligned_free(obj->Items);
  78. obj->Items = data;
  79. }
  80. else
  81. obj->Alloc = old_Alloc;
  82. }
  83. else
  84. obj->Items = data;
  85. if (!obj->Items) obj->Alloc=0;
  86. }
  87. void compactRecordList(itemRecordListW *obj)
  88. {
  89. if (obj->Size && obj->Size < obj->Alloc - 1024)
  90. {
  91. size_t old_Alloc = obj->Size;
  92. obj->Alloc = obj->Size;
  93. itemRecordW *data = (itemRecordW *)_aligned_realloc(obj->Items, sizeof(itemRecordW) * obj->Alloc, 16);
  94. if (!data)
  95. {
  96. data = (itemRecordW *)_aligned_malloc(sizeof(itemRecordW) * obj->Alloc, 16);
  97. if (data)
  98. {
  99. memcpy(data, obj->Items, sizeof(itemRecordW) * old_Alloc);
  100. _aligned_free(obj->Items);
  101. obj->Items = data;
  102. }
  103. else
  104. obj->Alloc = old_Alloc;
  105. }
  106. else
  107. obj->Items = data;
  108. }
  109. }
  110. void copyRecord(itemRecord *out, const itemRecord *in)
  111. {
  112. #define COPYSTR(FOO) out->FOO = in->FOO ? _strdup(in->FOO) : 0;
  113. COPYSTR(filename)
  114. COPYSTR(title)
  115. COPYSTR(ext)
  116. COPYSTR(album)
  117. COPYSTR(artist)
  118. COPYSTR(comment)
  119. COPYSTR(genre)
  120. out->year=in->year;
  121. out->track=in->track;
  122. out->length=in->length;
  123. #undef COPYSTR
  124. out->extended_info=0;
  125. if (in->extended_info)
  126. {
  127. for (int y = 0; in->extended_info[y]; y ++)
  128. {
  129. char *p=in->extended_info[y];
  130. if (*p) setRecordExtendedItem(out,p,p+strlen(p)+1);
  131. }
  132. }
  133. }
  134. void copyRecordList(itemRecordList *out, const itemRecordList *in)
  135. {
  136. allocRecordList(out,out->Size+in->Size,0);
  137. if (!out->Items) return;
  138. for (int x = 0; x < in->Size; x ++)
  139. {
  140. copyRecord(&out->Items[out->Size++],&in->Items[x]);
  141. }
  142. }
  143. char *getRecordExtendedItem(const itemRecord *item, const char *name)
  144. {
  145. if (item->extended_info)
  146. {
  147. for (size_t x = 0; item->extended_info[x]; x ++)
  148. {
  149. if (!_stricmp(item->extended_info[x],name))
  150. return item->extended_info[x]+strlen(name)+1;
  151. }
  152. }
  153. return NULL;
  154. }
  155. void setRecordExtendedItem(itemRecord *item, const char *name, char *value)
  156. {
  157. if (!item || !name) return;
  158. size_t x = 0;
  159. if (item->extended_info)
  160. {
  161. for (x = 0; item->extended_info[x]; x ++)
  162. {
  163. if (!_stricmp(item->extended_info[x],name))
  164. {
  165. size_t name_len = strlen(name), value_len = strlen(value);
  166. if (value_len>strlen(item->extended_info[x]+name_len+1))
  167. {
  168. free(item->extended_info[x]);
  169. item->extended_info[x]=(char*)malloc(name_len+value_len+2);
  170. }
  171. strncpy(item->extended_info[x], name, name_len);
  172. strncpy(item->extended_info[x]+strlen(name)+1, value, value_len);
  173. return;
  174. }
  175. }
  176. }
  177. // x=number of valid items.
  178. char **data = (char**)realloc(item->extended_info,sizeof(char*) * (x+2));
  179. if (data)
  180. {
  181. // if we could allocate then add, otherwise we'll have to skip
  182. item->extended_info = data;
  183. size_t name_len = strlen(name), value_len = strlen(value);
  184. item->extended_info[x]=(char*)malloc(name_len+value_len+2);
  185. strncpy(item->extended_info[x], name, name_len);
  186. strncpy(item->extended_info[x]+name_len+1, value, value_len);
  187. item->extended_info[x+1]=0;
  188. }
  189. else
  190. {
  191. data = (char**)malloc(sizeof(char*) * (x+2));
  192. if (data)
  193. {
  194. memcpy(data, item->extended_info, sizeof(char*) * x);
  195. free(item->extended_info);
  196. // if we could allocate then add, otherwise we'll have to skip
  197. item->extended_info = data;
  198. size_t name_len = strlen(name), value_len = strlen(value);
  199. item->extended_info[x]=(char*)malloc(name_len+value_len+2);
  200. strncpy(item->extended_info[x], name, name_len);
  201. strncpy(item->extended_info[x]+name_len+1, value, value_len);
  202. item->extended_info[x+1]=0;
  203. }
  204. }
  205. }
  206. /*
  207. ----------------------------------
  208. wide version starts here
  209. ----------------------------------
  210. */
  211. void freeRecord(itemRecordW *p)
  212. {
  213. if (p)
  214. {
  215. ndestring_release(p->title);
  216. ndestring_release(p->artist);
  217. ndestring_release(p->comment);
  218. ndestring_release(p->album);
  219. ndestring_release(p->genre);
  220. ndestring_release(p->filename);
  221. ndestring_release(p->albumartist);
  222. ndestring_release(p->replaygain_album_gain);
  223. ndestring_release(p->replaygain_track_gain);
  224. ndestring_release(p->publisher);
  225. ndestring_release(p->composer);
  226. if (p->extended_info)
  227. {
  228. for (size_t x = 0; p->extended_info[x].key; x ++)
  229. {
  230. // TODO release 'key' ?
  231. // ndestring_release(p->extended_info[x].key);
  232. ndestring_release(p->extended_info[x].value);
  233. }
  234. free(p->extended_info);
  235. p->extended_info = 0;
  236. }
  237. }
  238. }
  239. void freeRecordList(itemRecordListW *obj)
  240. {
  241. if (obj)
  242. {
  243. emptyRecordList(obj);
  244. _aligned_free(obj->Items);
  245. obj->Items=0;
  246. obj->Alloc=obj->Size=0;
  247. }
  248. }
  249. void emptyRecordList(itemRecordListW *obj)
  250. {
  251. if (obj)
  252. {
  253. itemRecordW *p=obj->Items;
  254. while (obj->Size-->0)
  255. {
  256. freeRecord(p);
  257. p++;
  258. }
  259. obj->Size=0;
  260. }
  261. }
  262. void allocRecordList(itemRecordListW *obj, int newsize, int granularity)
  263. {
  264. if (newsize < obj->Alloc || newsize < obj->Size) return;
  265. int old_Alloc = obj->Alloc;
  266. obj->Alloc=newsize+granularity;
  267. itemRecordW *data = (itemRecordW*)_aligned_realloc(obj->Items,sizeof(itemRecordW)*obj->Alloc, 16);
  268. if (!data)
  269. {
  270. data = (itemRecordW*)_aligned_malloc(sizeof(itemRecordW) * obj->Alloc, 16);
  271. if (data)
  272. {
  273. memcpy(data, obj->Items, sizeof(itemRecordW) * obj->Alloc);
  274. _aligned_free(obj->Items);
  275. obj->Items = data;
  276. }
  277. else
  278. obj->Alloc = old_Alloc;
  279. }
  280. else
  281. obj->Items = data;
  282. if (!obj->Items) obj->Alloc=0;
  283. }
  284. #if 0 // unused, don't re-enable until you verify the TODO below
  285. void copyRecord(itemRecordW *out, const itemRecordW *in)
  286. {
  287. #define COPYSTR(FOO) out->FOO = in->FOO ? _wcsdup(in->FOO) : 0;
  288. #define COPY(FOO) out->FOO = in->FOO;
  289. /* this is only valid if 'in' is one of our item records! */
  290. out->filename = in->filename;
  291. NDEString *ndeString = WCHAR_TO_NDESTRING(out->filename);
  292. if (ndeString) ndeString->Retain();
  293. COPYSTR(title)
  294. COPYSTR(album)
  295. COPYSTR(artist)
  296. COPYSTR(comment)
  297. COPYSTR(genre)
  298. COPYSTR(albumartist);
  299. COPYSTR(replaygain_album_gain);
  300. COPYSTR(replaygain_track_gain);
  301. COPYSTR(publisher);
  302. COPYSTR(composer);
  303. COPY(year);
  304. COPY(track);
  305. COPY(tracks);
  306. COPY(length);
  307. COPY(rating);
  308. COPY(playcount);
  309. COPY(lastplay);
  310. COPY(lastupd);
  311. COPY(filetime);
  312. COPY(filesize);
  313. COPY(bitrate);
  314. COPY(type);
  315. COPY(disc);
  316. COPY(discs);
  317. COPY(bpm);
  318. COPYSTR(category);
  319. #undef COPYSTR
  320. out->extended_info=0;
  321. if (in->extended_info)
  322. {
  323. for (int y = 0; in->extended_info[y].key; y ++)
  324. {
  325. setRecordExtendedItem(out,in->extended_info[y].key,in->extended_info[y].value);
  326. }
  327. }
  328. }
  329. void copyRecordList(itemRecordListW *out, const itemRecordListW *in)
  330. {
  331. allocRecordList(out,out->Size+in->Size,0);
  332. if (!out->Items) return;
  333. for (size_t x = 0; x < in->Size; x ++)
  334. {
  335. copyRecord(&out->Items[out->Size++],&in->Items[x]);
  336. }
  337. }
  338. #endif
  339. wchar_t *getRecordExtendedItem(const itemRecordW *item, const wchar_t *name)
  340. {
  341. if (item && item->extended_info && name)
  342. {
  343. for (size_t x = 0; item->extended_info[x].key; x ++)
  344. {
  345. if (!_wcsicmp(item->extended_info[x].key,name))
  346. return item->extended_info[x].value;
  347. }
  348. }
  349. return NULL;
  350. }
  351. wchar_t *getRecordExtendedItem_fast(const itemRecordW *item, const wchar_t *name)
  352. {
  353. if (item && item->extended_info && name)
  354. {
  355. for (size_t x = 0; item->extended_info[x].key; x ++)
  356. {
  357. if (item->extended_info[x].key == name)
  358. return item->extended_info[x].value;
  359. }
  360. }
  361. return NULL;
  362. }
  363. void setRecordExtendedItem(itemRecordW *item, const wchar_t *name, const wchar_t *value)
  364. {
  365. if (!item || !name) return;
  366. size_t x=0;
  367. if (item->extended_info) for (x = 0; item->extended_info[x].key; x ++)
  368. {
  369. if (item->extended_info[x].key == name)
  370. {
  371. ndestring_retain(const_cast<wchar_t *>(value));
  372. ndestring_release(item->extended_info[x].value);
  373. item->extended_info[x].value = const_cast<wchar_t *>(value);
  374. return;
  375. }
  376. }
  377. // x=number of valid items.
  378. extendedInfoW *data=(extendedInfoW *)realloc(item->extended_info,sizeof(extendedInfoW) * (x+2));
  379. if (data)
  380. {
  381. item->extended_info=data;
  382. item->extended_info[x].key = const_cast<wchar_t *>(name);
  383. ndestring_retain(const_cast<wchar_t *>(value));
  384. item->extended_info[x].value = const_cast<wchar_t *>(value);
  385. item->extended_info[x+1].key=0;
  386. item->extended_info[x+1].value=0;
  387. }
  388. else
  389. {
  390. data=(extendedInfoW *)malloc(sizeof(extendedInfoW) * (x+2));
  391. if (data)
  392. {
  393. item->extended_info=data;
  394. item->extended_info[x].key = const_cast<wchar_t *>(name);
  395. ndestring_retain(const_cast<wchar_t *>(value));
  396. item->extended_info[x].value = const_cast<wchar_t *>(value);
  397. item->extended_info[x+1].key=0;
  398. item->extended_info[x+1].value=0;
  399. }
  400. }
  401. }
  402. // this version assumes that the 'name' won't already be in the itemRecord
  403. void setRecordExtendedItem_fast(itemRecordW *item, const wchar_t *name, const wchar_t *value)
  404. {
  405. if (!item || !name) return;
  406. size_t x = 0;
  407. if (item->extended_info)
  408. {
  409. for (x = 0; item->extended_info[x].key; x++)
  410. {
  411. }
  412. }
  413. // x=number of valid items.
  414. extendedInfoW *data=(extendedInfoW *)realloc(item->extended_info,sizeof(extendedInfoW) * (x+2));
  415. if (data)
  416. {
  417. item->extended_info = data;
  418. item->extended_info[x].key = const_cast<wchar_t *>(name);
  419. ndestring_retain(const_cast<wchar_t *>(value));
  420. item->extended_info[x].value = const_cast<wchar_t *>(value);
  421. item->extended_info[x+1].key=0;
  422. item->extended_info[x+1].value=0;
  423. }
  424. else
  425. {
  426. data=(extendedInfoW *)malloc(sizeof(extendedInfoW) * (x+2));
  427. if (data)
  428. {
  429. item->extended_info=data;
  430. item->extended_info[x].key = const_cast<wchar_t *>(name);
  431. ndestring_retain(const_cast<wchar_t *>(value));
  432. item->extended_info[x].value = const_cast<wchar_t *>(value);
  433. item->extended_info[x+1].key=0;
  434. item->extended_info[x+1].value=0;
  435. }
  436. }
  437. }
  438. // TODO: redo this without AutoChar
  439. #include "../replicant/nu/AutoChar.h"
  440. #include "../nu/AutoCharFn.h"
  441. #define COPY_EXTENDED_STR(field) if (input-> ## field && input-> ## field ## [0]) setRecordExtendedItem(output, #field, AutoChar(input-> ## field));
  442. #define COPY_EXTENDED_INT(field) if (input->##field > 0) { char temp[64] = {0}; _itoa(input->##field, temp, 10); setRecordExtendedItem(output, #field, temp); }
  443. #define COPY_EXTENDED_INT64(field) if (input->##field > 0) { char temp[64] = {0}; _i64toa(input->##field, temp, 10); setRecordExtendedItem(output, #field, temp); }
  444. #define COPY_EXTENDED_INT0(field) if (input->##field >= 0) { char temp[64] = {0}; _itoa(input->##field, temp, 10); setRecordExtendedItem(output, #field, temp); }
  445. void convertRecord(itemRecord *output, const itemRecordW *input)
  446. {
  447. output->filename=_strdup(AutoCharFn(input->filename));
  448. output->title=AutoCharDup(input->title);
  449. output->ext=AutoCharDup(input->ext);
  450. output->album=AutoCharDup(input->album);
  451. output->artist=AutoCharDup(input->artist);
  452. output->comment=AutoCharDup(input->comment);
  453. output->genre=AutoCharDup(input->genre);
  454. output->year=input->year;
  455. output->track=input->track;
  456. output->length=input->length;
  457. output->extended_info=0;
  458. COPY_EXTENDED_STR(albumartist);
  459. COPY_EXTENDED_STR(replaygain_album_gain);
  460. COPY_EXTENDED_STR(replaygain_track_gain);
  461. COPY_EXTENDED_STR(publisher);
  462. COPY_EXTENDED_STR(composer);
  463. COPY_EXTENDED_INT(tracks);
  464. COPY_EXTENDED_INT(rating);
  465. COPY_EXTENDED_INT(playcount);
  466. COPY_EXTENDED_INT64(lastplay);
  467. COPY_EXTENDED_INT64(lastupd);
  468. COPY_EXTENDED_INT64(filetime);
  469. COPY_EXTENDED_INT(filesize);
  470. COPY_EXTENDED_INT(bitrate);
  471. COPY_EXTENDED_INT0(type);
  472. COPY_EXTENDED_INT(disc);
  473. COPY_EXTENDED_INT(discs);
  474. COPY_EXTENDED_INT(bpm);
  475. COPY_EXTENDED_STR(category);
  476. if (input->extended_info)
  477. {
  478. for (int y = 0; input->extended_info[y].key; y ++)
  479. {
  480. setRecordExtendedItem(output, AutoChar(input->extended_info[y].key), AutoChar(input->extended_info[y].value));
  481. }
  482. }
  483. }
  484. #undef COPY_EXTENDED_STR
  485. #undef COPY_EXTENDED_INT
  486. #undef COPY_EXTENDED_INT0
  487. #include "../replicant/nu/AutoWide.h"
  488. #define COPY_EXTENDED_STR(field) output->##field = ndestring_wcsdup(AutoWideDup(getRecordExtendedItem(input, #field)));
  489. #define COPY_EXTENDED_INT(field) { char *x = getRecordExtendedItem(input, #field); output->##field=x?atoi(x):-1; }
  490. void convertRecord(itemRecordW *output, const itemRecord *input)
  491. {
  492. output->filename=ndestring_wcsdup(AutoWideDup(input->filename));
  493. output->title=ndestring_wcsdup(AutoWideDup(input->title));
  494. output->ext=ndestring_wcsdup(AutoWideDup(input->ext));
  495. output->album=ndestring_wcsdup(AutoWideDup(input->album));
  496. output->artist=ndestring_wcsdup(AutoWideDup(input->artist));
  497. output->comment=ndestring_wcsdup(AutoWideDup(input->comment));
  498. output->genre=ndestring_wcsdup(AutoWideDup(input->genre));
  499. output->year=input->year;
  500. output->track=input->track;
  501. output->length=input->length;
  502. output->extended_info=0;
  503. COPY_EXTENDED_STR(albumartist);
  504. COPY_EXTENDED_STR(replaygain_album_gain);
  505. COPY_EXTENDED_STR(replaygain_track_gain);
  506. COPY_EXTENDED_STR(publisher);
  507. COPY_EXTENDED_STR(composer);
  508. COPY_EXTENDED_INT(tracks);
  509. COPY_EXTENDED_INT(rating);
  510. COPY_EXTENDED_INT(playcount);
  511. COPY_EXTENDED_INT(lastplay);
  512. COPY_EXTENDED_INT(lastupd);
  513. COPY_EXTENDED_INT(filetime);
  514. COPY_EXTENDED_INT(filesize);
  515. COPY_EXTENDED_INT(type);
  516. COPY_EXTENDED_INT(disc);
  517. COPY_EXTENDED_INT(discs);
  518. COPY_EXTENDED_INT(bpm);
  519. COPY_EXTENDED_INT(bitrate);
  520. COPY_EXTENDED_STR(composer);
  521. COPY_EXTENDED_STR(category);
  522. // TODO: copy input's extended fields
  523. }
  524. #undef COPY_EXTENDED_STR
  525. #undef COPY_EXTENDED_INT
  526. void convertRecordList(itemRecordList *output, const itemRecordListW *input)
  527. {
  528. output->Alloc = output->Size = input->Size;
  529. output->Items = (itemRecord*)_aligned_malloc(sizeof(itemRecord)*input->Size, 16);
  530. if (output->Items)
  531. {
  532. memset(output->Items, 0, sizeof(itemRecord)*input->Size);
  533. for(int i=0; i < input->Size; i++)
  534. {
  535. convertRecord(&output->Items[i],&input->Items[i]);
  536. }
  537. }
  538. else
  539. output->Alloc = output->Size = 0;
  540. }
  541. void convertRecordList(itemRecordListW *output, const itemRecordList *input)
  542. {
  543. output->Alloc = output->Size = input->Size;
  544. output->Items = (itemRecordW*)malloc(sizeof(itemRecordW) * input->Size);
  545. if (output->Items)
  546. {
  547. memset(output->Items, 0, sizeof(itemRecordW) * input->Size);
  548. for(int i=0; i < input->Size; i++)
  549. {
  550. convertRecord(&output->Items[i],&input->Items[i]);
  551. }
  552. }
  553. }
  554. extern int sse_flag;
  555. // swaps two 16 byte aligned 128-byte values
  556. #ifdef _M_X64
  557. #include <emmintrin.h>
  558. #endif
  559. static void __fastcall swap128(uint8_t *_a, uint8_t *_b)
  560. {
  561. // ECX = a
  562. // EDX = b
  563. #ifdef _M_IX86
  564. _asm
  565. {
  566. // load first 64 bytes of each
  567. movaps xmm0, XMMWORD PTR [ecx+0]
  568. movaps xmm1, XMMWORD PTR [ecx+16]
  569. movaps xmm2, XMMWORD PTR [ecx+32]
  570. movaps xmm3, XMMWORD PTR [ecx+48]
  571. movaps xmm4, XMMWORD PTR [edx+0]
  572. movaps xmm5, XMMWORD PTR [edx+16]
  573. movaps xmm6, XMMWORD PTR [edx+32]
  574. movaps xmm7, XMMWORD PTR [edx+48]
  575. // store
  576. movaps XMMWORD PTR [edx+0], xmm0
  577. movaps XMMWORD PTR [edx+16], xmm1
  578. movaps XMMWORD PTR [edx+32], xmm2
  579. movaps XMMWORD PTR [edx+48], xmm3
  580. movaps XMMWORD PTR [ecx+0], xmm4
  581. movaps XMMWORD PTR [ecx+16], xmm5
  582. movaps XMMWORD PTR [ecx+32], xmm6
  583. movaps XMMWORD PTR [ecx+48], xmm7
  584. // load second 64 bytes of each
  585. movaps xmm0, XMMWORD PTR [ecx+64]
  586. movaps xmm1, XMMWORD PTR [ecx+80]
  587. movaps xmm2, XMMWORD PTR [ecx+96]
  588. movaps xmm3, XMMWORD PTR [ecx+112]
  589. movaps xmm4, XMMWORD PTR [edx+64]
  590. movaps xmm5, XMMWORD PTR [edx+80]
  591. movaps xmm6, XMMWORD PTR [edx+96]
  592. movaps xmm7, XMMWORD PTR [edx+112]
  593. // store
  594. movaps XMMWORD PTR [edx+64], xmm0
  595. movaps XMMWORD PTR [edx+80], xmm1
  596. movaps XMMWORD PTR [edx+96], xmm2
  597. movaps XMMWORD PTR [edx+112], xmm3
  598. movaps XMMWORD PTR [ecx+64], xmm4
  599. movaps XMMWORD PTR [ecx+80], xmm5
  600. movaps XMMWORD PTR [ecx+96], xmm6
  601. movaps XMMWORD PTR [ecx+112], xmm7
  602. }
  603. #else
  604. //sizeof(itemRecordW) is 176 on AMD64. that's 11 SSE registers
  605. __m128i b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10;
  606. __m128i a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  607. __m128i *a = (__m128i *)_a;
  608. __m128i *b = (__m128i *)_b;
  609. a0 = _mm_load_si128(&a[0]);
  610. a1 = _mm_load_si128(&a[1]);
  611. a2 = _mm_load_si128(&a[2]);
  612. a3 = _mm_load_si128(&a[3]);
  613. a4 = _mm_load_si128(&a[4]);
  614. a5 = _mm_load_si128(&a[5]);
  615. a6 = _mm_load_si128(&a[6]);
  616. a7 = _mm_load_si128(&a[7]);
  617. a8 = _mm_load_si128(&a[0]);
  618. a9 = _mm_load_si128(&a[1]);
  619. a10 = _mm_load_si128(&a[2]);
  620. b0 = _mm_load_si128(&b[0]);
  621. b1 = _mm_load_si128(&b[1]);
  622. b2 = _mm_load_si128(&b[2]);
  623. b3 = _mm_load_si128(&b[3]);
  624. b4 = _mm_load_si128(&b[4]);
  625. b5 = _mm_load_si128(&b[5]);
  626. b6 = _mm_load_si128(&b[6]);
  627. b7 = _mm_load_si128(&b[7]);
  628. b8 = _mm_load_si128(&b[8]);
  629. b9 = _mm_load_si128(&b[9]);
  630. b10 = _mm_load_si128(&b[10]);
  631. _mm_store_si128(&a[0], b0);
  632. _mm_store_si128(&a[1], b1);
  633. _mm_store_si128(&a[2], b2);
  634. _mm_store_si128(&a[3], b3);
  635. _mm_store_si128(&a[4], b4);
  636. _mm_store_si128(&a[5], b5);
  637. _mm_store_si128(&a[6], b6);
  638. _mm_store_si128(&a[7], b7);
  639. _mm_store_si128(&b[0], a0);
  640. _mm_store_si128(&b[1], a1);
  641. _mm_store_si128(&b[2], a2);
  642. _mm_store_si128(&b[3], a3);
  643. _mm_store_si128(&b[4], a4);
  644. _mm_store_si128(&b[5], a5);
  645. _mm_store_si128(&b[6], a6);
  646. _mm_store_si128(&b[7], a7);
  647. #endif
  648. }
  649. /***
  650. *shortsort(hi, lo, width, comp) - insertion sort for sorting short arrays
  651. *
  652. *Purpose:
  653. * sorts the sub-array of elements between lo and hi (inclusive)
  654. * side effects: sorts in place
  655. * assumes that lo < hi
  656. *
  657. *Entry:
  658. * char *lo = pointer to low element to sort
  659. * char *hi = pointer to high element to sort
  660. * size_t width = width in bytes of each array element
  661. * int (*comp)() = pointer to function returning analog of strcmp for
  662. * strings, but supplied by user for comparing the array elements.
  663. * it accepts 2 pointers to elements and returns neg if 1<2, 0 if
  664. * 1=2, pos if 1>2.
  665. *
  666. *Exit:
  667. * returns void
  668. *
  669. *Exceptions:
  670. *
  671. *******************************************************************************/
  672. static void shortsort_sse(uint8_t *lo, uint8_t *hi, const void *context,
  673. int (__fastcall *comp)(const void *, const void *, const void *))
  674. {
  675. const size_t width=sizeof(itemRecordW);
  676. uint8_t *p;
  677. /* Note: in assertions below, i and j are alway inside original bound of
  678. array to sort. */
  679. while (hi > lo) {
  680. /* A[i] <= A[j] for i <= j, j > hi */
  681. uint8_t *max = lo;
  682. for (p = lo+width; p <= hi; p += width) {
  683. /* A[i] <= A[max] for lo <= i < p */
  684. if (comp(p, max, context) > 0) {
  685. max = p;
  686. }
  687. /* A[i] <= A[max] for lo <= i <= p */
  688. }
  689. /* A[i] <= A[max] for lo <= i <= hi */
  690. swap128(max, hi);
  691. /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
  692. hi -= width;
  693. /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
  694. }
  695. /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
  696. so array is sorted */
  697. }
  698. #define CUTOFF 8
  699. #define STKSIZ (8*sizeof(void*) - 2)
  700. extern "C" void qsort_itemRecord(void *base, size_t num, const void *context,
  701. int (__fastcall *comp)(const void *, const void *, const void *))
  702. {
  703. /* Note: the number of stack entries required is no more than
  704. 1 + log2(num), so 30 is sufficient for any array */
  705. uint8_t *lo, *hi; /* ends of sub-array currently sorting */
  706. uint8_t *mid; /* points to middle of subarray */
  707. uint8_t *loguy, *higuy; /* traveling pointers for partition step */
  708. size_t size; /* size of the sub-array */
  709. uint8_t *lostk[STKSIZ], *histk[STKSIZ];
  710. int stkptr; /* stack for saving sub-array to be processed */
  711. const size_t width=sizeof(itemRecordW);
  712. #ifdef _M_IX86
  713. assert(sizeof(itemRecordW) == 128);
  714. #elif defined (_M_X64)
  715. assert(sizeof(itemRecordW) == 176);
  716. #else
  717. #error not implemented on this processor!
  718. #endif
  719. if (!sse_flag)
  720. {
  721. nu::qsort(base, num, sizeof(itemRecordW), context, comp);
  722. return;
  723. }
  724. if (num < 2)
  725. return; /* nothing to do */
  726. stkptr = 0; /* initialize stack */
  727. lo = static_cast<uint8_t *>(base);
  728. hi = (uint8_t *)base + width * (num-1); /* initialize limits */
  729. /* this entry point is for pseudo-recursion calling: setting
  730. lo and hi and jumping to here is like recursion, but stkptr is
  731. preserved, locals aren't, so we preserve stuff on the stack */
  732. recurse:
  733. size = (hi - lo) / width + 1; /* number of el's to sort */
  734. /* below a certain size, it is faster to use a O(n^2) sorting method */
  735. if (size <= CUTOFF) {
  736. shortsort_sse(lo, hi, context, comp);
  737. }
  738. else {
  739. /* First we pick a partitioning element. The efficiency of the
  740. algorithm demands that we find one that is approximately the median
  741. of the values, but also that we select one fast. We choose the
  742. median of the first, middle, and last elements, to avoid bad
  743. performance in the face of already sorted data, or data that is made
  744. up of multiple sorted runs appended together. Testing shows that a
  745. median-of-three algorithm provides better performance than simply
  746. picking the middle element for the latter case. */
  747. mid = lo + (size / 2) * width; /* find middle element */
  748. /* Sort the first, middle, last elements into order */
  749. if (comp(lo, mid, context) > 0) {
  750. swap128(lo, mid);
  751. }
  752. if (comp(lo, hi, context) > 0) {
  753. swap128(lo, hi);
  754. }
  755. if (comp(mid, hi, context) > 0) {
  756. swap128(mid, hi);
  757. }
  758. /* We now wish to partition the array into three pieces, one consisting
  759. of elements <= partition element, one of elements equal to the
  760. partition element, and one of elements > than it. This is done
  761. below; comments indicate conditions established at every step. */
  762. loguy = lo;
  763. higuy = hi;
  764. /* Note that higuy decreases and loguy increases on every iteration,
  765. so loop must terminate. */
  766. for (;;) {
  767. /* lo <= loguy < hi, lo < higuy <= hi,
  768. A[i] <= A[mid] for lo <= i <= loguy,
  769. A[i] > A[mid] for higuy <= i < hi,
  770. A[hi] >= A[mid] */
  771. /* The doubled loop is to avoid calling comp(mid,mid), since some
  772. existing comparison funcs don't work when passed the same
  773. value for both pointers. */
  774. if (mid > loguy) {
  775. do {
  776. loguy += width;
  777. } while (loguy < mid && comp(loguy, mid, context) <= 0);
  778. }
  779. if (mid <= loguy) {
  780. do {
  781. loguy += width;
  782. } while (loguy <= hi && comp(loguy, mid, context) <= 0);
  783. }
  784. /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,
  785. either loguy > hi or A[loguy] > A[mid] */
  786. do {
  787. higuy -= width;
  788. } while (higuy > mid && comp(higuy, mid, context) > 0);
  789. /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,
  790. either higuy == lo or A[higuy] <= A[mid] */
  791. if (higuy < loguy)
  792. break;
  793. /* if loguy > hi or higuy == lo, then we would have exited, so
  794. A[loguy] > A[mid], A[higuy] <= A[mid],
  795. loguy <= hi, higuy > lo */
  796. swap128(loguy, higuy);
  797. /* If the partition element was moved, follow it. Only need
  798. to check for mid == higuy, since before the swap,
  799. A[loguy] > A[mid] implies loguy != mid. */
  800. if (mid == higuy)
  801. mid = loguy;
  802. /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top
  803. of loop is re-established */
  804. }
  805. /* A[i] <= A[mid] for lo <= i < loguy,
  806. A[i] > A[mid] for higuy < i < hi,
  807. A[hi] >= A[mid]
  808. higuy < loguy
  809. implying:
  810. higuy == loguy-1
  811. or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */
  812. /* Find adjacent elements equal to the partition element. The
  813. doubled loop is to avoid calling comp(mid,mid), since some
  814. existing comparison funcs don't work when passed the same value
  815. for both pointers. */
  816. higuy += width;
  817. if (mid < higuy) {
  818. do {
  819. higuy -= width;
  820. } while (higuy > mid && comp(higuy, mid, context) == 0);
  821. }
  822. if (mid >= higuy) {
  823. do {
  824. higuy -= width;
  825. } while (higuy > lo && comp(higuy, mid, context) == 0);
  826. }
  827. /* OK, now we have the following:
  828. higuy < loguy
  829. lo <= higuy <= hi
  830. A[i] <= A[mid] for lo <= i <= higuy
  831. A[i] == A[mid] for higuy < i < loguy
  832. A[i] > A[mid] for loguy <= i < hi
  833. A[hi] >= A[mid] */
  834. /* We've finished the partition, now we want to sort the subarrays
  835. [lo, higuy] and [loguy, hi].
  836. We do the smaller one first to minimize stack usage.
  837. We only sort arrays of length 2 or more.*/
  838. if ( higuy - lo >= hi - loguy ) {
  839. if (lo < higuy) {
  840. lostk[stkptr] = lo;
  841. histk[stkptr] = higuy;
  842. ++stkptr;
  843. } /* save big recursion for later */
  844. if (loguy < hi) {
  845. lo = loguy;
  846. goto recurse; /* do small recursion */
  847. }
  848. }
  849. else {
  850. if (loguy < hi) {
  851. lostk[stkptr] = loguy;
  852. histk[stkptr] = hi;
  853. ++stkptr; /* save big recursion for later */
  854. }
  855. if (lo < higuy) {
  856. hi = higuy;
  857. goto recurse; /* do small recursion */
  858. }
  859. }
  860. }
  861. /* We have sorted the array, except for any pending sorts on the stack.
  862. Check if there are any, and do them. */
  863. --stkptr;
  864. if (stkptr >= 0) {
  865. lo = lostk[stkptr];
  866. hi = histk[stkptr];
  867. goto recurse; /* pop subarray from stack */
  868. }
  869. else
  870. return; /* all subarrays done */
  871. }