hqlcppcase.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146
  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) && canBuildStaticList(resultType))
  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. translator.buildExprAssign(ctx, target, defaultValue);
  246. if (getNumPairs() <= 2)
  247. {
  248. buildChop2Map(ctx, target, test, 0, getNumPairs());
  249. }
  250. else
  251. {
  252. //need to hack it because there is no signed integer type
  253. OwnedHqlExpr tempVar = ctx.getTempDeclare(indexType, NULL);
  254. buildChop3Map(ctx, target, test, tempVar, 0, getNumPairs());
  255. }
  256. }
  257. void HqlCppCaseInfo::buildChop2Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test, unsigned start, unsigned end)
  258. {
  259. BuildCtx subctx(ctx);
  260. if ((end - start) <= 3) // (1,2,3) avg(2) cf. (2,2,3) avg(2.3)
  261. {
  262. //optimize the case where they all create the same value
  263. bool same = true;
  264. unsigned index;
  265. for (index=start+1; index < end; ++index)
  266. {
  267. if (queryReturn(index-1) != queryReturn(index))
  268. {
  269. same = false;
  270. break;
  271. }
  272. }
  273. if (same)
  274. {
  275. CompoundBuilder cb(no_or);
  276. for (index=start; index < end; ++index)
  277. {
  278. IHqlExpression * compare = queryCompare(index);
  279. IHqlExpression * cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  280. cb.addOperand(cond);
  281. }
  282. OwnedHqlExpr compound = cb.getCompound();
  283. translator.buildFilter(subctx, compound);
  284. translator.buildExprAssign(subctx, target, queryReturn(start));
  285. }
  286. else
  287. {
  288. IHqlStmt * stmt = NULL;
  289. for (index=start; index < end; ++index)
  290. {
  291. if (stmt)
  292. subctx.selectElse(stmt);
  293. IHqlExpression * compare = queryCompare(index);
  294. OwnedHqlExpr cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  295. CHqlBoundExpr bound;
  296. translator.buildExpr(subctx, cond, bound);
  297. stmt = subctx.addFilter(bound.expr);
  298. translator.buildExprAssign(subctx, target, queryReturn(index));
  299. }
  300. }
  301. }
  302. else
  303. {
  304. unsigned mid = (start + end) / 2;
  305. IHqlExpression * compare = queryCompare(mid);
  306. OwnedHqlExpr cond = createCompareExpr(no_lt, test.getTranslatedExpr(), LINK(compare));
  307. CHqlBoundExpr bound;
  308. translator.buildExpr(subctx, cond, bound);
  309. IHqlStmt * stmt = subctx.addFilter(bound.expr);
  310. buildChop2Map(subctx, target, test, start, mid);
  311. subctx.selectElse(stmt);
  312. buildChop2Map(subctx, target, test, mid, end);
  313. }
  314. }
  315. IHqlExpression * HqlCppCaseInfo::buildIndexedMap(BuildCtx & ctx, IHqlExpression * test, unsigned lower, unsigned upper)
  316. {
  317. ITypeInfo * compareType = test->queryType()->queryPromotedType();
  318. type_t compareTypeCode = compareType->getTypeCode();
  319. HqlExprArray values;
  320. IHqlExpression * dft = queryActiveTableSelector(); // value doesn't matter as long as it will not occur
  321. unsigned num = (upper-lower+1);
  322. values.ensure(num);
  323. unsigned idx;
  324. for (idx = 0; idx < num; idx++)
  325. values.append(*LINK(dft));
  326. ForEachItemIn(idx2, pairs)
  327. {
  328. IHqlExpression & cur = pairs.item(idx2);
  329. IValue * value = cur.queryChild(0)->queryValue();
  330. unsigned replaceIndex;
  331. switch (compareTypeCode)
  332. {
  333. case type_int:
  334. replaceIndex = (int)value->getIntValue()-lower;
  335. break;
  336. case type_string:
  337. {
  338. StringBuffer temp;
  339. value->getStringValue(temp);
  340. replaceIndex = (int)(unsigned char)temp.charAt(0)-lower;
  341. break;
  342. }
  343. default:
  344. throwUnexpectedType(compareType);
  345. }
  346. IHqlExpression * mapTo = cur.queryChild(1);
  347. if (mapTo->getOperator() != no_constant)
  348. throwUnexpected();
  349. if (replaceIndex >= num)
  350. translator.reportWarning(HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
  351. else
  352. values.replace(*LINK(mapTo),replaceIndex);
  353. }
  354. //Now replace the placeholders with the default values.
  355. for (idx = 0; idx < num; idx++)
  356. {
  357. if (&values.item(idx) == dft)
  358. values.replace(*defaultValue.getLink(),idx);
  359. }
  360. // use a var string type to get better C++ generated...
  361. ITypeInfo * storeType = getArrayElementType(resultType);
  362. ITypeInfo * listType = makeArrayType(storeType, values.ordinality());
  363. OwnedHqlExpr lvalues = createValue(no_list, listType, values);
  364. CHqlBoundExpr boundTable;
  365. translator.buildExpr(ctx, lvalues, boundTable);
  366. IHqlExpression * tableIndex;
  367. switch (compareTypeCode)
  368. {
  369. case type_int:
  370. tableIndex = LINK(test);
  371. break;
  372. case type_string:
  373. tableIndex = createValue(no_index, makeCharType(), LINK(test), getZero());
  374. break;
  375. default:
  376. throwUnexpectedType(compareType);
  377. }
  378. ITypeInfo * retType = resultType;
  379. IHqlExpression * ret = createValue(no_index, LINK(retType), LINK(boundTable.expr), tableIndex);
  380. return createTranslatedOwned(ret);
  381. }
  382. void HqlCppCaseInfo::buildLoopChopMap(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test)
  383. {
  384. //Declare a table that contains all the strings...
  385. ITypeInfo * compareType = queryCompareType();
  386. type_t ctc = compareType->getTypeCode();
  387. if ((ctc == type_data) && !hasLibraryChop())
  388. {
  389. buildGeneralAssign(ctx, target);
  390. return;
  391. }
  392. OwnedHqlExpr values = createCompareList();
  393. CHqlBoundExpr boundTable;
  394. translator.buildExpr(ctx, values, boundTable);
  395. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  396. if (hasLibraryChop())
  397. {
  398. ITypeInfo * tableEntryType = makeReferenceModifier(LINK(compareType));
  399. ITypeInfo * tableType = makePointerType(tableEntryType);
  400. HqlExprArray args;
  401. _ATOM func;
  402. switch (ctc)
  403. {
  404. case type_data:
  405. func = searchDataTableAtom;
  406. break;
  407. case type_varstring:
  408. func = searchVStringTableAtom;
  409. break;
  410. case type_qstring:
  411. func = searchQStringTableAtom;
  412. break;
  413. case type_string:
  414. if (compareType->queryCharset()->queryName() == asciiAtom)
  415. func = searchStringTableAtom;
  416. else if (compareType->queryCharset()->queryName() == ebcdicAtom)
  417. func = searchEStringTableAtom;
  418. else
  419. UNIMPLEMENTED;
  420. break;
  421. case type_unicode:
  422. func = searchUnicodeTableAtom;
  423. break;
  424. case type_utf8:
  425. func = searchUtf8TableAtom;
  426. break;
  427. case type_varunicode:
  428. func = searchVUnicodeTableAtom;
  429. break;
  430. default:
  431. throwUnexpectedType(compareType);
  432. }
  433. args.append(*getSizetConstant(values->numChildren()));
  434. if ((ctc != type_varstring) && (ctc != type_varunicode))
  435. args.append(*getSizetConstant(values->queryChild(0)->queryType()->getStringLen()));
  436. args.append(*createValue(no_address, tableType, createValue(no_index, LINK(tableEntryType), LINK(boundTable.expr), getZero())));
  437. if ((ctc != type_varstring) && (ctc != type_varunicode))
  438. args.append(*translator.getBoundLength(test));
  439. args.append(*ensureIndexable(test.expr));
  440. if ((ctc==type_unicode) || (ctc == type_varunicode) || (ctc == type_utf8))
  441. args.append(*createConstant(compareType->queryLocale()->str()));
  442. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(func, args);
  443. OwnedHqlExpr search = createTranslated(call);
  444. bool includeDefaultInResult = false;
  445. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  446. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  447. if (simpleResult)
  448. translator.buildExprAssign(ctx, target, simpleResult);
  449. else
  450. {
  451. ctx.addDeclare(midVar, NULL);
  452. translator.buildAssignToTemp(ctx, midVar, search);
  453. if (includeDefaultInResult)
  454. {
  455. translator.buildExprAssign(ctx, target, resultExpr);
  456. }
  457. else
  458. {
  459. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  460. BuildCtx subctx(ctx);
  461. IHqlStmt * stmt = subctx.addFilter(compare);
  462. translator.buildExprAssign(subctx, target, resultExpr);
  463. subctx.selectElse(stmt);
  464. translator.buildExprAssign(subctx, target, defaultValue);
  465. }
  466. }
  467. }
  468. else
  469. {
  470. #if 0
  471. //Keep this as a reminder of what was needed to fix qstrings.
  472. if (ctc == type_qstring)
  473. {
  474. Linked<ITypeInfo> compareType = queryCompareType();
  475. compareType.setown(makeArrayType(compareType.getLink()));
  476. table = createValue(no_typetransfer, compareType.getLink(), table);
  477. }
  478. #endif
  479. OwnedHqlExpr resultExpr = createResultsExpr(midVar, false);
  480. //Now generate the code that performs the binary chop..
  481. ctx.addDeclare(midVar, NULL);
  482. OwnedHqlExpr compareVar = ctx.getTempDeclare(indexType, NULL);
  483. OwnedHqlExpr leftVar = ctx.getTempDeclare(indexType, NULL);
  484. OwnedHqlExpr rightVar = ctx.getTempDeclare(indexType, NULL);
  485. OwnedHqlExpr numPairs = getSizetConstant(getNumPairs());
  486. ctx.addAssign(leftVar, queryZero());
  487. ctx.addAssign(rightVar, numPairs);
  488. translator.buildExprAssign(ctx, target, defaultValue);
  489. OwnedHqlExpr loopc = createBoolExpr(no_lt, LINK(leftVar), LINK(rightVar));
  490. OwnedHqlExpr mid = createValue(no_div, createValue(no_add, LINK(leftVar), LINK(rightVar)), createConstant(indexType->castFrom(false, 2)));
  491. OwnedHqlExpr mid_p1 = createValue(no_add, LINK(indexType), LINK(midVar), createConstant(indexType->castFrom(false, 1)));
  492. OwnedHqlExpr curelem = createValue(no_index, LINK(compareType), boundTable.getTranslatedExpr(), createTranslated(mid_p1));
  493. OwnedHqlExpr test1 = createBoolExpr(no_lt, LINK(compareVar), getZero());
  494. OwnedHqlExpr test2 = createBoolExpr(no_gt, LINK(compareVar), getZero());
  495. OwnedHqlExpr order = createValue(no_order, LINK(indexType), test.getTranslatedExpr(), LINK(curelem));
  496. BuildCtx loopctx(ctx);
  497. loopctx.addLoop(loopc, NULL, true);
  498. translator.buildAssignToTemp(loopctx, midVar, mid);
  499. translator.buildAssignToTemp(loopctx, compareVar, order);
  500. BuildCtx subctx(loopctx);
  501. IHqlStmt * if1 = subctx.addFilter(test1); // if (test < 0)
  502. translator.buildAssignToTemp(subctx, rightVar, midVar); // right = mid;
  503. subctx.selectElse(if1); // else
  504. IHqlStmt * if2 = subctx.addFilter(test2); // if (test > 0)
  505. translator.buildAssignToTemp(subctx, leftVar, mid_p1); // left = mid + 1;
  506. subctx.selectElse(if2); // else
  507. //generate the default assignment...
  508. translator.buildExprAssign(subctx, target, resultExpr);
  509. subctx.addBreak();
  510. }
  511. }
  512. void HqlCppCaseInfo::buildIntegerSearchMap(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * test)
  513. {
  514. ITypeInfo * compareType = queryCompareType();
  515. HqlExprArray args;
  516. args.append(*createCompareList());
  517. args.append(*LINK(test));
  518. _ATOM func;
  519. if (compareType->isSigned())
  520. {
  521. if (compareType->getSize() > 4)
  522. func = searchTableInteger8Atom;
  523. else
  524. func = searchTableInteger4Atom;
  525. }
  526. else
  527. {
  528. if (compareType->getSize() > 4)
  529. func = searchTableUInteger8Atom;
  530. else
  531. func = searchTableUInteger4Atom;
  532. }
  533. OwnedHqlExpr search = translator.bindFunctionCall(func, args);
  534. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  535. bool includeDefaultInResult = false;
  536. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  537. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  538. if (simpleResult)
  539. translator.buildExprAssign(ctx, target, simpleResult);
  540. else
  541. {
  542. ctx.addDeclare(midVar, NULL);
  543. translator.buildAssignToTemp(ctx, midVar, search);
  544. if (includeDefaultInResult)
  545. {
  546. translator.buildExprAssign(ctx, target, resultExpr);
  547. }
  548. else
  549. {
  550. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  551. BuildCtx subctx(ctx);
  552. IHqlStmt * stmt = subctx.addFilter(compare);
  553. translator.buildExprAssign(subctx, target, resultExpr);
  554. subctx.selectElse(stmt);
  555. translator.buildExprAssign(subctx, target, defaultValue);
  556. }
  557. }
  558. }
  559. void HqlCppCaseInfo::buildSwitchCondition(BuildCtx & ctx, CHqlBoundExpr & bound)
  560. {
  561. OwnedHqlExpr simpleCond = complexCompare ? getSimplifyCompareArg(cond) : LINK(cond);
  562. translator.buildCachedExpr(ctx, simpleCond, bound);
  563. }
  564. void HqlCppCaseInfo::buildSwitchMap(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * test)
  565. {
  566. bool isCharCompare = (test->queryType()->getTypeCode() == type_string);
  567. LinkedHqlExpr cond = test;
  568. if (isCharCompare)
  569. cond.setown(createValue(no_index, makeCharType(), LINK(test), getZero()));
  570. BuildCtx subctx(ctx);
  571. IHqlStmt * stmt = subctx.addSwitch(cond);
  572. // are all the comparisons against constant values? If so we optimize it...
  573. unsigned sameCount = 0;
  574. ForEachItemIn(idx, pairs)
  575. {
  576. IHqlExpression & cur = pairs.item(idx);
  577. LinkedHqlExpr compare = cur.queryChild(0);
  578. IHqlExpression * branchValue = cur.queryChild(1);
  579. if (isCharCompare)
  580. {
  581. OwnedITypeInfo charType = makeCharType();
  582. IValue * cur = compare->queryValue();
  583. IValue * next = cur->castTo(charType);
  584. compare.setown(createConstant(next));
  585. }
  586. bool same = false;
  587. bool skip = false;
  588. if (idx != pairs.ordinality()-1)
  589. {
  590. IHqlExpression & next = pairs.item(idx+1);
  591. if (next.queryChild(1) == branchValue)
  592. same = true;
  593. //if save item is included twice, remove one so no error
  594. //from the case statement
  595. if (next.queryChild(0) == cur.queryChild(0))
  596. {
  597. skip = true;
  598. #ifdef _DEBUG
  599. throwUnexpected(); // should have been removed as a duplicate
  600. #endif
  601. }
  602. }
  603. if (sameCount >= MAX_NUM_NOBREAK_CASE)
  604. same = false;
  605. if (!skip)
  606. {
  607. subctx.addCase(stmt, compare);
  608. // common up case labels that produce the same result
  609. if (!same)
  610. {
  611. sameCount = 1;
  612. if (target)
  613. translator.buildExprAssign(subctx, *target, branchValue);
  614. else
  615. translator.buildReturn(subctx, branchValue);
  616. }
  617. else
  618. sameCount++;
  619. }
  620. }
  621. if (target)
  622. {
  623. subctx.addDefault(stmt);
  624. translator.buildExprAssign(subctx, *target, defaultValue);
  625. }
  626. else
  627. translator.buildReturn(ctx, defaultValue);
  628. }
  629. void HqlCppCaseInfo::buildGeneralAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  630. {
  631. unsigned max = pairs.ordinality();
  632. Owned<BuildCtx> subctx = new BuildCtx(ctx);
  633. CHqlBoundExpr pureCond;
  634. if (cond.get())
  635. translator.buildCachedExpr(*subctx, cond, pureCond);
  636. OwnedHqlExpr testMore;
  637. if (max > MAX_NESTED_CASES)
  638. {
  639. //Too many nested blocks cause the compiler indigestion...
  640. Owned<ITypeInfo> t = makeBoolType();
  641. testMore.setown(ctx.getTempDeclare(t, queryBoolExpr(false)));
  642. }
  643. for (unsigned idx = 0; idx < max; idx++)
  644. {
  645. IHqlExpression & cur = pairs.item(idx);
  646. IHqlExpression * curtest = cur.queryChild(0);
  647. IHqlExpression * curvalue = cur.queryChild(1);
  648. OwnedHqlExpr compare;
  649. if (!pureCond.expr)
  650. compare.setown(ensureExprType(curtest, queryBoolType()));
  651. else
  652. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  653. if (idx && ((idx % MAX_NESTED_CASES) == 0))
  654. {
  655. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(true));
  656. subctx.setown(new BuildCtx(ctx));
  657. subctx->addFilter(testMore);
  658. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(false));
  659. }
  660. IHqlStmt * test = translator.buildFilterViaExpr(*subctx, compare);
  661. translator.buildExprAssign(*subctx, target, curvalue);
  662. subctx->selectElse(test);
  663. }
  664. translator.buildExprAssign(*subctx, target, defaultValue);
  665. }
  666. void HqlCppCaseInfo::buildGeneralReturn(BuildCtx & ctx)
  667. {
  668. unsigned max = pairs.ordinality();
  669. CHqlBoundExpr pureCond;
  670. if (cond.get())
  671. translator.buildCachedExpr(ctx, cond, pureCond);
  672. for (unsigned idx = 0; idx < max; idx++)
  673. {
  674. IHqlExpression & cur = pairs.item(idx);
  675. IHqlExpression * curtest = cur.queryChild(0);
  676. IHqlExpression * curvalue = cur.queryChild(1);
  677. OwnedHqlExpr compare;
  678. if (!pureCond.expr)
  679. compare.setown(ensureExprType(curtest, queryBoolType()));
  680. else
  681. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  682. BuildCtx subctx(ctx);
  683. translator.buildFilter(subctx, compare);
  684. translator.buildReturn(subctx, curvalue);
  685. }
  686. translator.buildReturn(ctx, defaultValue);
  687. }
  688. bool HqlCppCaseInfo::okToAlwaysEvaluateDefault()
  689. {
  690. return defaultValue->isPure();
  691. }
  692. ITypeInfo * HqlCppCaseInfo::queryCompareType()
  693. {
  694. return cond->queryType()->queryPromotedType();
  695. }
  696. IHqlExpression * HqlCppCaseInfo::createCompareList()
  697. {
  698. //NB: All cases need to have the same type because they are stored in a table
  699. Linked<ITypeInfo> promoted = pairs.item(0).queryChild(0)->queryType();
  700. unsigned max = pairs.ordinality();
  701. for (unsigned idx1 = 1; idx1 < max; idx1++)
  702. {
  703. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  704. promoted.setown(getPromotedECLType(promoted, type));
  705. }
  706. HqlExprArray values;
  707. values.ensure(pairs.ordinality());
  708. ForEachItemIn(idx, pairs)
  709. {
  710. IHqlExpression & pair = pairs.item(idx);
  711. IHqlExpression * compare = pair.queryChild(0);
  712. values.append(*ensureExprType(compare, promoted));
  713. }
  714. Linked<ITypeInfo> compareType = queryCompareType();
  715. switch (compareType->getTypeCode())
  716. {
  717. case type_string:
  718. case type_data:
  719. case type_varstring:
  720. case type_qstring:
  721. case type_utf8:
  722. compareType.setown(makePointerType(makeCharType(false)));
  723. break;
  724. case type_unicode:
  725. case type_varunicode:
  726. compareType.setown(makePointerType(makeClassType("UChar")));
  727. break;
  728. }
  729. return createValue(no_list, makeArrayType(compareType.getLink()), values);
  730. }
  731. IHqlExpression * HqlCppCaseInfo::createResultsExpr(IHqlExpression * matchVar, bool canIncludeDefault, bool * includedDefault)
  732. {
  733. if (includedDefault)
  734. *includedDefault = false;
  735. //Look at all the return results and see what relation we can create
  736. //This can generate one of the following:
  737. //1. A single value.
  738. //2. A function of the result. e.g., IN...
  739. //3. A lookup in another table. [ all values are constant ]
  740. //4. A nested map statement
  741. bool areSame = true;
  742. bool areLinear = true;
  743. bool areConstant = true;
  744. __int64 linearStart = 0;
  745. __int64 linearMultiple = 1;
  746. ITypeInfo * retType = resultType;
  747. switch (retType->getTypeCode())
  748. {
  749. case type_int:
  750. case type_boolean:
  751. break;
  752. case type_string:
  753. case type_data:
  754. // areConstant = false; // a temporary hack to stop incorrect table being generated.
  755. areLinear = false;
  756. break;
  757. default:
  758. areLinear = false;
  759. break;
  760. }
  761. IHqlExpression * prevValue = NULL;
  762. HqlExprArray values;
  763. values.ensure(pairs.ordinality());
  764. ForEachItemIn(idx, pairs)
  765. {
  766. IHqlExpression & pair = pairs.item(idx);
  767. IHqlExpression * value = pair.queryChild(1);
  768. IValue * cvalue = value->queryValue();
  769. if (cvalue)
  770. {
  771. if (areLinear)
  772. {
  773. __int64 val = cvalue->getIntValue();
  774. if (idx == 0)
  775. linearStart = val;
  776. else if (idx == 1)
  777. linearMultiple = (val - linearStart);
  778. else if (val != linearStart + idx * linearMultiple)
  779. areLinear = false;
  780. }
  781. }
  782. else
  783. {
  784. areConstant = false;
  785. areLinear = false;
  786. }
  787. if (idx > 0)
  788. {
  789. if (areSame && (prevValue != value))
  790. areSame = false;
  791. }
  792. values.append(*ensureExprType(value, resultType));
  793. prevValue = value;
  794. }
  795. if (areSame)
  796. return LINK(prevValue);
  797. if (areLinear)
  798. {
  799. IHqlExpression * ret = ensureExprType(matchVar, resultType);
  800. if (linearMultiple != 1)
  801. ret = createValue(no_mul, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearMultiple)));
  802. if (linearStart != 0)
  803. ret = createValue(no_add, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearStart)));
  804. return ret;
  805. }
  806. unsigned firstMatchEntry = 0;
  807. if (canIncludeDefault)
  808. {
  809. //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
  810. if (areConstant && defaultValue->isConstant() && defaultValue->queryType() == values.item(0).queryType())
  811. {
  812. firstMatchEntry = 1;
  813. values.add(*LINK(defaultValue), 0);
  814. *includedDefault = true;
  815. }
  816. }
  817. // easy way to create a value list...
  818. ITypeInfo * storeType = getArrayElementType(retType);
  819. OwnedHqlExpr newlist = createValue(no_list, makeSetType(storeType), values);
  820. if (areConstant && canBuildStaticList(resultType))
  821. {
  822. IHqlExpression * index = adjustValue(matchVar, 1+firstMatchEntry);
  823. return createValue(no_index, LINK(retType), LINK(newlist), index, createAttribute(noBoundCheckAtom));
  824. }
  825. //Need to generate a case (switch integer case 1: ..... )
  826. HqlExprArray choosePairs;
  827. cvtChooseListToPairs(choosePairs, newlist, 0);
  828. IHqlExpression * caseExpr = createOpenValue(no_case, LINK(retType));
  829. caseExpr->addOperand(LINK(matchVar));
  830. ForEachItemIn(idx2, choosePairs)
  831. caseExpr->addOperand(&choosePairs.item(idx2));
  832. choosePairs.kill(true);
  833. caseExpr->addOperand(LINK(defaultValue));
  834. return caseExpr->closeExpr();
  835. }
  836. void HqlCppCaseInfo::generateCompareVar(BuildCtx & ctx, IHqlExpression * target, CHqlBoundExpr & test, IHqlExpression * other)
  837. {
  838. OwnedHqlExpr compare = createValue(no_order, test.getTranslatedExpr(), LINK(other));
  839. translator.buildAssignToTemp(ctx, target, compare);
  840. }
  841. unsigned HqlCppCaseInfo::getNumPairs()
  842. {
  843. return pairs.ordinality();
  844. }
  845. bool HqlCppCaseInfo::hasLibraryChop()
  846. {
  847. ITypeInfo * compareType = queryCompareType();
  848. type_t ctc = compareType->getTypeCode();
  849. switch (ctc)
  850. {
  851. case type_data:
  852. return canBuildStaticList(promotedElementType);
  853. case type_string:
  854. case type_varstring:
  855. case type_qstring:
  856. case type_unicode:
  857. case type_varunicode:
  858. case type_utf8:
  859. return true;
  860. }
  861. return false;
  862. }
  863. void HqlCppCaseInfo::processBranches()
  864. {
  865. sortPairs();
  866. removeDuplicates();
  867. promoteTypes();
  868. }
  869. void HqlCppCaseInfo::promoteTypes()
  870. {
  871. Owned<ITypeInfo> promoted = pairs.item(0).queryChild(0)->getType();
  872. unsigned max = pairs.ordinality();
  873. for (unsigned idx1 = 1; idx1 < max; idx1++)
  874. {
  875. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  876. if (isStringType(promoted) && isStringType(type))
  877. {
  878. if (promoted->getStringLen() != type->getStringLen())
  879. {
  880. promoted.setown(::getPromotedECLType(promoted, type));
  881. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  882. }
  883. }
  884. promoted.setown(::getPromotedECLType(promoted, type));
  885. }
  886. promotedElementType.set(promoted);
  887. if (isStringType(promoted))
  888. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  889. ITypeInfo * testType = queryCompareType();
  890. if ((testType->queryCharset() != promoted->queryCharset()) || (testType->queryLocale() != promoted->queryLocale()))
  891. cond.setown(ensureExprType(cond, promoted));
  892. }
  893. bool HqlCppCaseInfo::canBuildArrayLookup(const CHqlBoundExpr & test)
  894. {
  895. ITypeInfo * condType = test.queryType()->queryPromotedType();
  896. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  897. unsigned bitSize = condType->getBitSize();
  898. if (constantValues && (bitSize && (bitSize <= 8) && !condType->isSigned()))
  899. {
  900. unsigned limit = (1 << bitSize);
  901. //use case if enough items, or above a certain density...
  902. if (pairs.ordinality() * 100 >= limit * SWITCH_TABLE_DENSITY_THRESHOLD)
  903. {
  904. if ((condType->getTypeCode() == type_int) || (condType->getTypeCode() == type_string))
  905. return true;
  906. }
  907. }
  908. return false;
  909. }
  910. bool HqlCppCaseInfo::queryBuildArrayLookup(BuildCtx & ctx, const CHqlBoundTarget & target, const CHqlBoundExpr & test)
  911. {
  912. if (canBuildArrayLookup(test) && canBuildStaticList(resultType))
  913. {
  914. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  915. ITypeInfo * condType = test.queryType()->queryPromotedType();
  916. unsigned bitSize = condType->getBitSize();
  917. unsigned limit = (1 << bitSize);
  918. BuildCtx subctx(ctx);
  919. OwnedHqlExpr ret = buildIndexedMap(subctx, test.expr, 0, limit-1);
  920. translator.buildExprAssign(ctx, target, ret);
  921. return true;
  922. }
  923. return false;
  924. }
  925. void HqlCppCaseInfo::removeDuplicates()
  926. {
  927. unsigned num = pairs.ordinality();
  928. if (num > 1)
  929. {
  930. num--;
  931. while (num--)
  932. {
  933. IHqlExpression & cur = pairs.item(num);
  934. IHqlExpression & next = pairs.item(num+1);
  935. if (cur.queryChild(0) == next.queryChild(0))
  936. {
  937. if (cur.queryChild(1) == next.queryChild(1))
  938. pairs.remove(num+1);
  939. else
  940. {
  941. // we need to keep the first in the original list.... Horrid, but it works...
  942. unsigned off1 = originalPairs.find(cur);
  943. unsigned off2 = originalPairs.find(next);
  944. assertex(off1 != NotFound && off2 != NotFound);
  945. if (off1 < off2)
  946. pairs.remove(num+1);
  947. else
  948. pairs.remove(num);
  949. }
  950. }
  951. }
  952. }
  953. }
  954. IHqlExpression * HqlCppCaseInfo::queryCreateSimpleResultAssign(IHqlExpression * search, IHqlExpression * resultExpr)
  955. {
  956. IHqlExpression * trueExpr = queryBoolExpr(true);
  957. IHqlExpression * falseExpr = queryBoolExpr(false);
  958. if (resultExpr == trueExpr && defaultValue == falseExpr)
  959. return createBoolExpr(no_ne, LINK(search), createNotFoundValue());
  960. if (resultExpr == falseExpr && defaultValue == trueExpr)
  961. return createBoolExpr(no_eq, LINK(search), createNotFoundValue());
  962. return NULL;
  963. }
  964. IHqlExpression * HqlCppCaseInfo::queryCompare(unsigned index)
  965. {
  966. return pairs.item(index).queryChild(0);
  967. }
  968. IHqlExpression * HqlCppCaseInfo::queryReturn(unsigned index)
  969. {
  970. return pairs.item(index).queryChild(1);
  971. }
  972. void HqlCppCaseInfo::setCond(IHqlExpression * expr)
  973. {
  974. cond.set(expr);
  975. if (isCompare3Valued(expr->queryType()))
  976. complexCompare = true;
  977. }
  978. void HqlCppCaseInfo::setDefault(IHqlExpression * expr)
  979. {
  980. defaultValue.set(expr);
  981. }
  982. void HqlCppCaseInfo::sortPairs()
  983. {
  984. appendArray(originalPairs, pairs);
  985. pairs.sort(comparePair);
  986. }
  987. void HqlCppCaseInfo::updateResultType(IHqlExpression * expr)
  988. {
  989. ITypeInfo * curResultType = expr->queryType();
  990. if (resultType)
  991. resultType.setown(::getPromotedECLType(resultType, curResultType));
  992. else
  993. resultType.set(curResultType);
  994. }