hqlcppcase.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "jliball.hpp"
  15. #include "hql.hpp"
  16. #include "platform.h"
  17. #include "jlib.hpp"
  18. #include "jexcept.hpp"
  19. #include "jmisc.hpp"
  20. #include "hql.hpp"
  21. #include "hqlfunc.hpp"
  22. #include "hqlcpp.ipp"
  23. #include "hqlwcpp.hpp"
  24. #include "hqlutil.hpp"
  25. #include "hqlcpputil.hpp"
  26. #include "hqlcatom.hpp"
  27. #include "hqlcerrors.hpp"
  28. #define INTEGER_SEARCH_THRESHOLD 30 // above this, a table search is generated.
  29. #define MAX_NUM_NOBREAK_CASE 80 // maximum number of case: without a break - compiler workaround
  30. #define INLINE_COMPARE_THRESHOLD 2 // above this, a loop is generated
  31. #define SWITCH_TABLE_DENSITY_THRESHOLD 3 // % used before use array index.
  32. #define MAX_NESTED_CASES 8 // to stop C++ compiler running out of scopes.
  33. //===========================================================================
  34. static _ATOM searchDataTableAtom;
  35. static _ATOM searchEStringTableAtom;
  36. static _ATOM searchQStringTableAtom;
  37. static _ATOM searchStringTableAtom;
  38. static _ATOM searchVStringTableAtom;
  39. //===========================================================================
  40. MODULE_INIT(INIT_PRIORITY_STANDARD)
  41. {
  42. searchDataTableAtom = createIdentifierAtom("searchDataTable");
  43. searchEStringTableAtom = createIdentifierAtom("searchEStringTable");
  44. searchQStringTableAtom = createIdentifierAtom("searchQStringTable");
  45. searchStringTableAtom = createIdentifierAtom("searchStringTable");
  46. searchVStringTableAtom = createIdentifierAtom("searchVStringTable");
  47. return true;
  48. }
  49. MODULE_EXIT()
  50. {
  51. }
  52. //===========================================================================
  53. //Case helper functions...
  54. void cvtChooseListToPairs(HqlExprArray & target, IHqlExpression * from, unsigned base)
  55. {
  56. unsigned max = from->numChildren();
  57. unsigned idx;
  58. target.ensure(max);
  59. for (idx = 0; idx < max; idx++)
  60. {
  61. IHqlExpression * v1 = createConstant(createIntValue(idx+base, LINK(unsignedType)));
  62. IHqlExpression * v2 = from->queryChild(idx);
  63. ITypeInfo * type = v2->queryType();
  64. target.append(* createValue(no_mapto, LINK(type), v1, LINK(v2)));
  65. }
  66. }
  67. void cvtIndexListToPairs(HqlExprArray & target, IHqlExpression * from)
  68. {
  69. unsigned max = from->numChildren();
  70. unsigned idx;
  71. target.ensure(max);
  72. for (idx = 0; idx < max; idx++)
  73. {
  74. IHqlExpression * v1 = from->queryChild(idx);
  75. IHqlExpression * v2 = createConstant(createIntValue(idx+1, LINK(unsignedType)));
  76. ITypeInfo * type = v2->queryType();
  77. target.append(* createValue(no_mapto, LINK(type), LINK(v1), v2));
  78. }
  79. }
  80. void cvtInListToPairs(HqlExprArray & target, IHqlExpression * from, bool valueIfMatch)
  81. {
  82. unsigned max = from->numChildren();
  83. unsigned idx;
  84. IHqlExpression * tValue = queryBoolExpr(valueIfMatch);
  85. ITypeInfo * type = queryBoolType();
  86. target.ensure(max);
  87. for (idx = 0; idx < max; idx++)
  88. {
  89. IHqlExpression * v1 = from->queryChild(idx);
  90. target.append(* createValue(no_mapto, LINK(type), LINK(v1), LINK(tValue)));
  91. }
  92. }
  93. IHqlExpression * createNotFoundValue()
  94. {
  95. OwnedITypeInfo int4 = makeIntType(4, true);
  96. return createConstant(int4->castFrom(true, -1));
  97. }
  98. //===========================================================================
  99. static int comparePair(IInterface * * left, IInterface * * right)
  100. {
  101. IHqlExpression * lexpr = (IHqlExpression *)*left;
  102. IHqlExpression * rexpr = (IHqlExpression *)*right;
  103. return lexpr->queryChild(0)->queryValue()->compare(rexpr->queryChild(0)->queryValue());
  104. }
  105. HqlCppCaseInfo::HqlCppCaseInfo(HqlCppTranslator & _translator) : translator(_translator)
  106. {
  107. complexCompare = false;
  108. constantCases = true;
  109. constantValues = true;
  110. indexType.setown(makeIntType(sizeof(int), true));
  111. }
  112. void HqlCppCaseInfo::addPair(IHqlExpression * expr)
  113. {
  114. pairs.append(*LINK(expr));
  115. IHqlExpression * compareValue = expr->queryChild(0);
  116. if (!compareValue->queryValue())
  117. constantCases = false;
  118. if (!expr->queryChild(1)->queryValue())
  119. constantValues = false;
  120. if (cond && !complexCompare)
  121. {
  122. ITypeInfo * valueType = compareValue->queryType();
  123. if (valueType != cond->queryType())
  124. complexCompare = isCompare3Valued(compareValue->queryType());
  125. }
  126. updateResultType(expr->queryChild(1));
  127. }
  128. void HqlCppCaseInfo::addPairs(HqlExprArray & _pairs)
  129. {
  130. pairs.ensure(_pairs.ordinality());
  131. ForEachItemIn(idx, _pairs)
  132. addPair(&_pairs.item(idx));
  133. }
  134. bool HqlCppCaseInfo::buildAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  135. {
  136. if (pairs.ordinality() == 0)
  137. {
  138. translator.buildExprAssign(ctx, target, defaultValue);
  139. }
  140. else if (cond.get() && constantCases)
  141. {
  142. processBranches();
  143. BuildCtx subctx(ctx);
  144. CHqlBoundExpr test;
  145. buildSwitchCondition(ctx, test);
  146. if (complexCompare)
  147. {
  148. if ((pairs.ordinality() > INLINE_COMPARE_THRESHOLD) || (translator.getHints() & HintSize))
  149. {
  150. if (okToAlwaysEvaluateDefault() || hasLibraryChop())
  151. buildLoopChopMap(subctx, target, test);
  152. else
  153. buildGeneralAssign(subctx, target);
  154. }
  155. else
  156. {
  157. if (okToAlwaysEvaluateDefault())
  158. buildChop3Map(subctx, target, test);
  159. else
  160. buildGeneralAssign(subctx, target);
  161. }
  162. }
  163. else
  164. {
  165. ITypeInfo * condType = test.queryType()->queryPromotedType();
  166. if (!queryBuildArrayLookup(subctx, target, test))
  167. {
  168. if (condType->getTypeCode() != type_real)
  169. {
  170. OwnedHqlExpr search = test.getTranslatedExpr();
  171. if (constantValues && (condType->getTypeCode() == type_int) && (pairs.ordinality() > INTEGER_SEARCH_THRESHOLD))
  172. buildIntegerSearchMap(subctx, target, search);
  173. else
  174. buildSwitchMap(subctx, &target, test.expr);
  175. }
  176. else
  177. {
  178. if (okToAlwaysEvaluateDefault() && pairs.ordinality() > 4)
  179. {
  180. translator.buildExprAssign(ctx, target, defaultValue);
  181. buildChop2Map(subctx, target, test, 0, pairs.ordinality());
  182. }
  183. else
  184. buildGeneralAssign(subctx, target);
  185. }
  186. }
  187. }
  188. }
  189. else
  190. buildGeneralAssign(ctx, target);
  191. return true;
  192. }
  193. bool HqlCppCaseInfo::buildReturn(BuildCtx & ctx)
  194. {
  195. if (pairs.ordinality() == 0)
  196. {
  197. translator.buildReturn(ctx, defaultValue);
  198. }
  199. else if (cond.get() && constantCases)
  200. {
  201. processBranches();
  202. BuildCtx subctx(ctx);
  203. CHqlBoundExpr test;
  204. buildSwitchCondition(ctx, test);
  205. if (complexCompare)
  206. {
  207. buildGeneralReturn(subctx);
  208. }
  209. else
  210. {
  211. //if canBuildArrayLookup(test)
  212. //if use a lookup table to map value->constants
  213. if (test.queryType()->getTypeCode() != type_real)
  214. buildSwitchMap(subctx, NULL, test.expr);
  215. else
  216. buildGeneralReturn(subctx);
  217. }
  218. }
  219. else
  220. buildGeneralReturn(ctx);
  221. return true;
  222. }
  223. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test, IHqlExpression * temp, unsigned start, unsigned end)
  224. {
  225. if ((end - start) <= 2)
  226. buildChop2Map(ctx, target, test, start, end);
  227. else
  228. {
  229. unsigned mid = (start + end) / 2;
  230. generateCompareVar(ctx, temp, test, queryCompare(mid));
  231. OwnedHqlExpr test1 = createValue(no_eq, LINK(temp), getZero());
  232. OwnedHqlExpr test2 = createValue(no_lt, LINK(temp), getZero());
  233. BuildCtx subctx(ctx);
  234. IHqlStmt * if1 = subctx.addFilter(test1); // if (test == 0)
  235. translator.buildExprAssign(subctx, target, queryReturn(mid)); // target = value(n)
  236. subctx.selectElse(if1); // else
  237. IHqlStmt * if2 = subctx.addFilter(test2); // if (test < 0)
  238. buildChop3Map(subctx, target, test, temp, start, mid); // repeat for start..mid
  239. subctx.selectElse(if2); // else
  240. buildChop3Map(subctx, target, test, temp, mid+1, end); // repeat for min..end
  241. }
  242. }
  243. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test)
  244. {
  245. //need to hack it because there is no signed integer type
  246. OwnedHqlExpr tempVar = ctx.getTempDeclare(indexType, NULL);
  247. translator.buildExprAssign(ctx, target, defaultValue);
  248. buildChop3Map(ctx, target, test, tempVar, 0, getNumPairs());
  249. }
  250. void HqlCppCaseInfo::buildChop2Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test, unsigned start, unsigned end)
  251. {
  252. BuildCtx subctx(ctx);
  253. if ((end - start) <= 3) // (1,2,3) avg(2) cf. (2,2,3) avg(2.3)
  254. {
  255. //optimize the case where they all create the same value
  256. bool same = true;
  257. unsigned index;
  258. for (index=start+1; index < end; ++index)
  259. {
  260. if (queryReturn(index-1) != queryReturn(index))
  261. {
  262. same = false;
  263. break;
  264. }
  265. }
  266. if (same)
  267. {
  268. CompoundBuilder cb(no_or);
  269. for (index=start; index < end; ++index)
  270. {
  271. IHqlExpression * compare = queryCompare(index);
  272. IHqlExpression * cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  273. cb.addOperand(cond);
  274. }
  275. OwnedHqlExpr compound = cb.getCompound();
  276. translator.buildFilter(subctx, compound);
  277. translator.buildExprAssign(subctx, target, queryReturn(start));
  278. }
  279. else
  280. {
  281. IHqlStmt * stmt = NULL;
  282. for (index=start; index < end; ++index)
  283. {
  284. if (stmt)
  285. subctx.selectElse(stmt);
  286. IHqlExpression * compare = queryCompare(index);
  287. OwnedHqlExpr cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  288. CHqlBoundExpr bound;
  289. translator.buildExpr(subctx, cond, bound);
  290. stmt = subctx.addFilter(bound.expr);
  291. translator.buildExprAssign(subctx, target, queryReturn(index));
  292. }
  293. }
  294. }
  295. else
  296. {
  297. unsigned mid = (start + end) / 2;
  298. IHqlExpression * compare = queryCompare(mid);
  299. OwnedHqlExpr cond = createCompareExpr(no_lt, test.getTranslatedExpr(), LINK(compare));
  300. CHqlBoundExpr bound;
  301. translator.buildExpr(subctx, cond, bound);
  302. IHqlStmt * stmt = subctx.addFilter(bound.expr);
  303. buildChop2Map(subctx, target, test, start, mid);
  304. subctx.selectElse(stmt);
  305. buildChop2Map(subctx, target, test, mid, end);
  306. }
  307. }
  308. IHqlExpression * HqlCppCaseInfo::buildIndexedMap(BuildCtx & ctx, IHqlExpression * test, unsigned lower, unsigned upper)
  309. {
  310. ITypeInfo * compareType = test->queryType()->queryPromotedType();
  311. type_t compareTypeCode = compareType->getTypeCode();
  312. HqlExprArray values;
  313. IHqlExpression * dft = queryActiveTableSelector(); // value doesn't matter as long as it will not occur
  314. unsigned num = (upper-lower+1);
  315. values.ensure(num);
  316. unsigned idx;
  317. for (idx = 0; idx < num; idx++)
  318. values.append(*LINK(dft));
  319. ForEachItemIn(idx2, pairs)
  320. {
  321. IHqlExpression & cur = pairs.item(idx2);
  322. IValue * value = cur.queryChild(0)->queryValue();
  323. unsigned replaceIndex;
  324. switch (compareTypeCode)
  325. {
  326. case type_int:
  327. replaceIndex = (int)value->getIntValue()-lower;
  328. break;
  329. case type_string:
  330. {
  331. StringBuffer temp;
  332. value->getStringValue(temp);
  333. replaceIndex = (int)(unsigned char)temp.charAt(0)-lower;
  334. break;
  335. }
  336. default:
  337. throwUnexpectedType(compareType);
  338. }
  339. IHqlExpression * mapTo = cur.queryChild(1);
  340. if (mapTo->getOperator() != no_constant)
  341. throwUnexpected();
  342. if (replaceIndex >= num)
  343. translator.reportWarning(HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
  344. else
  345. values.replace(*LINK(mapTo),replaceIndex);
  346. }
  347. //Now replace the placeholders with the default values.
  348. for (idx = 0; idx < num; idx++)
  349. {
  350. if (&values.item(idx) == dft)
  351. values.replace(*defaultValue.getLink(),idx);
  352. }
  353. // use a var string type to get better C++ generated...
  354. ITypeInfo * storeType = getArrayElementType(resultType);
  355. ITypeInfo * listType = makeArrayType(storeType, values.ordinality());
  356. OwnedHqlExpr lvalues = createValue(no_list, listType, values);
  357. CHqlBoundExpr boundTable;
  358. translator.buildExpr(ctx, lvalues, boundTable);
  359. IHqlExpression * tableIndex;
  360. switch (compareTypeCode)
  361. {
  362. case type_int:
  363. tableIndex = LINK(test);
  364. break;
  365. case type_string:
  366. tableIndex = createValue(no_index, makeCharType(), LINK(test), getZero());
  367. break;
  368. default:
  369. throwUnexpectedType(compareType);
  370. }
  371. ITypeInfo * retType = resultType;
  372. IHqlExpression * ret = createValue(no_index, LINK(retType), LINK(boundTable.expr), tableIndex);
  373. return createTranslatedOwned(ret);
  374. }
  375. void HqlCppCaseInfo::buildLoopChopMap(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test)
  376. {
  377. //Declare a table that contains all the strings...
  378. ITypeInfo * compareType = queryCompareType();
  379. type_t ctc = compareType->getTypeCode();
  380. OwnedHqlExpr values = createCompareList();
  381. CHqlBoundExpr boundTable;
  382. translator.buildExpr(ctx, values, boundTable);
  383. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  384. if (hasLibraryChop())
  385. {
  386. ITypeInfo * tableEntryType = makeReferenceModifier(LINK(compareType));
  387. ITypeInfo * tableType = makePointerType(tableEntryType);
  388. HqlExprArray args;
  389. _ATOM func;
  390. switch (ctc)
  391. {
  392. case type_data:
  393. func = searchDataTableAtom;
  394. break;
  395. case type_varstring:
  396. func = searchVStringTableAtom;
  397. break;
  398. case type_qstring:
  399. func = searchQStringTableAtom;
  400. break;
  401. case type_string:
  402. if (compareType->queryCharset()->queryName() == asciiAtom)
  403. func = searchStringTableAtom;
  404. else if (compareType->queryCharset()->queryName() == ebcdicAtom)
  405. func = searchEStringTableAtom;
  406. else
  407. UNIMPLEMENTED;
  408. break;
  409. case type_unicode:
  410. func = searchUnicodeTableAtom;
  411. break;
  412. case type_utf8:
  413. func = searchUtf8TableAtom;
  414. break;
  415. case type_varunicode:
  416. func = searchVUnicodeTableAtom;
  417. break;
  418. default:
  419. throwUnexpectedType(compareType);
  420. }
  421. args.append(*getSizetConstant(values->numChildren()));
  422. if ((ctc != type_varstring) && (ctc != type_varunicode))
  423. args.append(*getSizetConstant(values->queryChild(0)->queryType()->getStringLen()));
  424. args.append(*createValue(no_address, tableType, createValue(no_index, LINK(tableEntryType), LINK(boundTable.expr), getZero())));
  425. if ((ctc != type_varstring) && (ctc != type_varunicode))
  426. args.append(*translator.getBoundLength(test));
  427. args.append(*ensureIndexable(test.expr));
  428. if ((ctc==type_unicode) || (ctc == type_varunicode) || (ctc == type_utf8))
  429. args.append(*createConstant(compareType->queryLocale()->str()));
  430. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(func, args);
  431. OwnedHqlExpr search = createTranslated(call);
  432. bool includeDefaultInResult = false;
  433. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  434. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  435. if (simpleResult)
  436. translator.buildExprAssign(ctx, target, simpleResult);
  437. else
  438. {
  439. ctx.addDeclare(midVar, NULL);
  440. translator.buildAssignToTemp(ctx, midVar, search);
  441. if (includeDefaultInResult)
  442. {
  443. translator.buildExprAssign(ctx, target, resultExpr);
  444. }
  445. else
  446. {
  447. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  448. BuildCtx subctx(ctx);
  449. IHqlStmt * stmt = subctx.addFilter(compare);
  450. translator.buildExprAssign(subctx, target, resultExpr);
  451. subctx.selectElse(stmt);
  452. translator.buildExprAssign(subctx, target, defaultValue);
  453. }
  454. }
  455. }
  456. else
  457. {
  458. #if 0
  459. //Keep this as a reminder of what was needed to fix qstrings.
  460. if (ctc == type_qstring)
  461. {
  462. Linked<ITypeInfo> compareType = queryCompareType();
  463. compareType.setown(makeArrayType(compareType.getLink()));
  464. table = createValue(no_typetransfer, compareType.getLink(), table);
  465. }
  466. #endif
  467. OwnedHqlExpr resultExpr = createResultsExpr(midVar, false);
  468. //Now generate the code that performs the binary chop..
  469. ctx.addDeclare(midVar, NULL);
  470. OwnedHqlExpr compareVar = ctx.getTempDeclare(indexType, NULL);
  471. OwnedHqlExpr leftVar = ctx.getTempDeclare(indexType, NULL);
  472. OwnedHqlExpr rightVar = ctx.getTempDeclare(indexType, NULL);
  473. OwnedHqlExpr numPairs = getSizetConstant(getNumPairs());
  474. ctx.addAssign(leftVar, queryZero());
  475. ctx.addAssign(rightVar, numPairs);
  476. translator.buildExprAssign(ctx, target, defaultValue);
  477. OwnedHqlExpr loopc = createBoolExpr(no_lt, LINK(leftVar), LINK(rightVar));
  478. OwnedHqlExpr mid = createValue(no_div, createValue(no_add, LINK(leftVar), LINK(rightVar)), createConstant(indexType->castFrom(false, 2)));
  479. OwnedHqlExpr mid_p1 = createValue(no_add, LINK(indexType), LINK(midVar), createConstant(indexType->castFrom(false, 1)));
  480. OwnedHqlExpr curelem = createValue(no_index, LINK(compareType), boundTable.getTranslatedExpr(), createTranslated(mid_p1));
  481. OwnedHqlExpr test1 = createBoolExpr(no_lt, LINK(compareVar), getZero());
  482. OwnedHqlExpr test2 = createBoolExpr(no_gt, LINK(compareVar), getZero());
  483. OwnedHqlExpr order = createValue(no_order, LINK(indexType), test.getTranslatedExpr(), LINK(curelem));
  484. BuildCtx loopctx(ctx);
  485. loopctx.addLoop(loopc, NULL, true);
  486. translator.buildAssignToTemp(loopctx, midVar, mid);
  487. translator.buildAssignToTemp(loopctx, compareVar, order);
  488. BuildCtx subctx(loopctx);
  489. IHqlStmt * if1 = subctx.addFilter(test1); // if (test < 0)
  490. translator.buildAssignToTemp(subctx, rightVar, midVar); // right = mid;
  491. subctx.selectElse(if1); // else
  492. IHqlStmt * if2 = subctx.addFilter(test2); // if (test > 0)
  493. translator.buildAssignToTemp(subctx, leftVar, mid_p1); // left = mid + 1;
  494. subctx.selectElse(if2); // else
  495. //generate the default assignment...
  496. translator.buildExprAssign(subctx, target, resultExpr);
  497. subctx.addBreak();
  498. }
  499. }
  500. void HqlCppCaseInfo::buildIntegerSearchMap(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * test)
  501. {
  502. ITypeInfo * compareType = queryCompareType();
  503. HqlExprArray args;
  504. args.append(*createCompareList());
  505. args.append(*LINK(test));
  506. _ATOM func;
  507. if (compareType->isSigned())
  508. {
  509. if (compareType->getSize() > 4)
  510. func = searchTableInteger8Atom;
  511. else
  512. func = searchTableInteger4Atom;
  513. }
  514. else
  515. {
  516. if (compareType->getSize() > 4)
  517. func = searchTableUInteger8Atom;
  518. else
  519. func = searchTableUInteger4Atom;
  520. }
  521. OwnedHqlExpr search = translator.bindFunctionCall(func, args);
  522. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  523. bool includeDefaultInResult = false;
  524. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  525. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  526. if (simpleResult)
  527. translator.buildExprAssign(ctx, target, simpleResult);
  528. else
  529. {
  530. ctx.addDeclare(midVar, NULL);
  531. translator.buildAssignToTemp(ctx, midVar, search);
  532. if (includeDefaultInResult)
  533. {
  534. translator.buildExprAssign(ctx, target, resultExpr);
  535. }
  536. else
  537. {
  538. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  539. BuildCtx subctx(ctx);
  540. IHqlStmt * stmt = subctx.addFilter(compare);
  541. translator.buildExprAssign(subctx, target, resultExpr);
  542. subctx.selectElse(stmt);
  543. translator.buildExprAssign(subctx, target, defaultValue);
  544. }
  545. }
  546. }
  547. void HqlCppCaseInfo::buildSwitchCondition(BuildCtx & ctx, CHqlBoundExpr & bound)
  548. {
  549. OwnedHqlExpr simpleCond = complexCompare ? getSimplifyCompareArg(cond) : LINK(cond);
  550. translator.buildCachedExpr(ctx, simpleCond, bound);
  551. }
  552. void HqlCppCaseInfo::buildSwitchMap(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * test)
  553. {
  554. bool isCharCompare = (test->queryType()->getTypeCode() == type_string);
  555. LinkedHqlExpr cond = test;
  556. if (isCharCompare)
  557. cond.setown(createValue(no_index, makeCharType(), LINK(test), getZero()));
  558. BuildCtx subctx(ctx);
  559. IHqlStmt * stmt = subctx.addSwitch(cond);
  560. // are all the comparisons against constant values? If so we optimize it...
  561. unsigned sameCount = 0;
  562. ForEachItemIn(idx, pairs)
  563. {
  564. IHqlExpression & cur = pairs.item(idx);
  565. LinkedHqlExpr compare = cur.queryChild(0);
  566. IHqlExpression * branchValue = cur.queryChild(1);
  567. if (isCharCompare)
  568. {
  569. OwnedITypeInfo charType = makeCharType();
  570. IValue * cur = compare->queryValue();
  571. IValue * next = cur->castTo(charType);
  572. compare.setown(createConstant(next));
  573. }
  574. bool same = false;
  575. bool skip = false;
  576. if (idx != pairs.ordinality()-1)
  577. {
  578. IHqlExpression & next = pairs.item(idx+1);
  579. if (next.queryChild(1) == branchValue)
  580. same = true;
  581. //if save item is included twice, remove one so no error
  582. //from the case statement
  583. if (next.queryChild(0) == cur.queryChild(0))
  584. {
  585. skip = true;
  586. #ifdef _DEBUG
  587. throwUnexpected(); // should have been removed as a duplicate
  588. #endif
  589. }
  590. }
  591. if (sameCount >= MAX_NUM_NOBREAK_CASE)
  592. same = false;
  593. if (!skip)
  594. {
  595. subctx.addCase(stmt, compare);
  596. // common up case labels that produce the same result
  597. if (!same)
  598. {
  599. sameCount = 1;
  600. if (target)
  601. translator.buildExprAssign(subctx, *target, branchValue);
  602. else
  603. translator.buildReturn(subctx, branchValue);
  604. }
  605. else
  606. sameCount++;
  607. }
  608. }
  609. if (target)
  610. {
  611. subctx.addDefault(stmt);
  612. translator.buildExprAssign(subctx, *target, defaultValue);
  613. }
  614. else
  615. translator.buildReturn(ctx, defaultValue);
  616. }
  617. void HqlCppCaseInfo::buildGeneralAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  618. {
  619. unsigned max = pairs.ordinality();
  620. Owned<BuildCtx> subctx = new BuildCtx(ctx);
  621. CHqlBoundExpr pureCond;
  622. if (cond.get())
  623. translator.buildCachedExpr(*subctx, cond, pureCond);
  624. OwnedHqlExpr testMore;
  625. if (max > MAX_NESTED_CASES)
  626. {
  627. //Too many nested blocks cause the compiler indigestion...
  628. Owned<ITypeInfo> t = makeBoolType();
  629. testMore.setown(ctx.getTempDeclare(t, queryBoolExpr(false)));
  630. }
  631. for (unsigned idx = 0; idx < max; idx++)
  632. {
  633. IHqlExpression & cur = pairs.item(idx);
  634. IHqlExpression * curtest = cur.queryChild(0);
  635. IHqlExpression * curvalue = cur.queryChild(1);
  636. OwnedHqlExpr compare;
  637. if (!pureCond.expr)
  638. compare.setown(ensureExprType(curtest, queryBoolType()));
  639. else
  640. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  641. if (idx && ((idx % MAX_NESTED_CASES) == 0))
  642. {
  643. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(true));
  644. subctx.setown(new BuildCtx(ctx));
  645. subctx->addFilter(testMore);
  646. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(false));
  647. }
  648. IHqlStmt * test = translator.buildFilterViaExpr(*subctx, compare);
  649. translator.buildExprAssign(*subctx, target, curvalue);
  650. subctx->selectElse(test);
  651. }
  652. translator.buildExprAssign(*subctx, target, defaultValue);
  653. }
  654. void HqlCppCaseInfo::buildGeneralReturn(BuildCtx & ctx)
  655. {
  656. unsigned max = pairs.ordinality();
  657. CHqlBoundExpr pureCond;
  658. if (cond.get())
  659. translator.buildCachedExpr(ctx, cond, pureCond);
  660. for (unsigned idx = 0; idx < max; idx++)
  661. {
  662. IHqlExpression & cur = pairs.item(idx);
  663. IHqlExpression * curtest = cur.queryChild(0);
  664. IHqlExpression * curvalue = cur.queryChild(1);
  665. OwnedHqlExpr compare;
  666. if (!pureCond.expr)
  667. compare.setown(ensureExprType(curtest, queryBoolType()));
  668. else
  669. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  670. BuildCtx subctx(ctx);
  671. translator.buildFilter(subctx, compare);
  672. translator.buildReturn(subctx, curvalue);
  673. }
  674. translator.buildReturn(ctx, defaultValue);
  675. }
  676. bool HqlCppCaseInfo::okToAlwaysEvaluateDefault()
  677. {
  678. return defaultValue->isPure();
  679. }
  680. ITypeInfo * HqlCppCaseInfo::queryCompareType()
  681. {
  682. return cond->queryType()->queryPromotedType();
  683. }
  684. IHqlExpression * HqlCppCaseInfo::createCompareList()
  685. {
  686. //NB: All cases need to have the same type because they are stored in a table
  687. Linked<ITypeInfo> promoted = pairs.item(0).queryChild(0)->queryType();
  688. unsigned max = pairs.ordinality();
  689. for (unsigned idx1 = 1; idx1 < max; idx1++)
  690. {
  691. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  692. promoted.setown(getPromotedECLType(promoted, type));
  693. }
  694. HqlExprArray values;
  695. values.ensure(pairs.ordinality());
  696. ForEachItemIn(idx, pairs)
  697. {
  698. IHqlExpression & pair = pairs.item(idx);
  699. IHqlExpression * compare = pair.queryChild(0);
  700. values.append(*ensureExprType(compare, promoted));
  701. }
  702. Linked<ITypeInfo> compareType = queryCompareType();
  703. switch (compareType->getTypeCode())
  704. {
  705. case type_string:
  706. case type_data:
  707. case type_varstring:
  708. case type_qstring:
  709. case type_utf8:
  710. compareType.setown(makePointerType(makeCharType(false)));
  711. break;
  712. case type_unicode:
  713. case type_varunicode:
  714. compareType.setown(makePointerType(makeClassType("UChar")));
  715. break;
  716. }
  717. return createValue(no_list, makeArrayType(compareType.getLink()), values);
  718. }
  719. IHqlExpression * HqlCppCaseInfo::createResultsExpr(IHqlExpression * matchVar, bool canIncludeDefault, bool * includedDefault)
  720. {
  721. if (includedDefault)
  722. *includedDefault = false;
  723. //Look at all the return results and see what relation we can create
  724. //This can generate one of the following:
  725. //1. A single value.
  726. //2. A function of the result. e.g., IN...
  727. //3. A lookup in another table. [ all values are constant ]
  728. //4. A nested map statement
  729. bool areSame = true;
  730. bool areLinear = true;
  731. bool areConstant = true;
  732. __int64 linearStart = 0;
  733. __int64 linearMultiple = 1;
  734. ITypeInfo * retType = resultType;
  735. switch (retType->getTypeCode())
  736. {
  737. case type_int:
  738. case type_boolean:
  739. break;
  740. case type_string:
  741. case type_data:
  742. // areConstant = false; // a temporary hack to stop incorrect table being generated.
  743. areLinear = false;
  744. break;
  745. default:
  746. areLinear = false;
  747. break;
  748. }
  749. IHqlExpression * prevValue = NULL;
  750. HqlExprArray values;
  751. values.ensure(pairs.ordinality());
  752. ForEachItemIn(idx, pairs)
  753. {
  754. IHqlExpression & pair = pairs.item(idx);
  755. IHqlExpression * value = pair.queryChild(1);
  756. IValue * cvalue = value->queryValue();
  757. if (cvalue)
  758. {
  759. if (areLinear)
  760. {
  761. __int64 val = cvalue->getIntValue();
  762. if (idx == 0)
  763. linearStart = val;
  764. else if (idx == 1)
  765. linearMultiple = (val - linearStart);
  766. else if (val != linearStart + idx * linearMultiple)
  767. areLinear = false;
  768. }
  769. }
  770. else
  771. {
  772. areConstant = false;
  773. areLinear = false;
  774. }
  775. if (idx > 0)
  776. {
  777. if (areSame && (prevValue != value))
  778. areSame = false;
  779. }
  780. values.append(*ensureExprType(value, resultType));
  781. prevValue = value;
  782. }
  783. if (areSame)
  784. return LINK(prevValue);
  785. if (areLinear)
  786. {
  787. IHqlExpression * ret = ensureExprType(matchVar, resultType);
  788. if (linearMultiple != 1)
  789. ret = createValue(no_mul, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearMultiple)));
  790. if (linearStart != 0)
  791. ret = createValue(no_add, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearStart)));
  792. return ret;
  793. }
  794. unsigned firstMatchEntry = 0;
  795. if (canIncludeDefault)
  796. {
  797. //If all the values are constant, then can add the default as an extra 0th entry, because -1 will be the index for the default
  798. if (areConstant && defaultValue->isConstant() && defaultValue->queryType() == values.item(0).queryType())
  799. {
  800. firstMatchEntry = 1;
  801. values.add(*LINK(defaultValue), 0);
  802. *includedDefault = true;
  803. }
  804. }
  805. // easy way to create a value list...
  806. ITypeInfo * storeType = getArrayElementType(retType);
  807. OwnedHqlExpr newlist = createValue(no_list, makeSetType(storeType), values);
  808. if (areConstant)
  809. {
  810. IHqlExpression * index = adjustValue(matchVar, 1+firstMatchEntry);
  811. return createValue(no_index, LINK(retType), LINK(newlist), index, createAttribute(noBoundCheckAtom));
  812. }
  813. //Need to generate a case (switch integer case 1: ..... )
  814. HqlExprArray choosePairs;
  815. cvtChooseListToPairs(choosePairs, newlist, 0);
  816. IHqlExpression * caseExpr = createOpenValue(no_case, LINK(retType));
  817. caseExpr->addOperand(LINK(matchVar));
  818. ForEachItemIn(idx2, choosePairs)
  819. caseExpr->addOperand(&choosePairs.item(idx2));
  820. choosePairs.kill(true);
  821. caseExpr->addOperand(LINK(defaultValue));
  822. return caseExpr->closeExpr();
  823. }
  824. void HqlCppCaseInfo::generateCompareVar(BuildCtx & ctx, IHqlExpression * target, CHqlBoundExpr & test, IHqlExpression * other)
  825. {
  826. OwnedHqlExpr compare = createValue(no_order, test.getTranslatedExpr(), LINK(other));
  827. translator.buildAssignToTemp(ctx, target, compare);
  828. }
  829. unsigned HqlCppCaseInfo::getNumPairs()
  830. {
  831. return pairs.ordinality();
  832. }
  833. bool HqlCppCaseInfo::hasLibraryChop()
  834. {
  835. ITypeInfo * compareType = queryCompareType();
  836. type_t ctc = compareType->getTypeCode();
  837. return ((ctc == type_string) || (ctc == type_data) || (ctc == type_varstring) || (ctc == type_qstring) || (ctc == type_unicode) || (ctc == type_varunicode) || (ctc == type_utf8));
  838. }
  839. void HqlCppCaseInfo::processBranches()
  840. {
  841. sortPairs();
  842. removeDuplicates();
  843. promoteTypes();
  844. }
  845. void HqlCppCaseInfo::promoteTypes()
  846. {
  847. Owned<ITypeInfo> promoted = pairs.item(0).queryChild(0)->getType();
  848. unsigned max = pairs.ordinality();
  849. for (unsigned idx1 = 1; idx1 < max; idx1++)
  850. {
  851. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  852. if (isStringType(promoted) && isStringType(type))
  853. {
  854. if (promoted->getStringLen() != type->getStringLen())
  855. {
  856. promoted.setown(::getPromotedECLType(promoted, type));
  857. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  858. }
  859. }
  860. promoted.setown(::getPromotedECLType(promoted, type));
  861. }
  862. if (isStringType(promoted))
  863. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  864. ITypeInfo * testType = queryCompareType();
  865. if ((testType->queryCharset() != promoted->queryCharset()) || (testType->queryLocale() != promoted->queryLocale()))
  866. cond.setown(ensureExprType(cond, promoted));
  867. }
  868. bool HqlCppCaseInfo::canBuildArrayLookup(const CHqlBoundExpr & test)
  869. {
  870. ITypeInfo * condType = test.queryType()->queryPromotedType();
  871. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  872. unsigned bitSize = condType->getBitSize();
  873. if (constantValues && (bitSize && (bitSize <= 8) && !condType->isSigned()))
  874. {
  875. unsigned limit = (1 << bitSize);
  876. //use case if enough items, or above a certain density...
  877. if (pairs.ordinality() * 100 >= limit * SWITCH_TABLE_DENSITY_THRESHOLD)
  878. {
  879. if ((condType->getTypeCode() == type_int) || (condType->getTypeCode() == type_string))
  880. return true;
  881. }
  882. }
  883. return false;
  884. }
  885. bool HqlCppCaseInfo::queryBuildArrayLookup(BuildCtx & ctx, const CHqlBoundTarget & target, const CHqlBoundExpr & test)
  886. {
  887. if (canBuildArrayLookup(test))
  888. {
  889. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  890. ITypeInfo * condType = test.queryType()->queryPromotedType();
  891. unsigned bitSize = condType->getBitSize();
  892. unsigned limit = (1 << bitSize);
  893. BuildCtx subctx(ctx);
  894. OwnedHqlExpr ret = buildIndexedMap(subctx, test.expr, 0, limit-1);
  895. translator.buildExprAssign(ctx, target, ret);
  896. return true;
  897. }
  898. return false;
  899. }
  900. void HqlCppCaseInfo::removeDuplicates()
  901. {
  902. unsigned num = pairs.ordinality();
  903. if (num > 1)
  904. {
  905. num--;
  906. while (num--)
  907. {
  908. IHqlExpression & cur = pairs.item(num);
  909. IHqlExpression & next = pairs.item(num+1);
  910. if (cur.queryChild(0) == next.queryChild(0))
  911. {
  912. if (cur.queryChild(1) == next.queryChild(1))
  913. pairs.remove(num+1);
  914. else
  915. {
  916. // we need to keep the first in the original list.... Horrid, but it works...
  917. unsigned off1 = originalPairs.find(cur);
  918. unsigned off2 = originalPairs.find(next);
  919. assertex(off1 != NotFound && off2 != NotFound);
  920. if (off1 < off2)
  921. pairs.remove(num+1);
  922. else
  923. pairs.remove(num);
  924. }
  925. }
  926. }
  927. }
  928. }
  929. IHqlExpression * HqlCppCaseInfo::queryCreateSimpleResultAssign(IHqlExpression * search, IHqlExpression * resultExpr)
  930. {
  931. IHqlExpression * trueExpr = queryBoolExpr(true);
  932. IHqlExpression * falseExpr = queryBoolExpr(false);
  933. if (resultExpr == trueExpr && defaultValue == falseExpr)
  934. return createBoolExpr(no_ne, LINK(search), createNotFoundValue());
  935. if (resultExpr == falseExpr && defaultValue == trueExpr)
  936. return createBoolExpr(no_eq, LINK(search), createNotFoundValue());
  937. return NULL;
  938. }
  939. IHqlExpression * HqlCppCaseInfo::queryCompare(unsigned index)
  940. {
  941. return pairs.item(index).queryChild(0);
  942. }
  943. IHqlExpression * HqlCppCaseInfo::queryReturn(unsigned index)
  944. {
  945. return pairs.item(index).queryChild(1);
  946. }
  947. void HqlCppCaseInfo::setCond(IHqlExpression * expr)
  948. {
  949. cond.set(expr);
  950. if (isCompare3Valued(expr->queryType()))
  951. complexCompare = true;
  952. }
  953. void HqlCppCaseInfo::setDefault(IHqlExpression * expr)
  954. {
  955. defaultValue.set(expr);
  956. }
  957. void HqlCppCaseInfo::sortPairs()
  958. {
  959. appendArray(originalPairs, pairs);
  960. pairs.sort(comparePair);
  961. }
  962. void HqlCppCaseInfo::updateResultType(IHqlExpression * expr)
  963. {
  964. ITypeInfo * curResultType = expr->queryType();
  965. if (resultType)
  966. resultType.setown(::getPromotedECLType(resultType, curResultType));
  967. else
  968. resultType.set(curResultType);
  969. }