rtlnewkey.cpp 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725
  1. /*##############################################################################
  2. you may not use this file except in compliance with the License.
  3. You may obtain a copy of the License at
  4. http://www.apache.org/licenses/LICENSE-2.0
  5. Unless required by applicable law or agreed to in writing, software
  6. distributed under the License is distributed on an "AS IS" BASIS,
  7. WITHOUT WARRANTIES OR getValue OF ANY KIND, either express or implied.
  8. See the License for the specific language governing permissions and
  9. limitations under the License.
  10. ############################################################################## */
  11. #include <initializer_list>
  12. #include "jlib.hpp"
  13. #include "jdebug.hpp"
  14. #include "jsort.hpp"
  15. #include "jexcept.hpp"
  16. #include "rtlnewkey.hpp"
  17. #include "eclrtl_imp.hpp"
  18. #include "rtlrecord.hpp"
  19. #include "rtlkey.hpp"
  20. #include "rtlnewkey.hpp"
  21. /*
  22. * Read a single quoted string from in until the terminating quote is found
  23. *
  24. * @param out The resulting string with embedded escaped quote characters resolved.
  25. * @param in A reference to the start of the string. Updated to point to the end of the string.
  26. *
  27. */
  28. static void readString(StringBuffer &out, const char * &in)
  29. {
  30. const char *start = in;
  31. // Find terminating quote, skipping any escaped ones
  32. for (;;)
  33. {
  34. char c = *in++;
  35. if (!c)
  36. throw MakeStringException(0, "Invalid filter - missing closing '");
  37. if (c=='\'')
  38. break;
  39. if (c=='\\')
  40. c = *in++;
  41. }
  42. StringBuffer errmsg;
  43. unsigned errpos;
  44. if (!checkUnicodeLiteral(start, in-start-1, errpos, errmsg))
  45. throw makeStringExceptionV(0, "Invalid filter - %s", errmsg.str());
  46. rtlDataAttr temp;
  47. size32_t newlen = 0; // NOTE - this will be in codepoints, not bytes
  48. rtlCodepageToUtf8XUnescape(newlen, temp.refstr(), in-start-1, start, "UTF-8");
  49. size32_t newsize = rtlUtf8Size(newlen, temp.getstr());
  50. out.append(newsize, temp.getstr());
  51. }
  52. /*
  53. * Read a single string from in until a matching terminator is found
  54. *
  55. * @param out The resulting string.
  56. * @param in A reference to the start of the string. Updated to point to the end of the string.
  57. * @param term Characters that can serve as terminators.
  58. */
  59. static void readUntilTerminator(StringBuffer & out, const char * & in, const char * terminators)
  60. {
  61. const char * start = in;
  62. const char * pbrk = strpbrk(start, terminators);
  63. if (!pbrk)
  64. throw makeStringExceptionV(0, "Invalid filter - expected terminator '%s'", terminators);
  65. out.append(pbrk - start, start);
  66. in = pbrk;
  67. }
  68. void deserializeSet(ISetCreator & creator, const char * filter)
  69. {
  70. while (*filter)
  71. {
  72. char startRange = *filter++;
  73. if (startRange != '(' && startRange != '[')
  74. throw MakeStringException(0, "Invalid filter string: expected [ or ( at start of range");
  75. StringBuffer upperString, lowerString;
  76. if (*filter=='\'')
  77. {
  78. filter++;
  79. readString(lowerString, filter);
  80. }
  81. else
  82. readUntilTerminator(lowerString, filter, ",])");
  83. if (*filter == ',')
  84. {
  85. filter++;
  86. if (*filter=='\'')
  87. {
  88. filter++;
  89. readString(upperString, filter);
  90. }
  91. else
  92. readUntilTerminator(upperString, filter, "])");
  93. }
  94. else
  95. upperString.set(lowerString);
  96. char endRange = *filter++;
  97. if (endRange != ')' && endRange != ']')
  98. throw MakeStringException(0, "Invalid filter string: expected ] or ) at end of range");
  99. if (*filter==',')
  100. filter++;
  101. else if (*filter)
  102. throw MakeStringException(0, "Invalid filter string: expected , between ranges");
  103. TransitionMask lowerMask = (startRange == '(') ? CMPgt : CMPge;
  104. TransitionMask upperMask = (endRange == ')') ? CMPlt : CMPle;
  105. creator.addRange(lowerMask, lowerString, upperMask, upperString);
  106. }
  107. }
  108. // A class wrapped for adding ranges to IValueSets
  109. class ValueSetCreator : implements ISetCreator
  110. {
  111. public:
  112. ValueSetCreator(IValueSet & _set) : set(_set) {}
  113. virtual void addRange(TransitionMask lowerMask, const StringBuffer & lowerString, TransitionMask upperMask, const StringBuffer & upperString) override
  114. {
  115. Owned<ValueTransition> lower = lowerString ? set.createUtf8Transition(lowerMask, rtlUtf8Length(lowerString.length(), lowerString), lowerString) : nullptr;
  116. Owned<ValueTransition> upper = upperString ? set.createUtf8Transition(upperMask, rtlUtf8Length(upperString.length(), upperString), upperString) : nullptr;
  117. set.addRange(lower, upper);
  118. }
  119. protected:
  120. IValueSet & set;
  121. };
  122. void deserializeSet(IValueSet & set, const char * filter)
  123. {
  124. ValueSetCreator creator(set);
  125. deserializeSet(creator, filter);
  126. }
  127. //---------------------------------------------------------------------------------------------------------------------
  128. /*
  129. * This class represents a value and a comparison condition and is used for representing ranges of values
  130. *
  131. * A lowerbound will always have the CMPgt bit set in the mask, and upper bound will have CMPlt set in the mask.
  132. * The value is always represented in the same way as a field of that type would be in a record.
  133. */
  134. class ValueTransition : implements CInterface
  135. {
  136. public:
  137. ValueTransition(TransitionMask _mask, const RtlTypeInfo & type, const void *_value)
  138. {
  139. mask = _mask;
  140. dbgassertex(_value || isMinimum() || isMaximum());
  141. if (_value)
  142. {
  143. size32_t size = type.size((const byte *)_value, nullptr);
  144. value.allocateN(size, false);
  145. memcpy(value, _value, size);
  146. }
  147. }
  148. ValueTransition(const RtlTypeInfo & type, MemoryBuffer & in)
  149. {
  150. byte inmask;
  151. in.read(inmask);
  152. if (!(inmask & CMPnovalue))
  153. {
  154. mask = (TransitionMask)inmask;
  155. size32_t size = type.size(in.readDirect(0), nullptr);
  156. value.allocateN(size, false);
  157. in.read(size, value);
  158. }
  159. else
  160. {
  161. mask = (TransitionMask)(inmask & ~CMPnovalue);
  162. }
  163. }
  164. ValueTransition(TransitionMask _mask) : mask(_mask)
  165. {
  166. dbgassertex(isMaximum() || isMinimum());
  167. }
  168. bool equals(const RtlTypeInfo & type, const ValueTransition & other) const
  169. {
  170. if (mask != other.mask)
  171. return false;
  172. if (value && other.value)
  173. {
  174. return type.compare(value, other.value) == 0;
  175. }
  176. else
  177. return !value && !other.value;
  178. }
  179. MemoryBuffer & serialize(const RtlTypeInfo & type, MemoryBuffer & out) const
  180. {
  181. byte outmask = mask;
  182. if (value)
  183. {
  184. size32_t size = type.size(value, nullptr);
  185. out.append(outmask);
  186. out.append(size, value);
  187. }
  188. else
  189. {
  190. outmask |= CMPnovalue;
  191. out.append(outmask);
  192. }
  193. return out;
  194. }
  195. int compareRaw(const RtlTypeInfo & type, const byte * field) const
  196. {
  197. if (!value)
  198. {
  199. if (mask & CMPmin)
  200. return +1;
  201. if (mask & CMPmax)
  202. return -1;
  203. }
  204. return type.compare(field, value.get());
  205. }
  206. int compare(const RtlTypeInfo & type, const byte * field) const
  207. {
  208. int c = compareRaw(type, field);
  209. if (c == 0)
  210. {
  211. if (mask & CMPeq)
  212. return 0;
  213. //Lower bound
  214. if (mask & CMPgt)
  215. return -1;
  216. //Check against upper bound
  217. if (mask & CMPlt)
  218. return +1;
  219. throwUnexpected();
  220. }
  221. return c;
  222. }
  223. int compareRaw(const RtlTypeInfo & type, const ValueTransition & other) const
  224. {
  225. if (!value || !other.value)
  226. {
  227. if (isMinimum())
  228. return other.isMinimum() ? 0 : -1;
  229. if (isMaximum())
  230. return other.isMaximum() ? 0 : +1;
  231. if (other.isMinimum())
  232. return +1;
  233. if (other.isMaximum())
  234. return -1;
  235. throwUnexpected();
  236. }
  237. return type.compare(value, other.value);
  238. }
  239. StringBuffer & describe(const RtlTypeInfo & type, StringBuffer & out) const
  240. {
  241. if (mask & CMPgt)
  242. {
  243. if (mask & CMPeq)
  244. out.append("[");
  245. else
  246. out.append("(");
  247. }
  248. if (value)
  249. {
  250. size32_t len;
  251. rtlDataAttr text;
  252. type.getUtf8(len, text.refstr(), value);
  253. size32_t size = rtlUtf8Size(len, text.getstr());
  254. if (type.isNumeric())
  255. {
  256. out.append(size, text.getstr());
  257. }
  258. else
  259. {
  260. out.append("'");
  261. appendUtf8AsECL(out, size, text.getstr());
  262. out.append("'");
  263. }
  264. }
  265. if (mask & CMPlt)
  266. {
  267. if (mask & CMPeq)
  268. out.append("]");
  269. else
  270. out.append(")");
  271. }
  272. return out;
  273. }
  274. bool isPreviousBound(const RtlTypeInfo & type, const ValueTransition & other) const
  275. {
  276. if (isInclusiveBound() || other.isInclusiveBound())
  277. {
  278. if (compareRaw(type, other) == 0)
  279. return true;
  280. }
  281. if (isInclusiveBound() && other.isInclusiveBound())
  282. {
  283. //MORE: if isPreviousValue(other)
  284. //if (oneless(hival, t.getValue()))
  285. }
  286. return false;
  287. }
  288. //If this transition isn't shared then modify it directly, otherwise clone. Always return a linked object.
  289. ValueTransition * modifyTransition(const RtlTypeInfo & type, TransitionMask newMask)
  290. {
  291. assertex(value);
  292. if (IsShared())
  293. {
  294. return new ValueTransition(newMask, type, value);
  295. }
  296. else
  297. {
  298. mask = newMask;
  299. return LINK(this);
  300. }
  301. }
  302. ValueTransition * modifyInverse(const RtlTypeInfo & type)
  303. {
  304. TransitionMask newMask = (TransitionMask)(mask ^ (CMPgt|CMPlt|CMPeq));
  305. return modifyTransition(type, newMask);
  306. }
  307. bool isLowerBound() const { return (mask & CMPgt) != 0; }
  308. bool isUpperBound() const { return (mask & CMPlt) != 0; }
  309. bool isInclusiveBound() const { return (mask & CMPeq) != 0; }
  310. bool isMinimum() const { return (mask & CMPmin) != 0; }
  311. bool isMaximum() const { return (mask & CMPmax) != 0; }
  312. private:
  313. TransitionMask mask;
  314. OwnedMalloc<byte> value;
  315. };
  316. typedef CIArrayOf<ValueTransition> ValueTransitionArray;
  317. //---------------------------------------------------------------------------------------------------------------------
  318. /*
  319. * The ValueSet class represents a set of ranges of values.
  320. *
  321. * The transitions always come in pairs - an upper and lower bound. Each bound can be inclusive or exclusive.
  322. */
  323. class ValueSet : public CInterfaceOf<IValueSet>
  324. {
  325. public:
  326. ValueSet(const RtlTypeInfo & _type) : type(_type)
  327. {
  328. }
  329. ValueSet(const RtlTypeInfo & _type, MemoryBuffer & in) : type(_type)
  330. {
  331. unsigned cnt;
  332. in.readPacked(cnt);
  333. for (unsigned i = 0; i < cnt; i++)
  334. transitions.append(*new ValueTransition(type, in));
  335. }
  336. // Methods for creating a value set
  337. virtual ValueTransition * createTransition(TransitionMask mask, unsigned __int64 value) const override
  338. {
  339. MemoryBuffer buff;
  340. MemoryBufferBuilder builder(buff, 0);
  341. type.buildInt(builder, 0, nullptr, value);
  342. return new ValueTransition(mask, type, buff.toByteArray());
  343. }
  344. virtual ValueTransition * createStringTransition(TransitionMask mask, size32_t len, const char * value) const override
  345. {
  346. MemoryBuffer buff;
  347. MemoryBufferBuilder builder(buff, 0);
  348. type.buildString(builder, 0, nullptr, len, value);
  349. return new ValueTransition(mask, type, buff.toByteArray());
  350. }
  351. virtual ValueTransition * createUtf8Transition(TransitionMask mask, size32_t len, const char * value) const override
  352. {
  353. MemoryBuffer buff;
  354. MemoryBufferBuilder builder(buff, 0);
  355. type.buildUtf8(builder, 0, nullptr, len, value);
  356. return new ValueTransition(mask, type, buff.toByteArray());
  357. }
  358. virtual void addRange(ValueTransition * lower, ValueTransition * upper) override
  359. {
  360. Owned<ValueTransition> minBound;
  361. Owned<ValueTransition> maxBound;
  362. if (!lower)
  363. {
  364. minBound.setown(new ValueTransition(CMPminmask));
  365. lower = minBound;
  366. }
  367. if (!upper)
  368. {
  369. maxBound.setown(new ValueTransition(CMPmaxmask));
  370. upper = maxBound;
  371. }
  372. if (!lower->isLowerBound() || !upper->isUpperBound())
  373. throw MakeStringException(1, "Invalid range bounds");
  374. //If lower > upper then it is an empty range
  375. int rc = lower->compareRaw(type, *upper);
  376. if (rc > 0)
  377. return;
  378. //Check for exclusive ranges for a single value
  379. if (rc == 0)
  380. {
  381. if (!lower->isInclusiveBound() || !upper->isInclusiveBound())
  382. return;
  383. }
  384. // binchop to find last transition > val...
  385. unsigned int low = 0;
  386. unsigned high = transitions.ordinality();
  387. while (low < high)
  388. {
  389. unsigned mid = low + (high - low) / 2;
  390. int rc = lower->compareRaw(type, transitions.item(mid));
  391. if (rc <= 0)
  392. high = mid;
  393. else
  394. low = mid+1;
  395. }
  396. unsigned idx;
  397. if (transitions.isItem(low))
  398. {
  399. ValueTransition & next = transitions.item(low);
  400. if (lower->compareRaw(type, next) == 0)
  401. {
  402. if (next.isLowerBound())
  403. {
  404. if (!next.isInclusiveBound() && lower->isInclusiveBound())
  405. transitions.replace(*LINK(lower), low);
  406. idx = low+1;
  407. }
  408. else
  409. {
  410. if (next.isInclusiveBound() || lower->isInclusiveBound())
  411. {
  412. transitions.remove(low);
  413. idx = low;
  414. }
  415. else
  416. {
  417. transitions.add(*LINK(lower), low+1);
  418. idx = low + 2;
  419. }
  420. }
  421. }
  422. else
  423. {
  424. if (next.isLowerBound())
  425. {
  426. transitions.add(*LINK(lower), low);
  427. idx = low + 1;
  428. }
  429. else
  430. {
  431. //previous must exist and be lower => ignore this one
  432. idx = low;
  433. }
  434. }
  435. }
  436. else
  437. {
  438. transitions.append(*LINK(lower));
  439. transitions.append(*LINK(upper));
  440. return;
  441. }
  442. //Walk the remaining transitions until you find one that is higher than the current one (or run out)
  443. while (transitions.isItem(idx))
  444. {
  445. ValueTransition & cur = transitions.item(idx);
  446. int rc = cur.compareRaw(type, *upper);
  447. if (rc > 0)
  448. {
  449. if (cur.isUpperBound())
  450. return;
  451. break;
  452. }
  453. if (rc == 0)
  454. {
  455. if (cur.isUpperBound())
  456. {
  457. if (!cur.isInclusiveBound() && upper->isInclusiveBound())
  458. transitions.replace(*LINK(upper), idx);
  459. return;
  460. }
  461. //Upper value matches the next lower bound - could either remove the next item if either is inclusive, otherwise add
  462. if (cur.isInclusiveBound() || upper->isInclusiveBound())
  463. {
  464. transitions.remove(idx);
  465. return;
  466. }
  467. break;
  468. }
  469. transitions.remove(idx);
  470. }
  471. if (transitions.isItem(idx))
  472. {
  473. ValueTransition & cur = transitions.item(idx);
  474. assertex(cur.isLowerBound());
  475. if (upper->isPreviousBound(type, cur))
  476. {
  477. transitions.remove(idx);
  478. return;
  479. }
  480. }
  481. transitions.add(*LINK(upper), idx);
  482. }
  483. virtual void addAll() override
  484. {
  485. reset();
  486. addRange(nullptr, nullptr);
  487. }
  488. virtual void killRange(ValueTransition * lower, ValueTransition * upper) override
  489. {
  490. Owned<ValueTransition> minBound;
  491. Owned<ValueTransition> maxBound;
  492. if (!lower)
  493. {
  494. minBound.setown(new ValueTransition(CMPminmask));
  495. lower = minBound;
  496. }
  497. if (!upper)
  498. {
  499. maxBound.setown(new ValueTransition(CMPmaxmask));
  500. upper = maxBound;
  501. }
  502. if (!lower->isLowerBound() || !upper->isUpperBound())
  503. throw MakeStringException(1, "Invalid range bounds");
  504. //If lower > upper then it is an empty range
  505. int rc = lower->compareRaw(type, *upper);
  506. if (rc > 0)
  507. return;
  508. //Check for exclusive ranges for a single value
  509. if (rc == 0)
  510. {
  511. if (!lower->isInclusiveBound() || !upper->isInclusiveBound())
  512. return;
  513. }
  514. // binchop to find last transition > val...
  515. unsigned int low = 0;
  516. unsigned high = transitions.ordinality();
  517. while (low < high)
  518. {
  519. unsigned mid = low + (high - low) / 2;
  520. int rc = lower->compareRaw(type, transitions.item(mid));
  521. if (rc <= 0)
  522. high = mid;
  523. else
  524. low = mid+1;
  525. }
  526. unsigned idx = low;
  527. if (!transitions.isItem(low))
  528. return;
  529. //First terminate any set that overlaps the start of the range
  530. ValueTransition & next = transitions.item(low);
  531. if (lower->compareRaw(type, next) == 0)
  532. {
  533. if (next.isLowerBound())
  534. {
  535. // Range [x..y] remove [x..]
  536. if (!lower->isInclusiveBound() && next.isInclusiveBound())
  537. {
  538. //[x,y] - (x,z) = [x],{ (x,y)-(x,z)
  539. transitions.add(*lower->modifyTransition(type, CMPle), low+1);
  540. idx = low+2;
  541. }
  542. else
  543. transitions.remove(low);
  544. }
  545. else
  546. {
  547. //[x..y]-[y..z) -> [x..y)
  548. if (lower->isInclusiveBound() && next.isInclusiveBound())
  549. {
  550. //Convert to an exclusive bound. This must be different from the lower bound
  551. //(otherwise it would have matched that bound 1st)
  552. ValueTransition * newTransition = next.modifyTransition(type, CMPlt);
  553. transitions.replace(*newTransition, low);
  554. idx = low+1;
  555. }
  556. else
  557. idx = low+1;
  558. }
  559. }
  560. else
  561. {
  562. if (next.isUpperBound())
  563. {
  564. transitions.add(*lower->modifyTransition(type, lower->isInclusiveBound() ? CMPlt : CMPle), idx);
  565. idx++;
  566. }
  567. }
  568. //Walk the remaining transitions until you find one that is higher than the current one (or run out)
  569. while (transitions.isItem(idx))
  570. {
  571. ValueTransition & cur = transitions.item(idx);
  572. int rc = cur.compareRaw(type, *upper);
  573. if (rc > 0)
  574. {
  575. if (cur.isUpperBound())
  576. transitions.add(*upper->modifyTransition(type, upper->isInclusiveBound() ? CMPgt : CMPge), idx);
  577. return;
  578. }
  579. if (rc == 0)
  580. {
  581. if (cur.isUpperBound())
  582. {
  583. //[x..y] remove [y..y)
  584. if (cur.isInclusiveBound() && !upper->isInclusiveBound())
  585. transitions.add(*upper->modifyTransition(type, CMPge), idx);
  586. else
  587. transitions.remove(idx);
  588. return;
  589. }
  590. else
  591. {
  592. if (!upper->isInclusiveBound())
  593. return;
  594. }
  595. }
  596. transitions.remove(idx);
  597. }
  598. }
  599. virtual void reset() override
  600. {
  601. transitions.kill();
  602. }
  603. virtual void invertSet() override
  604. {
  605. if (transitions.empty())
  606. {
  607. addAll();
  608. return;
  609. }
  610. unsigned idx = 0;
  611. ValueTransitionArray newTransitions;
  612. if (!transitions.item(0).isMinimum())
  613. newTransitions.append(*new ValueTransition(CMPminmask));
  614. else
  615. idx++;
  616. bool unboundedUpper = transitions.tos().isMaximum();
  617. unsigned max = transitions.ordinality();
  618. if (unboundedUpper)
  619. max--;
  620. for (; idx < max; idx ++)
  621. newTransitions.append(*transitions.item(idx).modifyInverse(type));
  622. if (!unboundedUpper)
  623. newTransitions.append(*new ValueTransition(CMPmaxmask));
  624. transitions.swapWith(newTransitions);
  625. }
  626. virtual void unionSet(const IValueSet * _other) override
  627. {
  628. //Iterate through the ranges in other and add them to this set
  629. const ValueSet * other = static_cast<const ValueSet *>(_other);
  630. for (unsigned i=0; i < other->transitions.ordinality(); i+=2)
  631. addRange(&other->transitions.item(i), &other->transitions.item(i+1));
  632. }
  633. virtual void excludeSet(const IValueSet * _other) override
  634. {
  635. //Iterate through the ranges in other and add them to this set
  636. const ValueSet * other = static_cast<const ValueSet *>(_other);
  637. for (unsigned i=0; i < other->transitions.ordinality(); i+=2)
  638. killRange(&other->transitions.item(i), &other->transitions.item(i+1));
  639. }
  640. virtual void intersectSet(IValueSet const * _other) override
  641. {
  642. const ValueSet * other = static_cast<const ValueSet *>(_other);
  643. //Iterate through the ranges in other and remove them from this set
  644. unsigned curOther = 0;
  645. unsigned otherMax = other->numTransitions();
  646. ValueTransitionArray newTransitions;
  647. for (unsigned i = 0; i < numTransitions(); i+=2)
  648. {
  649. ValueTransition & lower = transitions.item(i);
  650. ValueTransition & upper = transitions.item(i+1);
  651. for (;;)
  652. {
  653. if (curOther == otherMax)
  654. goto done; // break out of both loops.
  655. ValueTransition & otherLower = other->transitions.item(curOther);
  656. ValueTransition & otherUpper = other->transitions.item(curOther+1);
  657. //If upper is lower than the other lower bound then no rows overlap, skip this range
  658. int rc1 = upper.compareRaw(type, otherLower);
  659. if (rc1 < 0 ||
  660. ((rc1 == 0) && (!upper.isInclusiveBound() || !otherLower.isInclusiveBound())))
  661. break;
  662. //If other upper is lower than the lower bound then no rows overlap, skip other range
  663. int rc2 = otherUpper.compareRaw(type, lower);
  664. if (rc2 < 0 ||
  665. ((rc2 == 0) && (!otherUpper.isInclusiveBound() || !lower.isInclusiveBound())))
  666. {
  667. curOther += 2;
  668. continue;
  669. }
  670. //Lower bound of the intersection is the higher of the two lower bounds
  671. int rc3 = lower.compareRaw(type, otherLower);
  672. if (rc3 < 0 || ((rc3 == 0) && lower.isInclusiveBound()))
  673. newTransitions.append(OLINK(otherLower));
  674. else
  675. newTransitions.append(OLINK(lower));
  676. //Upper bound of the intersection is the lower of the two bounds - and move onto next range that is consumed
  677. int rc4 = upper.compareRaw(type, otherUpper);
  678. if (rc4 < 0 || ((rc4 == 0) && !upper.isInclusiveBound()))
  679. {
  680. newTransitions.append(OLINK(upper));
  681. break;
  682. }
  683. else
  684. {
  685. newTransitions.append(OLINK(otherUpper));
  686. curOther += 2;
  687. }
  688. }
  689. }
  690. done:
  691. transitions.swapWith(newTransitions);
  692. }
  693. virtual ValueTransition * createRawTransition(TransitionMask mask, const void * value) const override
  694. {
  695. return new ValueTransition(mask, type, value);
  696. }
  697. virtual void addRawRange(const void * lower, const void * upper) override
  698. {
  699. Owned<ValueTransition> lowerBound = lower ? createRawTransition(CMPge, lower) : nullptr;
  700. Owned<ValueTransition> upperBound = upper ? createRawTransition(CMPle, upper) : nullptr;
  701. addRange(lowerBound, upperBound);
  702. }
  703. virtual void killRawRange(const void * lower, const void * upper) override
  704. {
  705. Owned<ValueTransition> lowerBound = lower ? createRawTransition(CMPge, lower) : nullptr;
  706. Owned<ValueTransition> upperBound = upper ? createRawTransition(CMPle, upper) : nullptr;
  707. killRange(lowerBound, upperBound);
  708. }
  709. virtual bool equals(const IValueSet & _other) const override
  710. {
  711. const ValueSet & other = static_cast<const ValueSet &>(_other);
  712. if (!type.equivalent(&other.type))
  713. return false;
  714. if (transitions.ordinality() != other.transitions.ordinality())
  715. return false;
  716. ForEachItemIn(i, transitions)
  717. {
  718. if (!transitions.item(i).equals(type, other.transitions.item(i)))
  719. return false;
  720. }
  721. return true;
  722. }
  723. // Methods for using a value set
  724. virtual bool isWild() const override;
  725. virtual unsigned numRanges() const override;
  726. virtual int compareLowest(const byte * field, unsigned range) const override;
  727. virtual int compareHighest(const byte * field, unsigned range) const override;
  728. virtual int findForwardMatchRange(const byte * field, unsigned & matchRange) const override;
  729. // Does this field match any range?
  730. virtual bool matches(const byte * field) const override;
  731. // Does this field match this particular range?
  732. virtual bool matches(const byte * field, unsigned range) const override;
  733. virtual StringBuffer & serialize(StringBuffer & out) const override
  734. {
  735. //Does this need to include the type information?
  736. return describe(out);
  737. }
  738. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override
  739. {
  740. out.appendPacked((unsigned)transitions.ordinality());
  741. ForEachItemIn(i, transitions)
  742. transitions.item(i).serialize(type, out);
  743. return out;
  744. }
  745. virtual const RtlTypeInfo & queryType() const override
  746. {
  747. return type;
  748. }
  749. protected:
  750. inline int compareRaw(const byte * field, ValueTransition * transition) const __attribute__((always_inline))
  751. {
  752. return transition->compareRaw(type, field);
  753. }
  754. inline int compare(const byte * field, ValueTransition * transition) const __attribute__((always_inline))
  755. {
  756. return transition->compare(type, field);
  757. }
  758. ValueTransition * queryTransition(unsigned i) const { return &transitions.item(i); }
  759. unsigned numTransitions() const { return transitions.ordinality(); }
  760. StringBuffer & describe(StringBuffer & out) const
  761. {
  762. for (unsigned i = 0; i < transitions.ordinality(); i += 2)
  763. {
  764. if (i != 0)
  765. out.append(",");
  766. ValueTransition & lower = transitions.item(i);
  767. ValueTransition & upper = transitions.item(i+1);
  768. lower.describe(type, out);
  769. if (lower.compareRaw(type, upper) != 0)
  770. {
  771. out.append(",");
  772. upper.describe(type, out);
  773. }
  774. else
  775. out.append("]");
  776. }
  777. return out;
  778. }
  779. bool hasLowerBound() const
  780. {
  781. if (transitions.empty())
  782. return false;
  783. return !transitions.item(0).isMinimum();
  784. }
  785. bool hasUpperBound() const
  786. {
  787. if (transitions.empty())
  788. return false;
  789. return !transitions.tos().isMaximum();
  790. }
  791. protected:
  792. const RtlTypeInfo & type;
  793. ValueTransitionArray transitions;
  794. };
  795. unsigned ValueSet::numRanges() const
  796. {
  797. return transitions.ordinality() / 2;
  798. }
  799. bool ValueSet::isWild() const
  800. {
  801. if (transitions.ordinality() != 2)
  802. return false;
  803. return queryTransition(0)->isMinimum() && queryTransition(1)->isMaximum();
  804. }
  805. bool ValueSet::matches(const byte * field) const
  806. {
  807. //NOTE: It is guaranteed that transitions with the same value are merged if possible - which allows the loop to terminate early on equality.
  808. unsigned high = numRanges();
  809. unsigned low = 0;
  810. while (low < high)
  811. {
  812. unsigned mid = low + (high-low)/2;
  813. unsigned lower = mid * 2;
  814. //Using compareRaw allows early termination for equalities that actually fail to match.
  815. int rc = compareRaw(field, queryTransition(lower));
  816. if (rc < 0)
  817. {
  818. high = mid;
  819. }
  820. else if (rc == 0)
  821. {
  822. if (queryTransition(lower)->isInclusiveBound())
  823. return true;
  824. else
  825. return false;
  826. }
  827. else
  828. {
  829. unsigned upper = lower + 1;
  830. rc = compareRaw(field, queryTransition(upper));
  831. if (rc < 0)
  832. return true;
  833. if (rc == 0)
  834. {
  835. if (queryTransition(upper)->isInclusiveBound())
  836. return true;
  837. else
  838. return false;
  839. }
  840. low = mid+1;
  841. }
  842. }
  843. return false;
  844. }
  845. bool ValueSet::matches(const byte * field, unsigned range) const
  846. {
  847. if (range >= numRanges())
  848. return false;
  849. unsigned lower = range * 2;
  850. int rc = compare(field, queryTransition(lower));
  851. if (rc < 0)
  852. return false;
  853. if (rc == 0)
  854. return true;
  855. unsigned upper = lower + 1;
  856. rc = compare(field, queryTransition(upper));
  857. return (rc <= 0);
  858. }
  859. int ValueSet::compareLowest(const byte * field, unsigned range) const
  860. {
  861. return compare(field, queryTransition(range*2));
  862. }
  863. int ValueSet::compareHighest(const byte * field, unsigned range) const
  864. {
  865. return compare(field, queryTransition(range*2+1));
  866. }
  867. /*
  868. //find the last range where the lower bound <= the field, returns 0 if the field matches the lower bound, > 0 otherwise.
  869. //matchRange is set to the range number, set to numRanges if there is no possible match. Uses a binary chop
  870. int ValueSet::findCandidateRange(const byte * field, unsigned & matchRange) const
  871. {
  872. //NOTE: It is guaranteed that transitions are merged if possible - which allows the loop to terminate early.
  873. unsigned high = numRanges();
  874. unsigned low = 0;
  875. int rc = 0;
  876. while (low < high)
  877. {
  878. unsigned mid = low + (high - low) / 2;
  879. unsigned lower = mid * 2;
  880. rc = compare(field, queryTransition(lower));
  881. if (rc <= 0)
  882. high = mid;
  883. else
  884. low = mid + 1;
  885. }
  886. matchRange = low;
  887. return rc;
  888. }
  889. //find the last range where the lower bound <= the field, returns 0 if the field matches the lower bound, > 0 otherwise.
  890. //starts searching from curRange (which is likely to match). Uses a sequential search.
  891. int ValueSet::checkNextCandidateRange(const byte * field, unsigned & curRange) const
  892. {
  893. unsigned cur = curRange;
  894. while (cur < numRanges())
  895. {
  896. unsigned lower = cur * 2;
  897. int rc = compare(field, queryTransition(lower));
  898. if (rc >= 0)
  899. {
  900. curRange = cur;
  901. return rc;
  902. }
  903. cur++;
  904. }
  905. curRange = numRanges();
  906. return 0;
  907. }
  908. */
  909. //If field lies within a range return true and set matchRange to the index of the range.
  910. //If field is outside a range return false and set matchRange to the index of the next range, i.e. min(range.lower) where range.lower > field
  911. //Find the largest transition value that is <= field, and then check if within upper limit
  912. //Could have a version that starts from the previous match to shorten the binary chop, or use a linear search instead
  913. int ValueSet::findForwardMatchRange(const byte * field, unsigned & matchRange) const
  914. {
  915. unsigned ranges = numRanges();
  916. unsigned high = ranges;
  917. unsigned low = 0;
  918. //Find the largest transition that is <= the search value
  919. while (high - low > 1)
  920. {
  921. unsigned mid = low + (high - low) / 2;
  922. unsigned lower = mid * 2;
  923. int rc = compare(field, queryTransition(lower));
  924. if (rc < 0)
  925. {
  926. // field is less than transition, so transition with value < search must be before.
  927. high = mid; // exclude mid and all transitions after it
  928. }
  929. else if (rc > 0)
  930. {
  931. // field is greater than transition, so transition with value > search must be this or after.
  932. low = mid; // exclude mid-1 and all transitions before it
  933. }
  934. else
  935. {
  936. matchRange = mid;
  937. return true;
  938. }
  939. }
  940. //rc is comparison from element mid.
  941. if (low != ranges)
  942. {
  943. if (compare(field, queryTransition(low*2)) >= 0)
  944. {
  945. int rc = compare(field, queryTransition(low*2+1));
  946. if (rc <= 0)
  947. {
  948. matchRange = low;
  949. return true;
  950. }
  951. low++;
  952. }
  953. }
  954. matchRange = low;
  955. return false;
  956. }
  957. IValueSet * createValueSet(const RtlTypeInfo & _type) { return new ValueSet(_type); }
  958. IValueSet * createValueSet(const RtlTypeInfo & _type, MemoryBuffer & in) { return new ValueSet(_type, in); }
  959. //---------------------------------------------------------------------------------------------------------------------
  960. /*
  961. * Base implementation class for field filters.
  962. */
  963. class FieldFilter : public CInterfaceOf<IFieldFilter>
  964. {
  965. public:
  966. FieldFilter(unsigned _field, const RtlTypeInfo & _type) : field(_field), type(_type) {}
  967. //More complex index matching
  968. virtual int compareRow(const RtlRow & left, const RtlRow & right) const override
  969. {
  970. return type.compare(left.queryField(field), right.queryField(field));
  971. }
  972. virtual unsigned queryFieldIndex() const override
  973. {
  974. return field;
  975. }
  976. virtual const RtlTypeInfo & queryType() const override
  977. {
  978. return type;
  979. }
  980. protected:
  981. unsigned field;
  982. const RtlTypeInfo & type;
  983. };
  984. /*
  985. * A field filter that can match a set of values.
  986. */
  987. class SetFieldFilter : public FieldFilter
  988. {
  989. public:
  990. SetFieldFilter(unsigned _field, IValueSet * _values) : FieldFilter(_field, _values->queryType()), values(_values) {}
  991. //Simple row matching
  992. virtual bool matches(const RtlRow & row) const override;
  993. virtual bool isEmpty() const override;
  994. virtual bool isWild() const override;
  995. //More complex index matching
  996. virtual unsigned numRanges() const override;
  997. virtual int compareLowest(const RtlRow & left, unsigned range) const override;
  998. virtual int compareHighest(const RtlRow & left, unsigned range) const override;
  999. virtual int findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const override;
  1000. virtual unsigned queryScore() const override;
  1001. virtual IFieldFilter *remap(unsigned newField) const override { return new SetFieldFilter(newField, values); }
  1002. virtual StringBuffer & serialize(StringBuffer & out) const override;
  1003. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override;
  1004. protected:
  1005. Linked<IValueSet> values;
  1006. };
  1007. bool SetFieldFilter::matches(const RtlRow & row) const
  1008. {
  1009. return values->matches(row.queryField(field));
  1010. }
  1011. bool SetFieldFilter::isEmpty() const
  1012. {
  1013. return values->numRanges() == 0;
  1014. }
  1015. bool SetFieldFilter::isWild() const
  1016. {
  1017. return values->isWild();
  1018. }
  1019. unsigned SetFieldFilter::numRanges() const
  1020. {
  1021. return values->numRanges();
  1022. }
  1023. int SetFieldFilter::compareLowest(const RtlRow & left, unsigned range) const
  1024. {
  1025. return values->compareLowest(left.queryField(field), range);
  1026. }
  1027. int SetFieldFilter::compareHighest(const RtlRow & left, unsigned range) const
  1028. {
  1029. return values->compareHighest(left.queryField(field), range);
  1030. }
  1031. int SetFieldFilter::findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const
  1032. {
  1033. return values->findForwardMatchRange(row.queryField(field), matchRange);
  1034. }
  1035. unsigned SetFieldFilter::queryScore() const
  1036. {
  1037. // MORE - the score should probably depend on the number and nature of ranges too.
  1038. unsigned score = type.getMinSize();
  1039. if (!score)
  1040. score = 5; // Arbitrary guess for average field length in a variable size field
  1041. return score;
  1042. }
  1043. StringBuffer & SetFieldFilter::serialize(StringBuffer & out) const
  1044. {
  1045. out.append('=');
  1046. return values->serialize(out);
  1047. }
  1048. MemoryBuffer & SetFieldFilter::serialize(MemoryBuffer & out) const
  1049. {
  1050. out.append('=');
  1051. return values->serialize(out);
  1052. }
  1053. IFieldFilter * createFieldFilter(unsigned fieldId, IValueSet * values)
  1054. {
  1055. return new SetFieldFilter(fieldId, values);
  1056. }
  1057. IFieldFilter * createEmptyFieldFilter(unsigned fieldId, const RtlTypeInfo & type)
  1058. {
  1059. Owned<IValueSet> values = createValueSet(type);
  1060. return new SetFieldFilter(fieldId, values);
  1061. }
  1062. IFieldFilter * createFieldFilter(unsigned fieldId, const RtlTypeInfo & type, const void * value)
  1063. {
  1064. Owned<IValueSet> values = createValueSet(type);
  1065. values->addRawRange(value, value);
  1066. return new SetFieldFilter(fieldId, values);
  1067. }
  1068. //---------------------------------------------------------------------------------------------------------------------
  1069. /*
  1070. * A field filter that can match any value.
  1071. */
  1072. class WildFieldFilter : public FieldFilter
  1073. {
  1074. public:
  1075. WildFieldFilter(unsigned _field, const RtlTypeInfo & _type) : FieldFilter(_field, _type) {}
  1076. //Simple row matching
  1077. virtual bool matches(const RtlRow & row) const override
  1078. {
  1079. return true;
  1080. }
  1081. virtual bool isEmpty() const override
  1082. {
  1083. return false;
  1084. }
  1085. virtual bool isWild() const override
  1086. {
  1087. return true;
  1088. }
  1089. //More complex index matching
  1090. virtual unsigned numRanges() const override
  1091. {
  1092. return 1;
  1093. }
  1094. virtual int compareLowest(const RtlRow & left, unsigned range) const override
  1095. {
  1096. //Should pass through to compare using the type.
  1097. //return type.compareLowest(left.queryField(fieldId));
  1098. //MORE
  1099. return +1;
  1100. }
  1101. virtual int compareHighest(const RtlRow & left, unsigned range) const override
  1102. {
  1103. //Should pass through to compare using the type.
  1104. //return type.compareLowest(left.queryField(fieldId));
  1105. //MORE
  1106. return -1;
  1107. }
  1108. virtual int findForwardMatchRange(const RtlRow & row, unsigned & matchRange) const override
  1109. {
  1110. matchRange = 0;
  1111. return true;
  1112. }
  1113. virtual unsigned queryScore() const override
  1114. {
  1115. return 0;
  1116. }
  1117. virtual IFieldFilter *remap(unsigned newField) const override { return new WildFieldFilter(newField, type); }
  1118. virtual StringBuffer & serialize(StringBuffer & out) const override
  1119. {
  1120. return out.append('*');
  1121. }
  1122. virtual MemoryBuffer & serialize(MemoryBuffer & out) const override
  1123. {
  1124. return out.append('*');
  1125. }
  1126. };
  1127. IFieldFilter * createWildFieldFilter(unsigned fieldId, const RtlTypeInfo & type)
  1128. {
  1129. //MORE: Is it worth special casing, or would a SetFieldFilter of null..null be just as good?
  1130. return new WildFieldFilter(fieldId, type);
  1131. }
  1132. //---------------------------------------------------------------------------------------------------------------------
  1133. //Note, the fieldId could be serialized within the string, but it is needed to determine the type, and
  1134. //passing it in allows this code to be decoupled from the type serialization code.
  1135. IFieldFilter * deserializeFieldFilter(unsigned fieldId, const RtlTypeInfo & type, const char * src)
  1136. {
  1137. switch (*src)
  1138. {
  1139. case '*':
  1140. return createWildFieldFilter(fieldId, type);
  1141. case '=':
  1142. {
  1143. Owned<IValueSet> values = createValueSet(type);
  1144. deserializeSet(*values, src+1);
  1145. return createFieldFilter(fieldId, values);
  1146. }
  1147. }
  1148. UNIMPLEMENTED_X("Unknown Field Filter");
  1149. }
  1150. IFieldFilter * deserializeFieldFilter(unsigned fieldId, const RtlTypeInfo & type, MemoryBuffer & in)
  1151. {
  1152. char kind;
  1153. in.read(kind);
  1154. switch (kind)
  1155. {
  1156. case '*':
  1157. return createWildFieldFilter(fieldId, type);
  1158. case '=':
  1159. {
  1160. Owned<IValueSet> values = createValueSet(type, in);
  1161. return createFieldFilter(fieldId, values);
  1162. }
  1163. }
  1164. UNIMPLEMENTED_X("Unknown Field Filter");
  1165. }
  1166. //---------------------------------------------------------------------------------------------------------------------
  1167. static int compareFieldFilters(IInterface * const * left, IInterface * const * right)
  1168. {
  1169. IFieldFilter * leftFilter = static_cast<IFieldFilter *>(*left);
  1170. IFieldFilter * rightFilter = static_cast<IFieldFilter *>(*right);
  1171. return leftFilter->queryFieldIndex() - rightFilter->queryFieldIndex();
  1172. }
  1173. void RowFilter::addFilter(const IFieldFilter & filter)
  1174. {
  1175. //assertex(filter.queryField() == filters.ordinality()); //MORE - fill with wild filters and replace existing wild
  1176. filters.append(filter);
  1177. unsigned fieldNum = filter.queryFieldIndex();
  1178. if (fieldNum >= numFieldsRequired)
  1179. numFieldsRequired = fieldNum+1;
  1180. }
  1181. bool RowFilter::matches(const RtlRow & row) const
  1182. {
  1183. row.lazyCalcOffsets(numFieldsRequired);
  1184. ForEachItemIn(i, filters)
  1185. {
  1186. if (!filters.item(i).matches(row))
  1187. return false;
  1188. }
  1189. return true;
  1190. }
  1191. void RowFilter::appendFilters(IConstArrayOf<IFieldFilter> & _filters)
  1192. {
  1193. ForEachItemIn(i, _filters)
  1194. {
  1195. addFilter(OLINK(_filters.item(i)));
  1196. }
  1197. }
  1198. void RowFilter::extractKeyFilter(const RtlRecord & record, IConstArrayOf<IFieldFilter> & keyFilters) const
  1199. {
  1200. if (!filters)
  1201. return;
  1202. // for an index must be in field order, and all values present
  1203. IConstArrayOf<IFieldFilter> temp;
  1204. ForEachItemIn(i, filters)
  1205. temp.append(OLINK(filters.item(i)));
  1206. temp.sort(compareFieldFilters);
  1207. unsigned maxField = temp.tos().queryFieldIndex();
  1208. unsigned curIdx=0;
  1209. for (unsigned field = 0; field <= maxField; field++)
  1210. {
  1211. const IFieldFilter & cur = temp.item(curIdx);
  1212. if (field == cur.queryFieldIndex())
  1213. {
  1214. keyFilters.append(OLINK(cur));
  1215. curIdx++;
  1216. }
  1217. else
  1218. keyFilters.append(*createWildFieldFilter(field, *record.queryType(field)));
  1219. }
  1220. }
  1221. void RowFilter::extractMemKeyFilter(const RtlRecord & record, const UnsignedArray &sortOrder, IConstArrayOf<IFieldFilter> & keyFilters) const
  1222. {
  1223. if (!filters)
  1224. return;
  1225. // for in-memory index, we want filters in the same order as the sort fields, with wilds added
  1226. ForEachItemIn(idx, sortOrder)
  1227. {
  1228. unsigned sortField = sortOrder.item(idx);
  1229. bool needWild = true;
  1230. ForEachItemIn(fidx, filters)
  1231. {
  1232. const IFieldFilter &filter = filters.item(fidx);
  1233. if (filter.queryFieldIndex()==sortField)
  1234. {
  1235. keyFilters.append(OLINK(filter));
  1236. needWild = false;
  1237. break;
  1238. }
  1239. }
  1240. if (needWild)
  1241. keyFilters.append(*createWildFieldFilter(sortField, *record.queryType(sortField)));
  1242. }
  1243. }
  1244. const IFieldFilter *RowFilter::findFilter(unsigned fieldNum) const
  1245. {
  1246. ForEachItemIn(i, filters)
  1247. {
  1248. const IFieldFilter &field = filters.item(i);
  1249. if (field.queryFieldIndex() == fieldNum)
  1250. return &field;
  1251. }
  1252. return nullptr;
  1253. }
  1254. const IFieldFilter *RowFilter::extractFilter(unsigned fieldNum)
  1255. {
  1256. ForEachItemIn(i, filters)
  1257. {
  1258. const IFieldFilter &field = filters.item(i);
  1259. if (field.queryFieldIndex() == fieldNum)
  1260. {
  1261. filters.remove(i, true);
  1262. return &field;
  1263. }
  1264. }
  1265. return nullptr;
  1266. }
  1267. void RowFilter::remove(unsigned idx)
  1268. {
  1269. filters.remove(idx);
  1270. }
  1271. void RowFilter::clear()
  1272. {
  1273. filters.kill();
  1274. numFieldsRequired = 0;
  1275. }
  1276. void RowFilter::recalcFieldsRequired()
  1277. {
  1278. numFieldsRequired = 0;
  1279. ForEachItemIn(i, filters)
  1280. {
  1281. const IFieldFilter &field = filters.item(i);
  1282. if (field.queryFieldIndex() >= numFieldsRequired)
  1283. numFieldsRequired = field.queryFieldIndex()+1;
  1284. }
  1285. }
  1286. void RowFilter::remapField(unsigned filterIdx, unsigned newFieldNum)
  1287. {
  1288. filters.replace(*filters.item(filterIdx).remap(newFieldNum), filterIdx);
  1289. }
  1290. //---------------------------------------------------------------------------------------------------------------------
  1291. bool RowCursor::setRowForward(const byte * row)
  1292. {
  1293. currentRow.setRow(row, numFieldsRequired);
  1294. unsigned field = 0;
  1295. //Now check which of the fields matches, and update matchedRanges to indicate
  1296. //MORE: Add an optimization:
  1297. //First of all check all of the fields that were previously matched. If the previous matches are in the same range,
  1298. //then the next field must either be in the same range, or a following range.
  1299. /*
  1300. for (; field < numMatched; field++)
  1301. {
  1302. const IFieldFilter & filter = queryFilter(field);
  1303. if (!filter.withinUpperRange(currentRow, matchPos(field)))
  1304. {
  1305. //This field now either matches a later range, or doesn't match at all.
  1306. //Find the new range for the current field that could include the row
  1307. cur.checkNextCandidateRange(currentRow, matchPos(i));
  1308. if (isValid(i))
  1309. return 0;
  1310. //Finished processing
  1311. if (i == 0)
  1312. return UINT_MAX;
  1313. //caller needs to find a new row that is larger that the current values for fields 0..i
  1314. //Now need to search for a value if
  1315. //Search for a new candidate value from this filter
  1316. return i+1;
  1317. }
  1318. //if (!filter.withinUpperRange(currentRow,
  1319. }
  1320. */
  1321. for (; field < filters.ordinality(); field++)
  1322. {
  1323. const IFieldFilter & filter = queryFilter(field);
  1324. //If the field is within a range return true and the range. If outside the range return the next range.
  1325. unsigned matchRange;
  1326. bool matched = filter.findForwardMatchRange(currentRow, matchRange);
  1327. if (!matched)
  1328. {
  1329. if (matchRange >= filter.numRanges())
  1330. return findNextRange(field);
  1331. nextUnmatchedRange = matchRange;
  1332. break;
  1333. }
  1334. matchedRanges.replace(matchRange, field);
  1335. }
  1336. numMatched = field;
  1337. return numMatched == filters.ordinality();
  1338. }
  1339. //The filter for field "field" has been exhausted, work out which value should be compared next
  1340. bool RowCursor::findNextRange(unsigned field)
  1341. {
  1342. unsigned matchRange;
  1343. for (;;)
  1344. {
  1345. if (field == 0)
  1346. {
  1347. eos = true;
  1348. return false;
  1349. }
  1350. field = field-1;
  1351. matchRange = matchedRanges.item(field);
  1352. const IFieldFilter & filter = queryFilter(field);
  1353. //If the field value is less than the upper bound of the current range, search for the next value above
  1354. //the current value
  1355. if (filter.compareHighest(currentRow, matchRange) < 0)
  1356. {
  1357. numMatched = field;
  1358. //MORE: Optimize the case where the field can be incremented - if so other fields can compare against lowest
  1359. //if (filter.incrementValue(currentRow))
  1360. // nextUnmatchedRange = 0;
  1361. //else
  1362. nextUnmatchedRange = -1U;
  1363. return false;
  1364. }
  1365. matchRange++;
  1366. if (matchRange < filter.numRanges())
  1367. break;
  1368. field--;
  1369. }
  1370. nextUnmatchedRange = matchRange;
  1371. numMatched = field-1;
  1372. return false;
  1373. }
  1374. //---------------------------------------------------------------------------------------------
  1375. class InMemoryRows
  1376. {
  1377. public:
  1378. InMemoryRows(size_t _countRows, const byte * * _rows, const RtlRecord & _record)
  1379. : countRows(_countRows), rows(_rows), record(_record)
  1380. {
  1381. }
  1382. const byte * queryRow(unsigned i) const { return rows[i]; }
  1383. size_t numRows() const { return countRows; }
  1384. const RtlRecord & queryRecord() const { return record; }
  1385. protected:
  1386. size_t countRows;
  1387. const byte * * rows;
  1388. const RtlRecord & record;
  1389. };
  1390. //Always has an even number of transitions
  1391. //Null transitions can be used at the start and end of the ranges to map anything
  1392. //equality conditions repeat the transition
  1393. class InMemoryRowCursor : public ISourceRowCursor
  1394. {
  1395. public:
  1396. InMemoryRowCursor(InMemoryRows & _source) : source(_source), seekRow(_source.queryRecord())
  1397. {
  1398. }
  1399. virtual const byte * findNext(const RowCursor & search) override
  1400. {
  1401. size_t numRows = source.numRows();
  1402. if (numRows == 0)
  1403. return nullptr;
  1404. size_t high = numRows;
  1405. size_t low = 0; // Could be cur
  1406. bool scanOnNext = false;
  1407. if (cur != 0 && scanOnNext)
  1408. {
  1409. //MORE: The next match is likely to be close, so first of all look for a match in the next few rows
  1410. //An always searching forwards, so can guarantee that it follows cur > low
  1411. }
  1412. //Find the value of low,high where all rows 0..low-1 are < search and rows low..max are >= search
  1413. while (low<high)
  1414. {
  1415. size_t mid = low + (high - low) / 2;
  1416. seekRow.setRow(source.queryRow(mid), search.numFilterFields());
  1417. int rc = search.compareNext(seekRow); // compare seekRow with the row we are hoping to find
  1418. if (rc < 0)
  1419. low = mid + 1; // if this row is lower than the seek row, exclude mid from the potential positions
  1420. else
  1421. high = mid; // otherwise exclude all above mid from the potential positions.
  1422. }
  1423. cur = low;
  1424. if (low == numRows)
  1425. return nullptr;
  1426. return source.queryRow(cur);
  1427. }
  1428. virtual const byte * next() override
  1429. {
  1430. cur++;
  1431. if (cur == source.numRows())
  1432. return nullptr;
  1433. return source.queryRow(cur);
  1434. }
  1435. virtual void reset() override
  1436. {
  1437. cur = 0;
  1438. seekRow.setRow(nullptr);
  1439. }
  1440. protected:
  1441. size_t cur = 0;
  1442. InMemoryRows & source;
  1443. RtlDynRow seekRow;
  1444. };
  1445. /*
  1446. Conclusions:
  1447. * Need compareLowest to be able to implement first()/ next with wildcards. Could implement with a typed lowest transition....
  1448. * Is it actually any different from start transition for most cases -
  1449. * index read is very efficient using a single memcmp when finding the next.
  1450. * Moving the compare into the transition makes the memcmp harder - although could be optimized + allow combining.
  1451. * The string sets should work on a field. The segmonitor should map row->field
  1452. * Could have multiple adjacent field fields once have variable length.
  1453. * Moving the compare into the transition makes index formats without decompression very tricky. Could possibly work around it by having a byte provider interface which could be called to get the next value.
  1454. *
  1455. *
  1456. */
  1457. #ifdef _USE_CPPUNIT
  1458. #include <cppunit/extensions/HelperMacros.h>
  1459. /*
  1460. class IStdException : extends std::exception
  1461. {
  1462. Owned<IException> jException;
  1463. public:
  1464. IStdException(IException *E) : jException(E) {};
  1465. };
  1466. */
  1467. //Scan a set of rows to find the matches - used to check that the keyed operations are correct
  1468. class RowScanner
  1469. {
  1470. public:
  1471. RowScanner(const RtlRecord & _info, RowFilter & _filter, const PointerArray & _rows) : rows(_rows), curRow(_info, nullptr), filter(_filter)
  1472. {
  1473. }
  1474. bool first()
  1475. {
  1476. return resolveNext(0);
  1477. }
  1478. bool next()
  1479. {
  1480. return resolveNext(curIndex+1);
  1481. }
  1482. bool resolveNext(unsigned next)
  1483. {
  1484. while (next < rows.ordinality())
  1485. {
  1486. curRow.setRow(rows.item(next));
  1487. if (filter.matches(curRow))
  1488. {
  1489. curIndex = next;
  1490. return true;
  1491. }
  1492. next++;
  1493. }
  1494. curIndex = next;
  1495. return false;
  1496. }
  1497. const RtlRow & queryRow() const { return curRow; }
  1498. protected:
  1499. const PointerArray & rows;
  1500. RtlDynRow curRow;
  1501. RowFilter & filter;
  1502. unsigned curIndex = 0;
  1503. };
  1504. static void addRange(IValueSet * set, const char * lower, const char * upper)
  1505. {
  1506. Owned<ValueTransition> lowerBound = lower ? set->createUtf8Transition(CMPge, rtlUtf8Length(strlen(lower), lower), lower) : nullptr;
  1507. Owned<ValueTransition> upperBound = upper ? set->createUtf8Transition(CMPle, rtlUtf8Length(strlen(upper), upper), upper) : nullptr;
  1508. set->addRange(lowerBound, upperBound);
  1509. };
  1510. class RawRowCompare : public ICompare
  1511. {
  1512. public:
  1513. RawRowCompare(const RtlRecord & _record) : record(_record) {}
  1514. virtual int docompare(const void * left,const void * right) const
  1515. {
  1516. return record.compare((const byte *)left, (const byte *)right);
  1517. }
  1518. const RtlRecord & record;
  1519. };
  1520. class ValueSetTest : public CppUnit::TestFixture
  1521. {
  1522. CPPUNIT_TEST_SUITE(ValueSetTest);
  1523. CPPUNIT_TEST(testKeyed2);
  1524. CPPUNIT_TEST(testRange);
  1525. CPPUNIT_TEST(testSerialize);
  1526. CPPUNIT_TEST(testUnion);
  1527. CPPUNIT_TEST(testExclude);
  1528. CPPUNIT_TEST(testInverse);
  1529. CPPUNIT_TEST(testIntersect);
  1530. CPPUNIT_TEST(testStr2);
  1531. CPPUNIT_TEST(testFilter);
  1532. CPPUNIT_TEST(testKeyed1);
  1533. CPPUNIT_TEST_SUITE_END();
  1534. protected:
  1535. void checkSet(const IValueSet * set, const char * expected)
  1536. {
  1537. StringBuffer temp;
  1538. set->serialize(temp);
  1539. if (!streq(expected, temp))
  1540. CPPUNIT_ASSERT_EQUAL(expected, temp.str());
  1541. }
  1542. void testRange(RtlTypeInfo & type, const char * low, const char * high, const char * expected)
  1543. {
  1544. Owned<IValueSet> set = createValueSet(type);
  1545. addRange(set, low, high);
  1546. checkSet(set, expected);
  1547. }
  1548. void testRangeStr1(const char * low, const char * high, const char * expected)
  1549. {
  1550. RtlStringTypeInfo str1(type_string, 1);
  1551. testRange(str1, low, high, expected);
  1552. }
  1553. void testRangeInt2(const char * low, const char * high, const char * expected)
  1554. {
  1555. RtlIntTypeInfo int2(type_int, 2);
  1556. testRange(int2, low, high, expected);
  1557. }
  1558. void testRangeStrX(const char * low, const char * high, const char * expected)
  1559. {
  1560. RtlStringTypeInfo type(type_string|RFTMunknownsize, 0);
  1561. testRange(type, low, high, expected);
  1562. }
  1563. void testRangeUniX(const char * low, const char * high, const char * expected)
  1564. {
  1565. RtlUnicodeTypeInfo type(type_string|RFTMunknownsize, 0, "");
  1566. testRange(type, low, high, expected);
  1567. }
  1568. void testRange()
  1569. {
  1570. testRangeStr1("A","Z","['A','Z']");
  1571. testRangeStr1("X","z","['X','z']");
  1572. testRangeStr1("Z","X","");
  1573. testRangeStr1(nullptr, "z","(,'z']");
  1574. testRangeStr1("Z", nullptr,"['Z',)");
  1575. testRangeStr1("A", "A","['A']");
  1576. testRangeStr1(nullptr, nullptr,"(,)");
  1577. testRangeStr1("é", "é","['é']"); // Test utf8 translation
  1578. testRangeStr1("AB", "ZX","['A','Z']");
  1579. testRangeInt2("0","1","[0,1]");
  1580. testRangeInt2("-1","1","[-1,1]");
  1581. testRangeInt2("-32768","32767","[-32768,32767]");
  1582. testRangeInt2("32768","0","[-32768,0]");
  1583. testRangeStrX("A", "Z","['A','Z']");
  1584. testRangeStrX("AB", "ZX","['AB','ZX']");
  1585. testRangeStrX("éèabc", "ab","");
  1586. testRangeStrX("a'b", "éèabc", "['a\\'b','éèabc']");
  1587. testRangeUniX("A", "Z","['A','Z']");
  1588. testRangeUniX("AB", "ZX","['AB','ZX']");
  1589. testRangeUniX("éèabc", "ab","");
  1590. testRangeUniX("a'b", "éèabc", "['a\\'b','éèabc']");
  1591. }
  1592. void testSerialize(RtlTypeInfo & type, const char * filter, const char * expected = nullptr)
  1593. {
  1594. Owned<IValueSet> set = createValueSet(type);
  1595. deserializeSet(*set, filter);
  1596. checkSet(set, expected ? expected : filter);
  1597. MemoryBuffer mb;
  1598. set->serialize(mb);
  1599. Owned<IValueSet> newset = createValueSet(type, mb);
  1600. checkSet(newset, expected ? expected : filter);
  1601. CPPUNIT_ASSERT(set->equals(*newset));
  1602. StringBuffer s;
  1603. set->serialize(s);
  1604. Owned<IValueSet> newset2 = createValueSet(type);
  1605. deserializeSet(*newset2, s);
  1606. CPPUNIT_ASSERT(set->equals(*newset2));
  1607. }
  1608. void testUnion(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  1609. {
  1610. Owned<IValueSet> set = createValueSet(type);
  1611. deserializeSet(*set, filter);
  1612. deserializeSet(*set, next);
  1613. checkSet(set, expected);
  1614. //test the arguments in the opposite order
  1615. Owned<IValueSet> set2 = createValueSet(type);
  1616. deserializeSet(*set2, next);
  1617. deserializeSet(*set2, filter);
  1618. checkSet(set, expected);
  1619. //test the arguments in the opposite order
  1620. Owned<IValueSet> set3a = createValueSet(type);
  1621. Owned<IValueSet> set3b = createValueSet(type);
  1622. deserializeSet(*set3a, next);
  1623. deserializeSet(*set3b, filter);
  1624. set3a->unionSet(set3b);
  1625. checkSet(set3a, expected);
  1626. }
  1627. void testSerialize()
  1628. {
  1629. RtlStringTypeInfo str1(type_string, 1);
  1630. RtlIntTypeInfo int2(type_int, 2);
  1631. RtlStringTypeInfo strx(type_string|RFTMunknownsize, 0);
  1632. RtlUtf8TypeInfo utf8(type_utf8|RFTMunknownsize, 0, nullptr);
  1633. testSerialize(int2, "[123]");
  1634. testSerialize(int2, "(123,234]");
  1635. testSerialize(int2, "[123,234)");
  1636. testSerialize(int2, "(123,234)");
  1637. testSerialize(int2, "(,234)");
  1638. testSerialize(int2, "(128,)");
  1639. testSerialize(int2, "(,)");
  1640. testSerialize(int2, "(123,234),(456,567)");
  1641. testSerialize(int2, "(456,567),(123,234)", "(123,234),(456,567)");
  1642. testSerialize(str1, "['A']");
  1643. testSerialize(str1, "[',']");
  1644. testSerialize(str1, "['\\'']");
  1645. testSerialize(str1, "['\\u0041']", "['A']");
  1646. testSerialize(str1, "['\\n']");
  1647. testSerialize(utf8, "['\\u611b']", "['愛']");
  1648. testSerialize(strx, "['\\'\\'','}']");
  1649. testSerialize(str1, "[A]", "['A']");
  1650. testSerialize(int2, "(123]", "");
  1651. testSerialize(int2, "[123)", "");
  1652. testSerialize(int2, "[1,0]", "");
  1653. }
  1654. void testUnion()
  1655. {
  1656. RtlIntTypeInfo int2(type_int, 2);
  1657. testSerialize(int2, "[3,5],[5,7]", "[3,7]");
  1658. testSerialize(int2, "[3,5],(5,7]", "[3,7]");
  1659. testSerialize(int2, "[3,5),[5,7]", "[3,7]");
  1660. testSerialize(int2, "[3,5),(5,7]");
  1661. testSerialize(int2, "[4],[4]", "[4]");
  1662. testSerialize(int2, "[4,5],[4]", "[4,5]");
  1663. testSerialize(int2, "[4,5],[5]", "[4,5]");
  1664. testUnion(int2, "[3,5]", "[,1]", "(,1],[3,5]");
  1665. testUnion(int2, "[3,5]", "[,3]", "(,5]");
  1666. testUnion(int2, "[3,5]", "[,4]", "(,5]");
  1667. testUnion(int2, "[3,5]", "[,]", "(,)");
  1668. testUnion(int2, "[3,5]", "[1,)", "[1,)");
  1669. testUnion(int2, "[3,5]", "[3,)", "[3,)");
  1670. testUnion(int2, "[3,5]", "[5,)", "[3,)");
  1671. testUnion(int2, "[3,5]", "(5,)", "[3,)");
  1672. testUnion(int2, "[3,5]", "[6,)", "[3,5],[6,)");
  1673. testUnion(int2, "[3,5]", "(6,)", "[3,5],(6,)");
  1674. testUnion(int2, "[4,7],[12,15]", "[1,1]", "[1],[4,7],[12,15]");
  1675. testUnion(int2, "[4,7],[12,15]", "[1,4)", "[1,7],[12,15]");
  1676. testUnion(int2, "[4,7],[12,15]", "[1,4]", "[1,7],[12,15]");
  1677. testUnion(int2, "[4,7],[12,15]", "[1,5)", "[1,7],[12,15]");
  1678. testUnion(int2, "[4,7],[12,15]", "[1,7)", "[1,7],[12,15]");
  1679. testUnion(int2, "[4,7],[12,15]", "[1,7]", "[1,7],[12,15]");
  1680. testUnion(int2, "[4,7],[12,15]", "[1,8]", "[1,8],[12,15]");
  1681. testUnion(int2, "[4,7],[12,15]", "[1,12)", "[1,15]");
  1682. testUnion(int2, "[4,7],[12,15]", "[1,12]", "[1,15]");
  1683. testUnion(int2, "[4,7],[12,15]", "[1,14]", "[1,15]");
  1684. testUnion(int2, "[4,7],[12,15]", "[1,15]", "[1,15]");
  1685. testUnion(int2, "[4,7],[12,15]", "[1,16]", "[1,16]");
  1686. testUnion(int2, "[4,7],[12,15]", "[1,17]", "[1,17]");
  1687. testUnion(int2, "[4,7],[12,15]", "(4,5)", "[4,7],[12,15]");
  1688. testUnion(int2, "[4,7],[12,15]", "(4,7)", "[4,7],[12,15]");
  1689. testUnion(int2, "[4,7],[12,15]", "(4,7]", "[4,7],[12,15]");
  1690. testUnion(int2, "[4,7],[12,15]", "(4,8]", "[4,8],[12,15]");
  1691. testUnion(int2, "[4,7],[12,15]", "(4,12)", "[4,15]");
  1692. testUnion(int2, "[4,7],[12,15]", "(4,12]", "[4,15]");
  1693. testUnion(int2, "[4,7],[12,15]", "[4,4]", "[4,7],[12,15]");
  1694. testUnion(int2, "[4,7],[12,15]", "[4,5)", "[4,7],[12,15]");
  1695. testUnion(int2, "[4,7],[12,15]", "[4,7)", "[4,7],[12,15]");
  1696. testUnion(int2, "[4,7],[12,15]", "[4,7]", "[4,7],[12,15]");
  1697. testUnion(int2, "[4,7],[12,15]", "[4,8]", "[4,8],[12,15]");
  1698. testUnion(int2, "[4,7],[12,15]", "[4,12)", "[4,15]");
  1699. testUnion(int2, "[4,7],[12,15]", "[4,12]", "[4,15]");
  1700. testUnion(int2, "[4,7],[12,15]", "[4,14]", "[4,15]");
  1701. testUnion(int2, "[4,7],[12,15]", "[4,15]", "[4,15]");
  1702. testUnion(int2, "[4,7],[12,15]", "[4,16]", "[4,16]");
  1703. testUnion(int2, "[4,7],[12,15]", "[4,17]", "[4,17]");
  1704. testUnion(int2, "[4,7],[12,15]", "(5,7)", "[4,7],[12,15]");
  1705. testUnion(int2, "[4,7],[12,15]", "(5,7]", "[4,7],[12,15]");
  1706. testUnion(int2, "[4,7],[12,15]", "(5,8]", "[4,8],[12,15]");
  1707. testUnion(int2, "[4,7],[12,15]", "(5,12)", "[4,15]");
  1708. testUnion(int2, "[4,7],[12,15]", "(5,12]", "[4,15]");
  1709. testUnion(int2, "[4,7],[12,15]", "(5,14]", "[4,15]");
  1710. testUnion(int2, "[4,7],[12,15]", "(5,15]", "[4,15]");
  1711. testUnion(int2, "[4,7],[12,15]", "(5,17]", "[4,17]");
  1712. testUnion(int2, "[4,7],[12,15]", "(7,8]", "[4,8],[12,15]");
  1713. testUnion(int2, "[4,7],[12,15]", "(7,8)", "[4,8),[12,15]");
  1714. testUnion(int2, "[4,7],[12,15]", "(7,12)", "[4,15]");
  1715. testUnion(int2, "[4,7],[12,15]", "(7,12]", "[4,15]");
  1716. testUnion(int2, "[4,7],[12,15]", "(7,14]", "[4,15]");
  1717. testUnion(int2, "[4,7],[12,15]", "(7,15]", "[4,15]");
  1718. testUnion(int2, "[4,7],[12,15]", "(7,17]", "[4,17]");
  1719. testUnion(int2, "[4,7],[12,15]", "[7,7]", "[4,7],[12,15]");
  1720. testUnion(int2, "[4,7],[12,15]", "[7,8]", "[4,8],[12,15]");
  1721. testUnion(int2, "[4,7],[12,15]", "[7,12)", "[4,15]");
  1722. testUnion(int2, "[4,7],[12,15]", "[7,17]", "[4,17]");
  1723. testUnion(int2, "[4,7],[12,15]", "[8,8]", "[4,7],[8],[12,15]");
  1724. testUnion(int2, "[4,7],[12,15]", "[8,12)", "[4,7],[8,15]");
  1725. testUnion(int2, "[4,7],[12,15]", "[8,12]", "[4,7],[8,15]");
  1726. testUnion(int2, "[4,7],[12,15]", "[8,14]", "[4,7],[8,15]");
  1727. testUnion(int2, "[4,7],[12,15]", "[8,15]", "[4,7],[8,15]");
  1728. testUnion(int2, "[4,7],[12,15]", "[8,16]", "[4,7],[8,16]");
  1729. testUnion(int2, "[4,7],[12,15]", "[8,17]", "[4,7],[8,17]");
  1730. testUnion(int2, "[4,7],[12,15]", "(8,11)", "[4,7],(8,11),[12,15]");
  1731. testUnion(int2, "[4,7],[12,15]", "(8,12)", "[4,7],(8,15]");
  1732. testUnion(int2, "[4,7],[12,15]", "(8,12]", "[4,7],(8,15]");
  1733. testUnion(int2, "[4,7],[12,15]", "(8,14]", "[4,7],(8,15]");
  1734. testUnion(int2, "[4,7],[12,15]", "(8,15]", "[4,7],(8,15]");
  1735. testUnion(int2, "[4,7],[12,15]", "(8,16]", "[4,7],(8,16]");
  1736. testUnion(int2, "[4,7],[12,15]", "(8,17]", "[4,7],(8,17]");
  1737. testUnion(int2, "[4,7],[12,15]", "(12,14]", "[4,7],[12,15]");
  1738. testUnion(int2, "[4,7],[12,15]", "(12,15]", "[4,7],[12,15]");
  1739. testUnion(int2, "[4,7],[12,15]", "(12,16]", "[4,7],[12,16]");
  1740. testUnion(int2, "[4,7],[12,15]", "(12,17]", "[4,7],[12,17]");
  1741. testUnion(int2, "[4,7],[12,15]", "[12,12]", "[4,7],[12,15]");
  1742. testUnion(int2, "[4,7],[12,15]", "[12,14]", "[4,7],[12,15]");
  1743. testUnion(int2, "[4,7],[12,15]", "[12,15]", "[4,7],[12,15]");
  1744. testUnion(int2, "[4,7],[12,15]", "[12,16]", "[4,7],[12,16]");
  1745. testUnion(int2, "[4,7],[12,15]", "[12,17]", "[4,7],[12,17]");
  1746. testUnion(int2, "[4,7],[12,15]", "[14,14]", "[4,7],[12,15]");
  1747. testUnion(int2, "[4,7],[12,15]", "[14,15]", "[4,7],[12,15]");
  1748. testUnion(int2, "[4,7],[12,15]", "[14,16]", "[4,7],[12,16]");
  1749. testUnion(int2, "[4,7],[12,15]", "[14,17]", "[4,7],[12,17]");
  1750. testUnion(int2, "[4,7],[12,15]", "[15]", "[4,7],[12,15]");
  1751. testUnion(int2, "[4,7],[12,15]", "[15,16]", "[4,7],[12,16]");
  1752. testUnion(int2, "[4,7],[12,15]", "[15,17]", "[4,7],[12,17]");
  1753. testUnion(int2, "[4,7],[12,15]", "[15,17)", "[4,7],[12,17)");
  1754. testUnion(int2, "[4,7],[12,15]", "[16]", "[4,7],[12,15],[16]");
  1755. testUnion(int2, "[4,7],[12,15]", "[16,17]", "[4,7],[12,15],[16,17]");
  1756. testUnion(int2, "[4,7],[12,15]", "[17]", "[4,7],[12,15],[17]");
  1757. testUnion(int2, "(4,7),(12,15)", "[1,1]", "[1],(4,7),(12,15)");
  1758. testUnion(int2, "(4,7),(12,15)", "[1,4)", "[1,4),(4,7),(12,15)");
  1759. testUnion(int2, "(4,7),(12,15)", "[1,4]", "[1,7),(12,15)");
  1760. testUnion(int2, "(4,7),(12,15)", "[1,5)", "[1,7),(12,15)");
  1761. testUnion(int2, "(4,7),(12,15)", "[1,7)", "[1,7),(12,15)");
  1762. testUnion(int2, "(4,7),(12,15)", "[1,7]", "[1,7],(12,15)");
  1763. testUnion(int2, "(4,7),(12,15)", "[1,8]", "[1,8],(12,15)");
  1764. testUnion(int2, "(4,7),(12,15)", "[1,12)", "[1,12),(12,15)");
  1765. testUnion(int2, "(4,7),(12,15)", "[1,12]", "[1,15)");
  1766. testUnion(int2, "(4,7),(12,15)", "[1,14]", "[1,15)");
  1767. testUnion(int2, "(4,7),(12,15)", "[1,15]", "[1,15]");
  1768. testUnion(int2, "(4,7),(12,15)", "[1,16]", "[1,16]");
  1769. testUnion(int2, "(4,7),(12,15)", "[1,17]", "[1,17]");
  1770. testUnion(int2, "(4,7),(12,15)", "(4,5)", "(4,7),(12,15)");
  1771. testUnion(int2, "(4,7),(12,15)", "(4,7)", "(4,7),(12,15)");
  1772. testUnion(int2, "(4,7),(12,15)", "(4,7]", "(4,7],(12,15)");
  1773. testUnion(int2, "(4,7),(12,15)", "(4,8]", "(4,8],(12,15)");
  1774. testUnion(int2, "(4,7),(12,15)", "(4,12)", "(4,12),(12,15)");
  1775. testUnion(int2, "(4,7),(12,15)", "(4,12]", "(4,15)");
  1776. testUnion(int2, "(4,7),(12,15)", "[4,4]", "[4,7),(12,15)");
  1777. testUnion(int2, "(4,7),(12,15)", "[4,5)", "[4,7),(12,15)");
  1778. testUnion(int2, "(4,7),(12,15)", "[4,7)", "[4,7),(12,15)");
  1779. testUnion(int2, "(4,7),(12,15)", "[4,7]", "[4,7],(12,15)");
  1780. testUnion(int2, "(4,7),(12,15)", "[4,8]", "[4,8],(12,15)");
  1781. testUnion(int2, "(4,7),(12,15)", "[4,12)", "[4,12),(12,15)");
  1782. testUnion(int2, "(4,7),(12,15)", "[4,12]", "[4,15)");
  1783. testUnion(int2, "(4,7),(12,15)", "[4,14]", "[4,15)");
  1784. testUnion(int2, "(4,7),(12,15)", "[4,15]", "[4,15]");
  1785. testUnion(int2, "(4,7),(12,15)", "[4,16]", "[4,16]");
  1786. testUnion(int2, "(4,7),(12,15)", "[4,17]", "[4,17]");
  1787. testUnion(int2, "(4,7),(12,15)", "(5,7)", "(4,7),(12,15)");
  1788. testUnion(int2, "(4,7),(12,15)", "(5,7]", "(4,7],(12,15)");
  1789. testUnion(int2, "(4,7),(12,15)", "(5,8]", "(4,8],(12,15)");
  1790. testUnion(int2, "(4,7),(12,15)", "(5,12)", "(4,12),(12,15)");
  1791. testUnion(int2, "(4,7),(12,15)", "(5,12]", "(4,15)");
  1792. testUnion(int2, "(4,7),(12,15)", "(5,14]", "(4,15)");
  1793. testUnion(int2, "(4,7),(12,15)", "(5,15]", "(4,15]");
  1794. testUnion(int2, "(4,7),(12,15)", "(5,17]", "(4,17]");
  1795. testUnion(int2, "(4,7),(12,15)", "(7,8]", "(4,7),(7,8],(12,15)");
  1796. testUnion(int2, "(4,7),(12,15)", "(7,8)", "(4,7),(7,8),(12,15)");
  1797. testUnion(int2, "(4,7),(12,15)", "(7,12)", "(4,7),(7,12),(12,15)");
  1798. testUnion(int2, "(4,7),(12,15)", "(7,12]", "(4,7),(7,15)");
  1799. testUnion(int2, "(4,7),(12,15)", "(7,14]", "(4,7),(7,15)");
  1800. testUnion(int2, "(4,7),(12,15)", "(7,15]", "(4,7),(7,15]");
  1801. testUnion(int2, "(4,7),(12,15)", "(7,17]", "(4,7),(7,17]");
  1802. testUnion(int2, "(4,7),(12,15)", "[7,7]", "(4,7],(12,15)");
  1803. testUnion(int2, "(4,7),(12,15)", "[7,8]", "(4,8],(12,15)");
  1804. testUnion(int2, "(4,7),(12,15)", "[7,12)", "(4,12),(12,15)");
  1805. testUnion(int2, "(4,7),(12,15)", "[7,17]", "(4,17]");
  1806. testUnion(int2, "(4,7),(12,15)", "[8,8]", "(4,7),[8],(12,15)");
  1807. testUnion(int2, "(4,7),(12,15)", "[8,12)", "(4,7),[8,12),(12,15)");
  1808. testUnion(int2, "(4,7),(12,15)", "[8,12]", "(4,7),[8,15)");
  1809. testUnion(int2, "(4,7),(12,15)", "[8,14]", "(4,7),[8,15)");
  1810. testUnion(int2, "(4,7),(12,15)", "[8,15]", "(4,7),[8,15]");
  1811. testUnion(int2, "(4,7),(12,15)", "[8,16]", "(4,7),[8,16]");
  1812. testUnion(int2, "(4,7),(12,15)", "[8,17]", "(4,7),[8,17]");
  1813. testUnion(int2, "(4,7),(12,15)", "(8,11)", "(4,7),(8,11),(12,15)");
  1814. testUnion(int2, "(4,7),(12,15)", "(8,12)", "(4,7),(8,12),(12,15)");
  1815. testUnion(int2, "(4,7),(12,15)", "(8,12]", "(4,7),(8,15)");
  1816. testUnion(int2, "(4,7),(12,15)", "(8,14]", "(4,7),(8,15)");
  1817. testUnion(int2, "(4,7),(12,15)", "(8,15]", "(4,7),(8,15]");
  1818. testUnion(int2, "(4,7),(12,15)", "(8,16]", "(4,7),(8,16]");
  1819. testUnion(int2, "(4,7),(12,15)", "(8,17]", "(4,7),(8,17]");
  1820. testUnion(int2, "(4,7),(12,15)", "(12,14]", "(4,7),(12,15)");
  1821. testUnion(int2, "(4,7),(12,15)", "(12,15]", "(4,7),(12,15]");
  1822. testUnion(int2, "(4,7),(12,15)", "(12,16]", "(4,7),(12,16]");
  1823. testUnion(int2, "(4,7),(12,15)", "(12,17]", "(4,7),(12,17]");
  1824. testUnion(int2, "(4,7),(12,15)", "[12,12]", "(4,7),[12,15)");
  1825. testUnion(int2, "(4,7),(12,15)", "[12,14]", "(4,7),[12,15)");
  1826. testUnion(int2, "(4,7),(12,15)", "[12,15]", "(4,7),[12,15]");
  1827. testUnion(int2, "(4,7),(12,15)", "[12,16]", "(4,7),[12,16]");
  1828. testUnion(int2, "(4,7),(12,15)", "[12,17]", "(4,7),[12,17]");
  1829. testUnion(int2, "(4,7),(12,15)", "[14,14]", "(4,7),(12,15)");
  1830. testUnion(int2, "(4,7),(12,15)", "[14,15]", "(4,7),(12,15]");
  1831. testUnion(int2, "(4,7),(12,15)", "[14,16]", "(4,7),(12,16]");
  1832. testUnion(int2, "(4,7),(12,15)", "[14,17]", "(4,7),(12,17]");
  1833. testUnion(int2, "(4,7),(12,15)", "[15]", "(4,7),(12,15]");
  1834. testUnion(int2, "(4,7),(12,15)", "[15,16]", "(4,7),(12,16]");
  1835. testUnion(int2, "(4,7),(12,15)", "(15,16]", "(4,7),(12,15),(15,16]");
  1836. testUnion(int2, "(4,7),(12,15)", "[15,17]", "(4,7),(12,17]");
  1837. testUnion(int2, "(4,7),(12,15)", "[15,17)", "(4,7),(12,17)");
  1838. testUnion(int2, "(4,7),(12,15)", "[16]", "(4,7),(12,15),[16]");
  1839. testUnion(int2, "(4,7),(12,15)", "[16,17]", "(4,7),(12,15),[16,17]");
  1840. testUnion(int2, "(4,7),(12,15)", "[17]", "(4,7),(12,15),[17]");
  1841. }
  1842. void testExclude(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  1843. {
  1844. Owned<IValueSet> set = createValueSet(type);
  1845. deserializeSet(*set, filter);
  1846. Owned<IValueSet> set2 = createValueSet(type);
  1847. deserializeSet(*set2, next);
  1848. set->excludeSet(set2);
  1849. checkSet(set, expected);
  1850. }
  1851. //Tests killRange which is used by excludeSet()
  1852. void testExclude()
  1853. {
  1854. RtlIntTypeInfo int2(type_int, 2);
  1855. testExclude(int2, "[4]", "(4,5]", "[4]");
  1856. testExclude(int2, "[4,7],[12,15]", "[1,1]", "[4,7],[12,15]");
  1857. testExclude(int2, "[4,7],[12,15]", "[1,4)", "[4,7],[12,15]");
  1858. testExclude(int2, "[4,7],[12,15]", "[1,4]", "(4,7],[12,15]");
  1859. testExclude(int2, "[4,7],[12,15]", "[1,5)", "[5,7],[12,15]");
  1860. testExclude(int2, "[4,7],[12,15]", "[1,7)", "[7],[12,15]");
  1861. testExclude(int2, "[4,7],[12,15]", "[1,7]", "[12,15]");
  1862. testExclude(int2, "[4,7],[12,15]", "(,)", "");
  1863. testExclude(int2, "[4,7],[12,15]", "(,12]", "(12,15]");
  1864. testExclude(int2, "[4,7],[12,15]", "(6,)", "[4,6]");
  1865. testExclude(int2, "[4,7],[12,15]", "[1,8]", "[12,15]");
  1866. testExclude(int2, "[4,7],[12,15]", "[1,12)", "[12,15]");
  1867. testExclude(int2, "[4,7],[12,15]", "[1,12]", "(12,15]");
  1868. testExclude(int2, "[4,7],[12,15]", "[1,14]", "(14,15]");
  1869. testExclude(int2, "[4,7],[12,15]", "[1,15]", "");
  1870. testExclude(int2, "[4,7],[12,15]", "[1,16]", "");
  1871. testExclude(int2, "[4,7],[12,15]", "(4,5)", "[4],[5,7],[12,15]");
  1872. testExclude(int2, "[4,7],[12,15]", "(4,7)", "[4],[7],[12,15]");
  1873. testExclude(int2, "[4,7],[12,15]", "(4,7]", "[4],[12,15]");
  1874. testExclude(int2, "[4,7],[12,15]", "(4,8]", "[4],[12,15]");
  1875. testExclude(int2, "[4,7],[12,15]", "(4,12)", "[4],[12,15]");
  1876. testExclude(int2, "[4,7],[12,15]", "(4,12]", "[4],(12,15]");
  1877. testExclude(int2, "[4,7],[12,15]", "[4,4]", "(4,7],[12,15]");
  1878. testExclude(int2, "[4,7],[12,15]", "[4,5)", "[5,7],[12,15]");
  1879. testExclude(int2, "[4,7],[12,15]", "[4,7)", "[7],[12,15]");
  1880. testExclude(int2, "[4,7],[12,15]", "[4,7]", "[12,15]");
  1881. testExclude(int2, "[4,7],[12,15]", "[4,8]", "[12,15]");
  1882. testExclude(int2, "[4,7],[12,15]", "[4,12)", "[12,15]");
  1883. testExclude(int2, "[4,7],[12,15]", "[4,12]", "(12,15]");
  1884. testExclude(int2, "[4,7],[12,15]", "[4,14]", "(14,15]");
  1885. testExclude(int2, "[4,7],[12,15]", "[4,15]", "");
  1886. testExclude(int2, "[4,7],[12,15]", "[4,16]", "");
  1887. testExclude(int2, "[4,7],[12,15]", "(5,7)", "[4,5],[7],[12,15]");
  1888. testExclude(int2, "[4,7],[12,15]", "(5,7]", "[4,5],[12,15]");
  1889. testExclude(int2, "[4,7],[12,15]", "(5,8]", "[4,5],[12,15]");
  1890. testExclude(int2, "[4,7],[12,15]", "(5,12)", "[4,5],[12,15]");
  1891. testExclude(int2, "[4,7],[12,15]", "(5,12]", "[4,5],(12,15]");
  1892. testExclude(int2, "[4,7],[12,15]", "(5,14]", "[4,5],(14,15]");
  1893. testExclude(int2, "[4,7],[12,15]", "(5,15)", "[4,5],[15]");
  1894. testExclude(int2, "[4,7],[12,15]", "(5,15]", "[4,5]");
  1895. testExclude(int2, "[4,7],[12,15]", "(5,17]", "[4,5]");
  1896. testExclude(int2, "[4,7],[12,15]", "(7,8]", "[4,7],[12,15]");
  1897. testExclude(int2, "[4,7],[12,15]", "(7,8)", "[4,7],[12,15]");
  1898. testExclude(int2, "[4,7],[12,15]", "(7,12)", "[4,7],[12,15]");
  1899. testExclude(int2, "[4,7],[12,15]", "(7,12]", "[4,7],(12,15]");
  1900. testExclude(int2, "[4,7],[12,15]", "(7,14]", "[4,7],(14,15]");
  1901. testExclude(int2, "[4,7],[12,15]", "(7,15]", "[4,7]");
  1902. testExclude(int2, "[4,7],[12,15]", "(7,17]", "[4,7]");
  1903. testExclude(int2, "[4,7],[12,15]", "[7,7]", "[4,7),[12,15]");
  1904. testExclude(int2, "[4,7],[12,15]", "[7,8]", "[4,7),[12,15]");
  1905. testExclude(int2, "[4,7],[12,15]", "[7,12)", "[4,7),[12,15]");
  1906. testExclude(int2, "[4,7],[12,15]", "[7,17]", "[4,7)");
  1907. testExclude(int2, "[4,7],[12,15]", "[8,8]", "[4,7],[12,15]");
  1908. testExclude(int2, "[4,7],[12,15]", "[8,12)", "[4,7],[12,15]");
  1909. testExclude(int2, "[4,7],[12,15]", "[8,12]", "[4,7],(12,15]");
  1910. testExclude(int2, "[4,7],[12,15]", "[8,14]", "[4,7],(14,15]");
  1911. testExclude(int2, "[4,7],[12,15]", "[8,15]", "[4,7]");
  1912. testExclude(int2, "[4,7],[12,15]", "[8,16]", "[4,7]");
  1913. testExclude(int2, "[4,7],[12,15]", "[8,17]", "[4,7]");
  1914. testExclude(int2, "[4,7],[12,15]", "(8,11)", "[4,7],[12,15]");
  1915. testExclude(int2, "[4,7],[12,15]", "(8,12)", "[4,7],[12,15]");
  1916. testExclude(int2, "[4,7],[12,15]", "(8,12]", "[4,7],(12,15]");
  1917. testExclude(int2, "[4,7],[12,15]", "(12,14]", "[4,7],[12],(14,15]");
  1918. testExclude(int2, "[4,7],[12,15]", "(12,15]", "[4,7],[12]");
  1919. testExclude(int2, "[4,7],[12,15]", "(12,16]", "[4,7],[12]");
  1920. testExclude(int2, "[4,7],[12,15]", "[12,12]", "[4,7],(12,15]");
  1921. testExclude(int2, "[4,7],[12,15]", "[12,14]", "[4,7],(14,15]");
  1922. testExclude(int2, "[4,7],[12,15]", "[12,15]", "[4,7]");
  1923. testExclude(int2, "[4,7],[12,15]", "[12,16]", "[4,7]");
  1924. testExclude(int2, "[4,7],[12,15]", "[14,14]", "[4,7],[12,14),(14,15]");
  1925. testExclude(int2, "[4,7],[12,15]", "[14,15]", "[4,7],[12,14)");
  1926. testExclude(int2, "[4,7],[12,15]", "[14,16]", "[4,7],[12,14)");
  1927. testExclude(int2, "[4,7],[12,15]", "[14,17]", "[4,7],[12,14)");
  1928. testExclude(int2, "[4,7],[12,15]", "[15]", "[4,7],[12,15)");
  1929. testExclude(int2, "[4,7],[12,15]", "[15,16]", "[4,7],[12,15)");
  1930. testExclude(int2, "[4,7],[12,15]", "[15,17]", "[4,7],[12,15)");
  1931. testExclude(int2, "[4,7],[12,15]", "[15,17)", "[4,7],[12,15)");
  1932. testExclude(int2, "[4,7],[12,15]", "[16]", "[4,7],[12,15]");
  1933. testExclude(int2, "(4,7),(12,15)", "[1,1]", "(4,7),(12,15)");
  1934. testExclude(int2, "(4,7),(12,15)", "[1,4)", "(4,7),(12,15)");
  1935. testExclude(int2, "(4,7),(12,15)", "[1,4]", "(4,7),(12,15)");
  1936. testExclude(int2, "(4,7),(12,15)", "[1,5)", "[5,7),(12,15)");
  1937. testExclude(int2, "(4,7),(12,15)", "[1,7)", "(12,15)");
  1938. testExclude(int2, "(4,7),(12,15)", "[1,7]", "(12,15)");
  1939. testExclude(int2, "(4,7),(12,15)", "[1,8]", "(12,15)");
  1940. testExclude(int2, "(4,7),(12,15)", "[1,12)", "(12,15)");
  1941. testExclude(int2, "(4,7),(12,15)", "[1,12]", "(12,15)");
  1942. testExclude(int2, "(4,7),(12,15)", "[1,14]", "(14,15)");
  1943. testExclude(int2, "(4,7),(12,15)", "[1,15]", "");
  1944. testExclude(int2, "(4,7),(12,15)", "[1,16]", "");
  1945. testExclude(int2, "(4,7),(12,15)", "(4,5)", "[5,7),(12,15)");
  1946. testExclude(int2, "(4,7),(12,15)", "(4,7)", "(12,15)");
  1947. testExclude(int2, "(4,7),(12,15)", "(4,7]", "(12,15)");
  1948. testExclude(int2, "(4,7),(12,15)", "(4,8]", "(12,15)");
  1949. testExclude(int2, "(4,7),(12,15)", "(4,12)", "(12,15)");
  1950. testExclude(int2, "(4,7),(12,15)", "(4,12]", "(12,15)");
  1951. testExclude(int2, "(4,7),(12,15)", "[4,4]", "(4,7),(12,15)");
  1952. testExclude(int2, "(4,7),(12,15)", "[4,5)", "[5,7),(12,15)");
  1953. testExclude(int2, "(4,7),(12,15)", "[4,7)", "(12,15)");
  1954. testExclude(int2, "(4,7),(12,15)", "[4,7]", "(12,15)");
  1955. testExclude(int2, "(4,7),(12,15)", "[4,8]", "(12,15)");
  1956. testExclude(int2, "(4,7),(12,15)", "[4,12)", "(12,15)");
  1957. testExclude(int2, "(4,7),(12,15)", "[4,12]", "(12,15)");
  1958. testExclude(int2, "(4,7),(12,15)", "[4,14]", "(14,15)");
  1959. testExclude(int2, "(4,7),(12,15)", "[4,15]", "");
  1960. testExclude(int2, "(4,7),(12,15)", "(5,6)", "(4,5],[6,7),(12,15)");
  1961. testExclude(int2, "(4,7),(12,15)", "(5,7)", "(4,5],(12,15)");
  1962. testExclude(int2, "(4,7),(12,15)", "(5,7]", "(4,5],(12,15)");
  1963. testExclude(int2, "(4,7),(12,15)", "(5,8]", "(4,5],(12,15)");
  1964. testExclude(int2, "(4,7),(12,15)", "(5,12)", "(4,5],(12,15)");
  1965. testExclude(int2, "(4,7),(12,15)", "(5,12]", "(4,5],(12,15)");
  1966. testExclude(int2, "(4,7),(12,15)", "(5,14]", "(4,5],(14,15)");
  1967. testExclude(int2, "(4,7),(12,15)", "(5,15]", "(4,5]");
  1968. testExclude(int2, "(4,7),(12,15)", "(5,17]", "(4,5]");
  1969. //return;
  1970. testExclude(int2, "(4,7),(12,15)", "(7,8]", "(4,7),(12,15)");
  1971. testExclude(int2, "(4,7),(12,15)", "(7,8)", "(4,7),(12,15)");
  1972. testExclude(int2, "(4,7),(12,15)", "(7,12)", "(4,7),(12,15)");
  1973. testExclude(int2, "(4,7),(12,15)", "(7,12]", "(4,7),(12,15)");
  1974. testExclude(int2, "(4,7),(12,15)", "(7,14]", "(4,7),(14,15)");
  1975. testExclude(int2, "(4,7),(12,15)", "(7,15]", "(4,7)");
  1976. testExclude(int2, "(4,7),(12,15)", "(7,17]", "(4,7)");
  1977. testExclude(int2, "(4,7),(12,15)", "[7,7]", "(4,7),(12,15)");
  1978. testExclude(int2, "(4,7),(12,15)", "[7,8]", "(4,7),(12,15)");
  1979. testExclude(int2, "(4,7),(12,15)", "[7,12)", "(4,7),(12,15)");
  1980. testExclude(int2, "(4,7),(12,15)", "[7,17]", "(4,7)");
  1981. testExclude(int2, "(4,7),(12,15)", "[8,8]", "(4,7),(12,15)");
  1982. testExclude(int2, "(4,7),(12,15)", "[8,12)", "(4,7),(12,15)");
  1983. testExclude(int2, "(4,7),(12,15)", "[8,12]", "(4,7),(12,15)");
  1984. testExclude(int2, "(4,7),(12,15)", "[8,14]", "(4,7),(14,15)");
  1985. testExclude(int2, "(4,7),(12,15)", "[8,15]", "(4,7)");
  1986. testExclude(int2, "(4,7),(12,15)", "[8,16]", "(4,7)");
  1987. testExclude(int2, "(4,7),(12,15)", "[8,17]", "(4,7)");
  1988. testExclude(int2, "(4,7),(12,15)", "(8,11)", "(4,7),(12,15)");
  1989. testExclude(int2, "(4,7),(12,15)", "(8,12)", "(4,7),(12,15)");
  1990. testExclude(int2, "(4,7),(12,15)", "(8,12]", "(4,7),(12,15)");
  1991. testExclude(int2, "(4,7),(12,15)", "(8,14]", "(4,7),(14,15)");
  1992. testExclude(int2, "(4,7),(12,15)", "(8,15]", "(4,7)");
  1993. testExclude(int2, "(4,7),(12,15)", "(8,16]", "(4,7)");
  1994. testExclude(int2, "(4,7),(12,15)", "(8,17]", "(4,7)");
  1995. testExclude(int2, "(4,7),(12,15)", "(12,14]", "(4,7),(14,15)");
  1996. testExclude(int2, "(4,7),(12,15)", "(12,15]", "(4,7)");
  1997. testExclude(int2, "(4,7),(12,15)", "(12,16]", "(4,7)");
  1998. testExclude(int2, "(4,7),(12,15)", "[12,12]", "(4,7),(12,15)");
  1999. testExclude(int2, "(4,7),(12,15)", "[13]", "(4,7),(12,13),(13,15)");
  2000. testExclude(int2, "(4,7),(12,15)", "[12,14)", "(4,7),[14,15)");
  2001. testExclude(int2, "(4,7),(12,15)", "[12,15)", "(4,7)");
  2002. testExclude(int2, "(4,7),(12,15)", "[12,16)", "(4,7)");
  2003. testExclude(int2, "(4,7),(12,15)", "[14,14]", "(4,7),(12,14),(14,15)");
  2004. testExclude(int2, "(4,7),(12,15)", "[14,15]", "(4,7),(12,14)");
  2005. testExclude(int2, "(4,7),(12,15)", "[14,16]", "(4,7),(12,14)");
  2006. testExclude(int2, "(4,7),(12,15)", "[15]", "(4,7),(12,15)");
  2007. }
  2008. void testInverse(RtlTypeInfo & type, const char * filter, const char * expected)
  2009. {
  2010. Owned<IValueSet> set = createValueSet(type);
  2011. deserializeSet(*set, filter);
  2012. set->invertSet();
  2013. checkSet(set, expected);
  2014. }
  2015. //Tests killRange which is used by excludeSet()
  2016. void testInverse()
  2017. {
  2018. RtlIntTypeInfo int2(type_int, 2);
  2019. testInverse(int2, "[4]", "(,4),(4,)");
  2020. testInverse(int2, "[4,5]", "(,4),(5,)");
  2021. testInverse(int2, "(4,5)", "(,4],[5,)");
  2022. testInverse(int2, "(,5)", "[5,)");
  2023. testInverse(int2, "[6,)", "(,6)");
  2024. testInverse(int2, "", "(,)");
  2025. testInverse(int2, "(,)", "");
  2026. testInverse(int2, "[4,5],(8,9),[12,14)", "(,4),(5,8],[9,12),[14,)");
  2027. }
  2028. void testIntersect(RtlTypeInfo & type, const char * filter, const char * next, const char * expected)
  2029. {
  2030. Owned<IValueSet> set = createValueSet(type);
  2031. deserializeSet(*set, filter);
  2032. Owned<IValueSet> set2 = createValueSet(type);
  2033. deserializeSet(*set2, next);
  2034. set->intersectSet(set2);
  2035. checkSet(set, expected);
  2036. //Test the opposite way around
  2037. Owned<IValueSet> seta = createValueSet(type);
  2038. deserializeSet(*seta, filter);
  2039. Owned<IValueSet> setb = createValueSet(type);
  2040. deserializeSet(*setb, next);
  2041. setb->intersectSet(seta);
  2042. checkSet(set, expected);
  2043. }
  2044. void testIntersect()
  2045. {
  2046. RtlIntTypeInfo int2(type_int, 2);
  2047. testIntersect(int2, "", "[1,2],(3,6)", "");
  2048. testIntersect(int2, "(,)", "[1,2],(3,6)", "[1,2],(3,6)");
  2049. testIntersect(int2, "(,)", "", "");
  2050. testIntersect(int2, "", "", "");
  2051. testIntersect(int2, "(,)", "(,)", "(,)");
  2052. testIntersect(int2, "(3,7),[10,20]", "[2]", "");
  2053. testIntersect(int2, "(3,7),[10,20]", "[3]", "");
  2054. testIntersect(int2, "(3,7),[10,20]", "[4]", "[4]");
  2055. testIntersect(int2, "(3,7),[10,20]", "[6]", "[6]");
  2056. testIntersect(int2, "(3,7),[10,20]", "[7]", "");
  2057. testIntersect(int2, "(3,7),[10,20]", "[10]", "[10]");
  2058. testIntersect(int2, "(3,7),[10,20]", "[20]", "[20]");
  2059. testIntersect(int2, "(3,7),[10,20]", "[21]", "");
  2060. testIntersect(int2, "(3,7),[10,20]", "[2,3]", "");
  2061. testIntersect(int2, "(3,7),[10,20]", "[2,5]", "(3,5]");
  2062. testIntersect(int2, "(3,7),[10,20]", "[2,7]", "(3,7)");
  2063. testIntersect(int2, "(3,7),[10,20]", "[2,8]", "(3,7)");
  2064. testIntersect(int2, "(3,7),[10,20]", "[2,10]", "(3,7),[10]");
  2065. testIntersect(int2, "(3,7),[10,20]", "[2,15]", "(3,7),[10,15]");
  2066. testIntersect(int2, "(3,7),[10,20]", "[2,20]", "(3,7),[10,20]");
  2067. testIntersect(int2, "(3,7),[10,20]", "[2,25]", "(3,7),[10,20]");
  2068. testIntersect(int2, "(3,7),[10,20]", "[3,3]", "");
  2069. testIntersect(int2, "(3,7),[10,20]", "[3,5]", "(3,5]");
  2070. testIntersect(int2, "(3,7),[10,20]", "[3,7]", "(3,7)");
  2071. testIntersect(int2, "(3,7),[10,20]", "[3,8]", "(3,7)");
  2072. testIntersect(int2, "(3,7),[10,20]", "[3,10]", "(3,7),[10]");
  2073. testIntersect(int2, "(3,7),[10,20]", "[3,15]", "(3,7),[10,15]");
  2074. testIntersect(int2, "(3,7),[10,20]", "[3,20]", "(3,7),[10,20]");
  2075. testIntersect(int2, "(3,7),[10,20]", "[3,25]", "(3,7),[10,20]");
  2076. testIntersect(int2, "(3,7),[10,20]", "[5,7]", "[5,7)");
  2077. testIntersect(int2, "(3,7),[10,20]", "[5,8]", "[5,7)");
  2078. testIntersect(int2, "(3,7),[10,20]", "[5,10]", "[5,7),[10]");
  2079. testIntersect(int2, "(3,7),[10,20]", "[5,15]", "[5,7),[10,15]");
  2080. testIntersect(int2, "(3,7),[10,20]", "[5,20]", "[5,7),[10,20]");
  2081. testIntersect(int2, "(3,7),[10,20]", "[5,25]", "[5,7),[10,20]");
  2082. testIntersect(int2, "(3,7),[10,20]", "[7,8]", "");
  2083. testIntersect(int2, "(3,7),[10,20]", "[7,10]", "[10]");
  2084. testIntersect(int2, "(3,7),[10,20]", "[7,15]", "[10,15]");
  2085. testIntersect(int2, "(3,7),[10,20]", "[7,20]", "[10,20]");
  2086. testIntersect(int2, "(3,7),[10,20]", "[7,25]", "[10,20]");
  2087. testIntersect(int2, "(3,7),[10,20]", "[10,15]", "[10,15]");
  2088. testIntersect(int2, "(3,7),[10,20]", "[10,20]", "[10,20]");
  2089. testIntersect(int2, "(3,7),[10,20]", "[10,25]", "[10,20]");
  2090. testIntersect(int2, "(3,7),[10,20]", "[15,20]", "[15,20]");
  2091. testIntersect(int2, "(3,7),[10,20]", "[15,25]", "[15,20]");
  2092. testIntersect(int2, "(3,7),[10,20]", "[20,25]", "[20]");
  2093. testIntersect(int2, "(3,7),[10,20]", "(2,3)", "");
  2094. testIntersect(int2, "(3,7),[10,20]", "(2,5)", "(3,5)");
  2095. testIntersect(int2, "(3,7),[10,20]", "(2,7)", "(3,7)");
  2096. testIntersect(int2, "(3,7),[10,20]", "(2,8)", "(3,7)");
  2097. testIntersect(int2, "(3,7),[10,20]", "(2,10)", "(3,7)");
  2098. testIntersect(int2, "(3,7),[10,20]", "(2,15)", "(3,7),[10,15)");
  2099. testIntersect(int2, "(3,7),[10,20]", "(2,20)", "(3,7),[10,20)");
  2100. testIntersect(int2, "(3,7),[10,20]", "(2,25)", "(3,7),[10,20]");
  2101. testIntersect(int2, "(3,7),[10,20]", "(3,5)", "(3,5)");
  2102. testIntersect(int2, "(3,7),[10,20]", "(3,7)", "(3,7)");
  2103. testIntersect(int2, "(3,7),[10,20]", "(3,8)", "(3,7)");
  2104. testIntersect(int2, "(3,7),[10,20]", "(3,10)", "(3,7)");
  2105. testIntersect(int2, "(3,7),[10,20]", "(3,15)", "(3,7),[10,15)");
  2106. testIntersect(int2, "(3,7),[10,20]", "(3,20)", "(3,7),[10,20)");
  2107. testIntersect(int2, "(3,7),[10,20]", "(3,25)", "(3,7),[10,20]");
  2108. testIntersect(int2, "(3,7),[10,20]", "(5,7)", "(5,7)");
  2109. testIntersect(int2, "(3,7),[10,20]", "(5,8)", "(5,7)");
  2110. testIntersect(int2, "(3,7),[10,20]", "(5,10)", "(5,7)");
  2111. testIntersect(int2, "(3,7),[10,20]", "(5,15)", "(5,7),[10,15)");
  2112. testIntersect(int2, "(3,7),[10,20]", "(5,20)", "(5,7),[10,20)");
  2113. testIntersect(int2, "(3,7),[10,20]", "(5,25)", "(5,7),[10,20]");
  2114. testIntersect(int2, "(3,7),[10,20]", "(7,8)", "");
  2115. testIntersect(int2, "(3,7),[10,20]", "(7,10)", "");
  2116. testIntersect(int2, "(3,7),[10,20]", "(7,15)", "[10,15)");
  2117. testIntersect(int2, "(3,7),[10,20]", "(7,20)", "[10,20)");
  2118. testIntersect(int2, "(3,7),[10,20]", "(7,25)", "[10,20]");
  2119. testIntersect(int2, "(3,7),[10,20]", "(10,15)", "(10,15)");
  2120. testIntersect(int2, "(3,7),[10,20]", "(10,20)", "(10,20)");
  2121. testIntersect(int2, "(3,7),[10,20]", "(15,20)", "(15,20)");
  2122. testIntersect(int2, "(3,7),[10,20]", "(15,25)", "(15,20]");
  2123. testIntersect(int2, "(3,7),[10,20]", "(20,25)", "");
  2124. testIntersect(int2, "(3,5),[7,10),[15,20),(30,32),[37]", "(4,7],(9,12),[13,31],(36,)", "(4,5),[7],(9,10),[15,20),(30,31],[37]");
  2125. }
  2126. void testStr2()
  2127. {
  2128. RtlStringTypeInfo str1(type_string, 1);
  2129. Owned<IValueSet> az = createValueSet(str1);
  2130. addRange(az, "A", "Z");
  2131. checkSet(az, "['A','Z']");
  2132. Owned<IValueSet> dj = createValueSet(str1);
  2133. addRange(dj, "D", "J");
  2134. checkSet(dj, "['D','J']");
  2135. Owned<IValueSet> hz = createValueSet(str1);
  2136. addRange(hz, "H", "Z");
  2137. Owned<IValueSet> jk = createValueSet(str1);
  2138. addRange(jk, "J", "K");
  2139. Owned<IValueSet> kj = createValueSet(str1);
  2140. addRange(kj, "K", "J");
  2141. checkSet(kj, "");
  2142. }
  2143. // id:int2 extra:string padding:! name:string2
  2144. // Keep in sorted order so they can be reused for index testing
  2145. const char *testRows[6] = {
  2146. "\001\000\004\000\000\000MARK!GH",
  2147. "\002\000\000\000\000\000!AB",
  2148. "\000\001\003\000\000\000FRY!JH",
  2149. "\001\001\003\000\000\000MAR!AC",
  2150. "\002\001\003\000\000\000MAS!JH",
  2151. "\003\002\004\000\000\000MASK!JH",
  2152. };
  2153. const RtlIntTypeInfo int2 = RtlIntTypeInfo(type_int, 2);
  2154. const RtlIntTypeInfo int4 = RtlIntTypeInfo(type_int, 4);
  2155. const RtlStringTypeInfo str1 = RtlStringTypeInfo(type_string, 1);
  2156. const RtlStringTypeInfo str2 = RtlStringTypeInfo(type_string, 2);
  2157. const RtlStringTypeInfo strx = RtlStringTypeInfo(type_string|RFTMunknownsize, 0);
  2158. const RtlFieldInfo id = RtlFieldInfo("id", nullptr, &int2);
  2159. const RtlFieldInfo extra = RtlFieldInfo("extra", nullptr, &strx);
  2160. const RtlFieldInfo padding = RtlFieldInfo("padding", nullptr, &str1);
  2161. const RtlFieldInfo name = RtlFieldInfo("name", nullptr, &str2);
  2162. const RtlFieldInfo * const fields[5] = { &id, &extra, &padding, &name, nullptr };
  2163. const RtlRecordTypeInfo recordType = RtlRecordTypeInfo(type_record, 4, fields);
  2164. const RtlRecord record = RtlRecord(recordType, true);
  2165. void processFilter(RowFilter & cursor, const char * originalFilter, const RtlRecord & searchRecord)
  2166. {
  2167. const char * filter = originalFilter;
  2168. while (filter && *filter)
  2169. {
  2170. StringBuffer next;
  2171. const char * semi = strchr(filter, ';');
  2172. if (semi)
  2173. {
  2174. next.append(semi-filter, filter);
  2175. filter = semi+1;
  2176. }
  2177. else
  2178. {
  2179. next.append(filter);
  2180. filter = nullptr;
  2181. }
  2182. const char * equal = strchr(next, '=');
  2183. assertex(equal);
  2184. StringBuffer fieldName(equal-next, next);
  2185. unsigned fieldNum = searchRecord.getFieldNum(fieldName);
  2186. assertex(fieldNum != (unsigned) -1);
  2187. const RtlTypeInfo *fieldType = searchRecord.queryType(fieldNum);
  2188. Owned<IValueSet> set = createValueSet(*fieldType);
  2189. deserializeSet(*set, equal+1);
  2190. cursor.addFilter(*new SetFieldFilter(fieldNum, set));
  2191. }
  2192. }
  2193. //testFilter("id=[1,3];name=(,GH)", { false, true, false, false, false });
  2194. void testFilter(const char * originalFilter, const std::initializer_list<bool> & expected)
  2195. {
  2196. const byte * * rows = reinterpret_cast<const byte * *>(testRows);
  2197. RowFilter cursor;
  2198. processFilter(cursor, originalFilter, record);
  2199. RtlDynRow row(record, nullptr);
  2200. assertex((expected.end() - expected.begin()) == (unsigned)_elements_in(testRows));
  2201. const bool * curExpected = expected.begin();
  2202. for (unsigned i= 0; i < _elements_in(testRows); i++)
  2203. {
  2204. row.setRow(rows[i]);
  2205. if (cursor.matches(row) != curExpected[i])
  2206. {
  2207. printf("Failure to match row %u filter '%s'\n", i, originalFilter);
  2208. CPPUNIT_ASSERT_EQUAL(curExpected[i], cursor.matches(row));
  2209. }
  2210. }
  2211. };
  2212. void testFilter()
  2213. {
  2214. testFilter("", { true, true, true, true, true, true });
  2215. testFilter("id=[1]", { true, false, false, false, false, false });
  2216. testFilter("id=[1],[2],[4],[6],[12],[23],[255],[256],[300],[301],[320]", { true, true, true, false, false, false });
  2217. testFilter("id=[1,2]", { true, true, false, false, false, false });
  2218. testFilter("id=(1,2]", { false, true, false, false, false, false });
  2219. testFilter("id=[1,3];name=(,GH)", { false, true, false, false, false, false });
  2220. testFilter("id=[1,3];name=(,GH]", { true, true, false, false, false, false });
  2221. testFilter("extra=['MAR','MAS']", { true, false, false, true, true, false });
  2222. testFilter("extra=('MAR','MAS')", { true, false, false, false, false, false });
  2223. testFilter("id=(,257]", { true, true, true, true, false, false });
  2224. }
  2225. void testKeyed(const char * originalFilter, const char * expected)
  2226. {
  2227. const byte * * rows = reinterpret_cast<const byte * *>(testRows);
  2228. RowFilter filter;
  2229. processFilter(filter, originalFilter, record);
  2230. InMemoryRows source(_elements_in(testRows), rows, record);
  2231. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2232. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2233. StringBuffer matches;
  2234. while (searcher.next())
  2235. {
  2236. searcher.queryRow().lazyCalcOffsets(1); // In unkeyed case we may not have calculated field 0 offset (though it is always going to be 0).
  2237. matches.append(searcher.queryRow().getInt(0)).append("|");
  2238. }
  2239. if (!streq(matches, expected))
  2240. {
  2241. printf("Failure to match expected keyed filter '%s' (%s, %s)\n", originalFilter, expected, matches.str());
  2242. CPPUNIT_ASSERT(streq(matches, expected));
  2243. }
  2244. }
  2245. void testKeyed1()
  2246. {
  2247. testKeyed("extra=['MAR','MAS']", "1|257|258|");
  2248. testKeyed("","1|2|256|257|258|515|");
  2249. testKeyed("id=[1,2]","1|2|");
  2250. testKeyed("id=[1],[256]","1|256|");
  2251. testKeyed("id=[1],[256,280]","1|256|257|258|");
  2252. testKeyed("id=[1],[256,280],[1000],[1023]","1|256|257|258|");
  2253. testKeyed("id=[1],[2],[4],[6],[12],[23],[255],[256],[300],[301],[320]","1|2|256|");
  2254. testKeyed("extra=['MAR','MAS']", "1|257|258|");
  2255. testKeyed("extra=('MAR','MAS')", "1|");
  2256. testKeyed("name=['AB','AC']", "2|257|");
  2257. }
  2258. void generateOrderedRows(PointerArray & rows, const RtlRecord & rowRecord)
  2259. {
  2260. //Generate rows with 3 fields. Try and ensure:
  2261. // each trailing field starts with 0, non zero.
  2262. // the third field has significant distribution in the number of elements for each value of field2
  2263. // duplicates occur in the full keyed values.
  2264. // sometimes the next value in sequence happens to match a trailing filter condition e.g. field3=1
  2265. //Last field First field x ranges from 0 to n1
  2266. //Second field
  2267. //Second field y ranges from 0 .. n2, and is included if (x + y) % 3 != 0 and (x + y) % 5 != 0
  2268. //Third field is sparse from 0..n3. m = ((x + y) % 11 ^2 + 1; if (n3 + x *2 + y) % m = 0 then it is included
  2269. unsigned n = 100000;
  2270. unsigned f1 = 0;
  2271. unsigned f2 = 0;
  2272. unsigned f3 = 0;
  2273. unsigned numf2 = 1;
  2274. unsigned countf2 = 0;
  2275. unsigned numf3 = 1;
  2276. unsigned countf3 = 0;
  2277. MemoryBuffer buff;
  2278. for (unsigned i = 0; i < n; i++)
  2279. {
  2280. buff.setLength(0);
  2281. MemoryBufferBuilder builder(buff, 0);
  2282. size32_t offset = 0;
  2283. offset = rowRecord.queryType(0)->buildInt(builder, offset, nullptr, f1);
  2284. offset = rowRecord.queryType(1)->buildInt(builder, offset, nullptr, f2);
  2285. offset = rowRecord.queryType(2)->buildInt(builder, offset, nullptr, f3);
  2286. byte * row = new byte[offset];
  2287. memcpy(row, buff.bufferBase(), offset);
  2288. rows.append(row);
  2289. unsigned pf2 = f2;
  2290. unsigned pf3 = f3;
  2291. if (++countf3 == numf3)
  2292. {
  2293. f2++;
  2294. if (++countf2 == numf2)
  2295. {
  2296. f1++;
  2297. f2 = i % 2;
  2298. numf2 = i % 23;
  2299. if (numf2 == 0)
  2300. {
  2301. f1++;
  2302. numf2 = (i % 21) + 1;
  2303. }
  2304. countf2 = 0;
  2305. }
  2306. f3 = i % 7;
  2307. countf3 = 0;
  2308. numf3 = i % 9;
  2309. if (numf3 == 0)
  2310. {
  2311. f3++;
  2312. numf3 = (i % 11) + 1;
  2313. }
  2314. }
  2315. if (i % 5)
  2316. f3++;
  2317. }
  2318. //Sort the rows - to allow different field types to be used.
  2319. RawRowCompare compareRow(rowRecord);
  2320. qsortvec(rows.getArray(), rows.ordinality(), compareRow);
  2321. }
  2322. void traceRow(const RtlRow & row)
  2323. {
  2324. printf("%u %u %u", (unsigned)row.getInt(0), (unsigned)row.getInt(1), (unsigned)row.getInt(2));
  2325. }
  2326. const RtlFieldInfo f1 = RtlFieldInfo("f1", nullptr, &int2);
  2327. const RtlFieldInfo f2 = RtlFieldInfo("f2", nullptr, &int2);
  2328. const RtlFieldInfo f3 = RtlFieldInfo("f3", nullptr, &int2);
  2329. const RtlFieldInfo * const testFields[4] = { &f1, &f2, &f3, nullptr };
  2330. const RtlRecordTypeInfo testRecordType = RtlRecordTypeInfo(type_record, 6, testFields);
  2331. const RtlRecord testRecord = RtlRecord(testRecordType, true);
  2332. void timeKeyedScan(const PointerArray & rows, const RtlRecord & searchRecord, const char * filterText)
  2333. {
  2334. RowFilter filter;
  2335. processFilter(filter, filterText, searchRecord);
  2336. CCycleTimer timeKeyed;
  2337. unsigned countKeyed = 0;
  2338. {
  2339. InMemoryRows source(rows.ordinality(), (const byte * *)rows.getArray(), searchRecord);
  2340. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2341. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2342. while (searcher.next())
  2343. {
  2344. countKeyed++;
  2345. }
  2346. }
  2347. unsigned __int64 keyedMs = timeKeyed.elapsedNs();
  2348. CCycleTimer timeScan;
  2349. unsigned countScan = 0;
  2350. {
  2351. RowScanner scanner(searchRecord, filter, rows);
  2352. bool hasSearch = scanner.first();
  2353. while (hasSearch)
  2354. {
  2355. countScan++;
  2356. hasSearch = scanner.next();
  2357. }
  2358. }
  2359. unsigned __int64 scanMs = timeScan.elapsedNs();
  2360. CPPUNIT_ASSERT_EQUAL(countScan, countKeyed);
  2361. printf("[%s] %u matches keyed(%" I64F "u) scan(%" I64F "u) (%.3f)\n", filterText, countScan, keyedMs, scanMs, (double)keyedMs/scanMs);
  2362. }
  2363. void testKeyed(const PointerArray & rows, const RtlRecord & searchRecord, const char * filterText)
  2364. {
  2365. RowFilter filter;
  2366. processFilter(filter, filterText, searchRecord);
  2367. InMemoryRows source(rows.ordinality(), (const byte * *)rows.getArray(), searchRecord);
  2368. InMemoryRowCursor sourceCursor(source); // could be created by source.createCursor()
  2369. KeySearcher searcher(source.queryRecord(), filter, &sourceCursor);
  2370. RowScanner scanner(source.queryRecord(), filter, rows);
  2371. unsigned count = 0;
  2372. bool hasSearch = searcher.next();
  2373. bool hasScan = scanner.first();
  2374. while (hasSearch && hasScan)
  2375. {
  2376. count++;
  2377. if (searchRecord.compare(searcher.queryRow().queryRow(), scanner.queryRow().queryRow()) != 0)
  2378. break;
  2379. hasSearch = searcher.next();
  2380. hasScan = scanner.next();
  2381. }
  2382. if (hasSearch || hasScan)
  2383. {
  2384. printf("[%s] Keyed: ", filterText);
  2385. if (hasSearch)
  2386. traceRow(searcher.queryRow());
  2387. else
  2388. printf("<missing>");
  2389. printf(" Scan: ");
  2390. if (hasScan)
  2391. traceRow(scanner.queryRow());
  2392. else
  2393. printf("<missing>");
  2394. printf("\n");
  2395. }
  2396. else
  2397. {
  2398. const bool compareTiming = true;
  2399. if (compareTiming)
  2400. timeKeyedScan(rows, searchRecord, filterText);
  2401. else
  2402. printf("[%s] %u matches\n", filterText, count);
  2403. }
  2404. }
  2405. void testKeyed2()
  2406. {
  2407. PointerArray rows;
  2408. generateOrderedRows(rows, testRecord);
  2409. testKeyed(rows, testRecord, "");
  2410. testKeyed(rows, testRecord, "f1=[5]");
  2411. testKeyed(rows, testRecord, "f1=[0]");
  2412. testKeyed(rows, testRecord, "f2=[1]");
  2413. testKeyed(rows, testRecord, "f3=[1]");
  2414. testKeyed(rows, testRecord, "f3=[4]");
  2415. testKeyed(rows, testRecord, "f3=[1,3]");
  2416. testKeyed(rows, testRecord, "f3=[1],[2],[3]");
  2417. testKeyed(rows, testRecord, "f1=[21];f2=[20];f3=[4]");
  2418. testKeyed(rows, testRecord, "f1=[7];f3=[5]");
  2419. testKeyed(rows, testRecord, "f1=[7,];f3=[,5]");
  2420. ForEachItemIn(i, rows)
  2421. delete [] (byte *)rows.item(i);
  2422. }
  2423. };
  2424. CPPUNIT_TEST_SUITE_REGISTRATION(ValueSetTest);
  2425. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ValueSetTest, "ValueSetTest");
  2426. #endif