Changeset 127:facc562f5674
- Timestamp:
- 11/30/07 06:56:52
(1 year ago)
- Author:
- lindquist
- branch:
- trunk
- Message:
[svn r131] Fixed #11
All associative array properties now work as they should.
Fixed problems with some cases of array.length and array.ptr.
Fixed some problems with array properties.
Fixed 'in' contracts.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r101 |
r127 |
|
| 260 | 260 | global.params.useAssert = 0; |
|---|
| 261 | 261 | global.params.useInvariants = 0; |
|---|
| 262 | | global.params.useIn = 0; |
|---|
| | 262 | global.params.useIn = 1; |
|---|
| 263 | 263 | global.params.useOut = 0; |
|---|
| 264 | 264 | global.params.useArrayBounds = 0; |
|---|
| 265 | 265 | global.params.useSwitchError = 0; |
|---|
| 266 | | global.params.useInline = 0; |
|---|
| | 266 | global.params.useInline = 0; // this one messes things up to a point where codegen breaks |
|---|
| 267 | 267 | global.params.obj = 1; |
|---|
| 268 | 268 | global.params.Dversion = 2; |
|---|
| r121 |
r127 |
|
| 1514 | 1514 | |
|---|
| 1515 | 1515 | nm = name[n->ty == Twchar]; |
|---|
| 1516 | | fd = FuncDeclaration::genCfunc(Type::tindex, nm); |
|---|
| | 1516 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); |
|---|
| 1517 | 1517 | fd->llvmRunTimeHack = true; |
|---|
| 1518 | | ((TypeFunction*)fd->type)->llvmRetInPtr = true; |
|---|
| 1519 | 1518 | ec = new VarExp(0, fd); |
|---|
| 1520 | 1519 | e = e->castTo(sc, n->arrayOf()); // convert to dynamic array |
|---|
| … | … | |
| 1533 | 1532 | |
|---|
| 1534 | 1533 | nm = name[n->ty == Twchar]; |
|---|
| 1535 | | fd = FuncDeclaration::genCfunc(Type::tindex, nm); |
|---|
| | 1534 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); |
|---|
| 1536 | 1535 | fd->llvmRunTimeHack = true; |
|---|
| 1537 | | ((TypeFunction*)fd->type)->llvmRetInPtr = true; |
|---|
| 1538 | 1536 | ec = new VarExp(0, fd); |
|---|
| 1539 | 1537 | e = e->castTo(sc, n->arrayOf()); // convert to dynamic array |
|---|
| … | … | |
| 1553 | 1551 | assert(size); |
|---|
| 1554 | 1552 | dup = (ident == Id::dup); |
|---|
| 1555 | | fd = FuncDeclaration::genCfunc(Type::tindex, dup ? Id::adDup : Id::adReverse); |
|---|
| | 1553 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse); |
|---|
| 1556 | 1554 | fd->llvmRunTimeHack = true; |
|---|
| 1557 | | ((TypeFunction*)fd->type)->llvmRetInPtr = true; |
|---|
| 1558 | 1555 | ec = new VarExp(0, fd); |
|---|
| 1559 | 1556 | e = e->castTo(sc, n->arrayOf()); // convert to dynamic array |
|---|
| … | … | |
| 1573 | 1570 | Expressions *arguments; |
|---|
| 1574 | 1571 | |
|---|
| 1575 | | fd = FuncDeclaration::genCfunc(tint32->arrayOf(), |
|---|
| | 1572 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), |
|---|
| 1576 | 1573 | (char*)(n->ty == Tbit ? "_adSortBit" : "_adSort")); |
|---|
| 1577 | 1574 | fd->llvmRunTimeHack = true; |
|---|
| 1578 | | ((TypeFunction*)fd->type)->llvmRetInPtr = true; |
|---|
| 1579 | 1575 | ec = new VarExp(0, fd); |
|---|
| 1580 | 1576 | e = e->castTo(sc, n->arrayOf()); // convert to dynamic array |
|---|
| … | … | |
| 2278 | 2274 | |
|---|
| 2279 | 2275 | fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen); |
|---|
| | 2276 | fd->llvmRunTimeHack = true; |
|---|
| 2280 | 2277 | ec = new VarExp(0, fd); |
|---|
| 2281 | 2278 | arguments = new Expressions(); |
|---|
| … | … | |
| 2292 | 2289 | |
|---|
| 2293 | 2290 | assert(size); |
|---|
| 2294 | | fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaKeys); |
|---|
| | 2291 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys); |
|---|
| | 2292 | fd->llvmRunTimeHack = true; |
|---|
| 2295 | 2293 | ec = new VarExp(0, fd); |
|---|
| 2296 | 2294 | arguments = new Expressions(); |
|---|
| … | … | |
| 2306 | 2304 | Expressions *arguments; |
|---|
| 2307 | 2305 | |
|---|
| 2308 | | fd = FuncDeclaration::genCfunc(Type::tindex, Id::aaValues); |
|---|
| | 2306 | fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues); |
|---|
| | 2307 | fd->llvmRunTimeHack = true; |
|---|
| 2309 | 2308 | ec = new VarExp(0, fd); |
|---|
| 2310 | 2309 | arguments = new Expressions(); |
|---|
| 2311 | 2310 | arguments->push(e); |
|---|
| 2312 | 2311 | size_t keysize = key->size(e->loc); |
|---|
| 2313 | | keysize = (keysize + 3) & ~3; // BUG: 64 bit pointers? |
|---|
| | 2312 | keysize = (keysize + 4 - 1) & ~(4 - 1); |
|---|
| 2314 | 2313 | arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); |
|---|
| 2315 | 2314 | arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); |
|---|
| … | … | |
| 2323 | 2322 | Expressions *arguments; |
|---|
| 2324 | 2323 | |
|---|
| 2325 | | fd = FuncDeclaration::genCfunc(Type::tint64, Id::aaRehash); |
|---|
| | 2324 | fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash); |
|---|
| | 2325 | fd->llvmRunTimeHack = true; |
|---|
| 2326 | 2326 | ec = new VarExp(0, fd); |
|---|
| 2327 | 2327 | arguments = new Expressions(); |
|---|
| r109 |
r127 |
|
| 49 | 49 | } |
|---|
| 50 | 50 | |
|---|
| | 51 | // returns the keytype typeinfo |
|---|
| | 52 | static llvm::Value* to_keyti(DValue* key) |
|---|
| | 53 | { |
|---|
| | 54 | // keyti param |
|---|
| | 55 | Type* keytype = key->getType(); |
|---|
| | 56 | keytype->getTypeInfo(NULL); |
|---|
| | 57 | TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration(); |
|---|
| | 58 | assert(tid); |
|---|
| | 59 | DtoResolveDsymbol(Type::typeinfo); |
|---|
| | 60 | DtoForceDeclareDsymbol(tid); |
|---|
| | 61 | assert(tid->llvmValue); |
|---|
| | 62 | return tid->llvmValue; |
|---|
| | 63 | } |
|---|
| | 64 | |
|---|
| 51 | 65 | ///////////////////////////////////////////////////////////////////////////////////// |
|---|
| 52 | 66 | |
|---|
| … | … | |
| 65 | 79 | |
|---|
| 66 | 80 | // keyti param |
|---|
| 67 | | Type* keytype = key->getType(); |
|---|
| 68 | | keytype->getTypeInfo(NULL); |
|---|
| 69 | | TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration(); |
|---|
| 70 | | assert(tid); |
|---|
| 71 | | DtoResolveDsymbol(Type::typeinfo); |
|---|
| 72 | | DtoForceDeclareDsymbol(tid); |
|---|
| 73 | | assert(tid->llvmValue); |
|---|
| 74 | | llvm::Value* keyti = tid->llvmValue; |
|---|
| | 81 | llvm::Value* keyti = to_keyti(key); |
|---|
| 75 | 82 | keyti = DtoBitCast(keyti, funcTy->getParamType(1)); |
|---|
| 76 | 83 | |
|---|
| … | … | |
| 90 | 97 | |
|---|
| 91 | 98 | // call runtime |
|---|
| 92 | | llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaGet"); |
|---|
| | 99 | llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.index"); |
|---|
| 93 | 100 | |
|---|
| 94 | 101 | // cast return value |
|---|
| … | … | |
| 120 | 127 | |
|---|
| 121 | 128 | // keyti param |
|---|
| 122 | | Type* keytype = key->getType(); |
|---|
| 123 | | keytype->getTypeInfo(NULL); |
|---|
| 124 | | TypeInfoDeclaration* tid = keytype->getTypeInfoDeclaration(); |
|---|
| 125 | | assert(tid); |
|---|
| 126 | | DtoResolveDsymbol(Type::typeinfo); |
|---|
| 127 | | DtoForceDeclareDsymbol(tid); |
|---|
| 128 | | assert(tid->llvmValue); |
|---|
| 129 | | llvm::Value* keyti = tid->llvmValue; |
|---|
| | 129 | llvm::Value* keyti = to_keyti(key); |
|---|
| 130 | 130 | keyti = DtoBitCast(keyti, funcTy->getParamType(1)); |
|---|
| 131 | 131 | |
|---|
| … | … | |
| 141 | 141 | |
|---|
| 142 | 142 | // call runtime |
|---|
| 143 | | llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aaIn"); |
|---|
| | 143 | llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "aa.in"); |
|---|
| 144 | 144 | |
|---|
| 145 | 145 | // cast return value |
|---|
| … | … | |
| 152 | 152 | |
|---|
| 153 | 153 | ///////////////////////////////////////////////////////////////////////////////////// |
|---|
| | 154 | |
|---|
| | 155 | void DtoAARemove(DValue* aa, DValue* key) |
|---|
| | 156 | { |
|---|
| | 157 | // call: |
|---|
| | 158 | // extern(C) void _aaDel(AA aa, TypeInfo keyti, void* pkey) |
|---|
| | 159 | |
|---|
| | 160 | // first get the runtime function |
|---|
| | 161 | llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_aaDel"); |
|---|
| | 162 | const llvm::FunctionType* funcTy = func->getFunctionType(); |
|---|
| | 163 | |
|---|
| | 164 | Logger::cout() << "_aaDel = " << *func << '\n'; |
|---|
| | 165 | |
|---|
| | 166 | // aa param |
|---|
| | 167 | llvm::Value* aaval = aa->getRVal(); |
|---|
| | 168 | Logger::cout() << "aaval: " << *aaval << '\n'; |
|---|
| | 169 | Logger::cout() << "totype: " << *funcTy->getParamType(0) << '\n'; |
|---|
| | 170 | aaval = DtoBitCast(aaval, funcTy->getParamType(0)); |
|---|
| | 171 | |
|---|
| | 172 | // keyti param |
|---|
| | 173 | llvm::Value* keyti = to_keyti(key); |
|---|
| | 174 | keyti = DtoBitCast(keyti, funcTy->getParamType(1)); |
|---|
| | 175 | |
|---|
| | 176 | // pkey param |
|---|
| | 177 | llvm::Value* pkey = to_pkey(key); |
|---|
| | 178 | pkey = DtoBitCast(pkey, funcTy->getParamType(2)); |
|---|
| | 179 | |
|---|
| | 180 | // build arg vector |
|---|
| | 181 | std::vector<llvm::Value*> args; |
|---|
| | 182 | args.push_back(aaval); |
|---|
| | 183 | args.push_back(keyti); |
|---|
| | 184 | args.push_back(pkey); |
|---|
| | 185 | |
|---|
| | 186 | // call runtime |
|---|
| | 187 | gIR->ir->CreateCall(func, args.begin(), args.end(),""); |
|---|
| | 188 | } |
|---|
| r109 |
r127 |
|
| 4 | 4 | DValue* DtoAAIndex(Type* type, DValue* aa, DValue* key); |
|---|
| 5 | 5 | DValue* DtoAAIn(Type* type, DValue* aa, DValue* key); |
|---|
| | 6 | void DtoAARemove(DValue* aa, DValue* key); |
|---|
| 6 | 7 | |
|---|
| 7 | 8 | #endif // LLVMDC_GEN_AA_H |
|---|
| r118 |
r127 |
|
| 809 | 809 | } |
|---|
| 810 | 810 | const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0)); |
|---|
| 811 | | assert(arrTy); |
|---|
| 812 | | return DtoConstSize_t(arrTy->getNumElements()); |
|---|
| | 811 | if (arrTy) |
|---|
| | 812 | return DtoConstSize_t(arrTy->getNumElements()); |
|---|
| | 813 | else |
|---|
| | 814 | return DtoLoad(DtoGEPi(s->ptr, 0,0, "tmp")); |
|---|
| 813 | 815 | } |
|---|
| 814 | 816 | return DtoLoad(DtoGEPi(v->getRVal(), 0,0, "tmp")); |
|---|
| … | … | |
| 832 | 834 | if (DSliceValue* s = v->isSlice()) { |
|---|
| 833 | 835 | if (s->len) return s->ptr; |
|---|
| | 836 | const llvm::Type* t = s->ptr->getType()->getContainedType(0); |
|---|
| | 837 | Logger::cout() << "ptr of full slice: " << *s->ptr << '\n'; |
|---|
| 834 | 838 | const llvm::ArrayType* arrTy = isaArray(s->ptr->getType()->getContainedType(0)); |
|---|
| 835 | | assert(arrTy); |
|---|
| 836 | | return DtoGEPi(s->ptr, 0,0, "tmp"); |
|---|
| | 839 | if (arrTy) |
|---|
| | 840 | return DtoGEPi(s->ptr, 0,0, "tmp"); |
|---|
| | 841 | else |
|---|
| | 842 | return DtoLoad(DtoGEPi(s->ptr, 0,1, "tmp")); |
|---|
| 837 | 843 | } |
|---|
| 838 | 844 | return DtoLoad(DtoGEPi(v->getRVal(), 0,1, "tmp")); |
|---|
| r123 |
r127 |
|
| 257 | 257 | if (fdecl->llvmRunTimeHack) { |
|---|
| 258 | 258 | gIR->declareList.push_back(fdecl); |
|---|
| | 259 | TypeFunction* tf = (TypeFunction*)fdecl->type; |
|---|
| | 260 | tf->llvmRetInPtr = DtoIsPassedByRef(tf->next); |
|---|
| 259 | 261 | return; |
|---|
| 260 | 262 | } |
|---|
| r125 |
r127 |
|
| 905 | 905 | } |
|---|
| 906 | 906 | assert(llfnty); |
|---|
| 907 | | //Logger::cout() << "Function LLVM type: " << *llfnty << '\n'; |
|---|
| | 907 | Logger::cout() << "Function LLVM type: " << *llfnty << '\n'; |
|---|
| 908 | 908 | |
|---|
| 909 | 909 | // argument handling |
|---|
| … | … | |
| 2573 | 2573 | } |
|---|
| 2574 | 2574 | |
|---|
| | 2575 | DValue* RemoveExp::toElem(IRState* p) |
|---|
| | 2576 | { |
|---|
| | 2577 | Logger::print("RemoveExp::toElem: %s\n", toChars()); |
|---|
| | 2578 | LOG_SCOPE; |
|---|
| | 2579 | |
|---|
| | 2580 | DValue* aa = e1->toElem(p); |
|---|
| | 2581 | DValue* key = e2->toElem(p); |
|---|
| | 2582 | |
|---|
| | 2583 | DtoAARemove(aa, key); |
|---|
| | 2584 | |
|---|
| | 2585 | return NULL; // does not produce anything useful |
|---|
| | 2586 | } |
|---|
| | 2587 | |
|---|
| 2575 | 2588 | ////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 2576 | 2589 | |
|---|
| … | … | |
| 2584 | 2597 | assert(keys->dim == values->dim); |
|---|
| 2585 | 2598 | |
|---|
| | 2599 | Type* aatype = DtoDType(type); |
|---|
| | 2600 | Type* vtype = aatype->next; |
|---|
| | 2601 | |
|---|
| | 2602 | DValue* aa; |
|---|
| | 2603 | if (p->topexp() && p->topexp()->e2 == this) |
|---|
| | 2604 | { |
|---|
| | 2605 | aa = p->topexp()->v; |
|---|
| | 2606 | } |
|---|
| | 2607 | else |
|---|
| | 2608 | { |
|---|
| | 2609 | llvm::Value* tmp = new llvm::AllocaInst(DtoType(type),"aaliteral",p->topallocapoint()); |
|---|
| | 2610 | aa = new DVarValue(type, tmp, true); |
|---|
| | 2611 | } |
|---|
| | 2612 | |
|---|
| 2586 | 2613 | const size_t n = keys->dim; |
|---|
| 2587 | 2614 | for (size_t i=0; i<n; ++i) |
|---|
| … | … | |
| 2591 | 2618 | |
|---|
| 2592 | 2619 | Logger::println("(%u) aa[%s] = %s", i, ekey->toChars(), eval->toChars()); |
|---|
| 2593 | | } |
|---|
| 2594 | | |
|---|
| 2595 | | assert(0); |
|---|
| | 2620 | |
|---|
| | 2621 | // index |
|---|
| | 2622 | DValue* key = ekey->toElem(p); |
|---|
| | 2623 | DValue* mem = DtoAAIndex(vtype, aa, key); |
|---|
| | 2624 | |
|---|
| | 2625 | // store |
|---|
| | 2626 | DValue* val = eval->toElem(p); |
|---|
| | 2627 | DtoAssign(mem, val); |
|---|
| | 2628 | } |
|---|
| | 2629 | |
|---|
| | 2630 | return aa; |
|---|
| 2596 | 2631 | } |
|---|
| 2597 | 2632 | |
|---|
| … | … | |
| 2667 | 2702 | //STUB(ArrayLengthExp); |
|---|
| 2668 | 2703 | //STUB(HaltExp); |
|---|
| 2669 | | STUB(RemoveExp); |
|---|
| | 2704 | //STUB(RemoveExp); |
|---|
| 2670 | 2705 | //STUB(ArrayLiteralExp); |
|---|
| 2671 | 2706 | //STUB(AssocArrayLiteralExp); |
|---|
| r125 |
r127 |
|
| 15 | 15 | <projectdirectory>.</projectdirectory> |
|---|
| 16 | 16 | <absoluteprojectpath>false</absoluteprojectpath> |
|---|
| 17 | | <description></description> |
|---|
| 18 | | <defaultencoding></defaultencoding> |
|---|
| | 17 | <description/> |
|---|
| | 18 | <defaultencoding/> |
|---|
| 19 | 19 | </general> |
|---|
| 20 | 20 | <kdevautoproject> |
|---|
| … | … | |
| 157 | 157 | </codecompletion> |
|---|
| 158 | 158 | <creategettersetter> |
|---|
| 159 | | <prefixGet></prefixGet> |
|---|
| | 159 | <prefixGet/> |
|---|
| 160 | 160 | <prefixSet>set</prefixSet> |
|---|
| 161 | 161 | <prefixVariable>m_,_</prefixVariable> |
|---|
| … | … | |
| 169 | 169 | <orientation>Vertical</orientation> |
|---|
| 170 | 170 | </splitheadersource> |
|---|
| 171 | | <references/> |
|---|
| | 171 | <references> |
|---|
| | 172 | <pcs>LLVM</pcs> |
|---|
| | 173 | </references> |
|---|
| 172 | 174 | </kdevcppsupport> |
|---|
| 173 | 175 | <kdevcustomproject> |
|---|
| … | … | |
| 175 | 177 | <directoryradio>executable</directoryradio> |
|---|
| 176 | 178 | <mainprogram>/home/tomas/kdevprojects/llvmdc</mainprogram> |
|---|
| 177 | | <programargs></programargs> |
|---|
| 178 | | <globaldebugarguments></globaldebugarguments> |
|---|
| | 179 | <programargs/> |
|---|
| | 180 | <globaldebugarguments/> |
|---|
| 179 | 181 | <globalcwd>/home/tomas/kdevprojects/llvmdc</globalcwd> |
|---|
| 180 | 182 | <useglobalprogram>false</useglobalprogram> |
|---|
| … | … | |
| 399 | 401 | <build> |
|---|
| 400 | 402 | <buildtool>make</buildtool> |
|---|
| 401 | | <builddir></builddir> |
|---|
| | 403 | <builddir/> |
|---|
| 402 | 404 | </build> |
|---|
| 403 | 405 | <other> |
|---|
| 404 | 406 | <prio>0</prio> |
|---|
| 405 | | <otherbin></otherbin> |
|---|
| 406 | | <defaulttarget></defaulttarget> |
|---|
| 407 | | <otheroptions></otheroptions> |
|---|
| | 407 | <otherbin/> |
|---|
| | 408 | <defaulttarget/> |
|---|
| | 409 | <otheroptions/> |
|---|
| 408 | 410 | <selectedenvironment>default</selectedenvironment> |
|---|
| 409 | 411 | <environments> |
|---|
| … | … | |
| 416 | 418 | <prio>0</prio> |
|---|
| 417 | 419 | <dontact>false</dontact> |
|---|
| 418 | | <makebin></makebin> |
|---|
| 419 | | <defaulttarget></defaulttarget> |
|---|
| 420 | | <makeoptions></makeoptions> |
|---|
| | 420 | <makebin/> |
|---|
| | 421 | <defaulttarget/> |
|---|
| | 422 | <makeoptions/> |
|---|
| 421 | 423 | <selectedenvironment>default</selectedenvironment> |
|---|
| 422 | 424 | <environments> |
|---|
| … | … | |
| 433 | 435 | <kdevdebugger> |
|---|
| 434 | 436 | <general> |
|---|
| 435 | | <gdbpath></gdbpath> |
|---|
| 436 | | <dbgshell></dbgshell> |
|---|
| 437 | | <configGdbScript></configGdbScript> |
|---|
| 438 | | <runShellScript></runShellScript> |
|---|
| 439 | | <runGdbScript></runGdbScript> |
|---|
| | 437 | <gdbpath/> |
|---|
| | 438 | <dbgshell/> |
|---|
| | 439 | <configGdbScript/> |
|---|
| | 440 | <runShellScript/> |
|---|
| | 441 | <runGdbScript/> |
|---|
| 440 | 442 | <breakonloadinglibs>true</breakonloadinglibs> |
|---|
| 441 | 443 | <separatetty>false</separatetty> |
|---|
| r109 |
r127 |
|
| 99 | 99 | size_t aligntsize(size_t tsize) |
|---|
| 100 | 100 | { |
|---|
| 101 | | // Is pointer alignment on the x64 4 bytes or 8? |
|---|
| 102 | | return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); |
|---|
| | 101 | // Is pointer alignment on the x86-64 4 bytes or 8? |
|---|
| | 102 | //return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1); |
|---|
| | 103 | return (tsize + 3) & (~3); |
|---|
| 103 | 104 | } |
|---|
| 104 | 105 | |
|---|
| … | … | |
| 743 | 744 | */ |
|---|
| 744 | 745 | |
|---|
| 745 | | extern (C) |
|---|
| | 746 | version(none) // not used, C variadics can't be implemented in LLVM on x86-64 |
|---|
| | 747 | { |
|---|
| 746 | 748 | BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...) |
|---|
| 747 | 749 | { |
|---|
| … | … | |
| 820 | 822 | return result; |
|---|
| 821 | 823 | } |
|---|
| 822 | | |
|---|
| 823 | | |
|---|
| | 824 | } |
|---|
| | 825 | |
|---|