hqlcppcase.cpp 39 KB

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