void f_debug_print_backtrace() { if (RuntimeOption::InjectedStackTrace) { Array bt = FrameInjection::GetBacktrace(true); int i = 0; for (ArrayIter it = bt.begin(); !it.end(); it.next(), i++) { Array frame = it.second().toArray(); StringBuffer buf; buf.append('#'); buf.append(i); if (i < 10) buf.append(' '); buf.append(' '); if (frame.exists("class")) { buf.append(frame->get("class").toString()); buf.append(frame->get("type").toString()); } buf.append(frame->get("function").toString()); buf.append("()"); if (frame.exists("file")) { buf.append(" called at ["); buf.append(frame->get("file").toString()); buf.append(':'); buf.append(frame->get("line").toString()); buf.append(']'); } buf.append('\n'); echo(buf.detach()); } } else { StackTrace st; echo(String(st.toString())); } }
ALWAYS_INLINE typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, Object>::type BaseMap::php_zip(const Variant& iterable) const { size_t sz; ArrayIter iter = getArrayIterHelper(iterable, sz); auto map = req::make<TMap>(); if (!m_size) { return Object{std::move(map)}; } map->reserve(std::min(sz, size_t(m_size))); uint32_t used = posLimit(); for (uint32_t i = 0; i < used && iter; ++i) { if (isTombstone(i)) continue; const Elm& e = data()[i]; Variant v = iter.second(); auto pair = req::make<c_Pair>(c_Pair::NoInit{}); pair->initAdd(&e.data); pair->initAdd(v); TypedValue tv; tv.m_data.pobj = pair.detach(); tv.m_type = KindOfObject; if (e.hasIntKey()) { map->setRaw(e.ikey, &tv); } else { assert(e.hasStrKey()); map->setRaw(e.skey, &tv); } ++iter; } return Object{std::move(map)}; }
/** * iter_next will advance the iterator to point to the next element. * If the iterator reaches the end, iter_next will free the iterator * and will decRef the array. * This function has been split into hot and cold parts. The hot part has * been carefully crafted so that it's a leaf function (after all functions * it calls have been trivially inlined) that then tail calls a cold * version of itself (iter_next_array_cold). The hot part should cover the * common case, which occurs when the array parameter is an HphpArray. * If you make any changes to this function, please keep the hot/cold * splitting in mind, and disasemble the optimized version of the binary * to make sure the hot part is a good-looking leaf function; otherwise, * you're likely to get a performance regression. */ static NEVER_INLINE int64 iter_next_cold(Iter* iter, TypedValue* valOut, TypedValue* keyOut) { TRACE(2, "iter_next_cold: I %p\n", iter); ASSERT(iter->m_itype == Iter::TypeArray || iter->m_itype == Iter::TypeIterator); ArrayIter* ai = &iter->arr(); ai->next(); if (ai->end()) { // The ArrayIter destructor will decRef the array ai->~ArrayIter(); iter->m_itype = Iter::TypeUndefined; return 0; } if (iter->m_itype == Iter::TypeArray) { iter_value_cell_local_impl<true>(iter, valOut); if (keyOut) { iter_key_cell_local_impl<true>(iter, keyOut); } } else { iter_value_cell_local_impl<false>(iter, valOut); if (keyOut) { iter_key_cell_local_impl<false>(iter, keyOut); } } return 1; }
String debug_string_backtrace(bool skip) { if (RuntimeOption::InjectedStackTrace) { Array bt; StringBuffer buf; bt = g_vmContext->debugBacktrace(skip); int i = 0; for (ArrayIter it = bt.begin(); !it.end(); it.next(), i++) { Array frame = it.second().toArray(); buf.append('#'); buf.append(i); if (i < 10) buf.append(' '); buf.append(' '); if (frame.exists(s_class)) { buf.append(frame->get(s_class).toString()); buf.append(frame->get(s_type).toString()); } buf.append(frame->get(s_function).toString()); buf.append("()"); if (frame.exists(s_file)) { buf.append(" called at ["); buf.append(frame->get(s_file).toString()); buf.append(':'); buf.append(frame->get(s_line).toString()); buf.append(']'); } buf.append('\n'); } return buf.detach(); } else { StackTrace st; return String(st.toString()); } }
void BaseMap::setAllImpl(const Variant& iterable) { if (iterable.isNull()) return; size_t sz; ArrayIter iter = getArrayIterHelper(iterable, sz); for (; iter; ++iter) { set(iter.first(), iter.second()); } }
void BaseVector::init(CVarRef t) { size_t sz; ArrayIter iter = getArrayIterHelper(t, sz); if (sz) { reserve(sz); } for (; iter; ++iter) { Variant v = iter.second(); TypedValue* tv = cvarToCell(&v); add(tv); } }
void BaseMap::addAllPairs(const Variant& iterable) { if (iterable.isNull()) return; VMRegGuard _; size_t sz; ArrayIter iter = getArrayIterHelper(iterable, sz); auto oldCap = cap(); reserve(m_size + sz); // presume minimum key collisions ... for (; iter; ++iter) { add(iter.second()); } // ... and shrink back if that was incorrect shrinkIfCapacityTooHigh(oldCap); }
String debug_string_backtrace(bool skip, bool ignore_args /* = false */, int64_t limit /* = 0 */) { Array bt; StringBuffer buf; bt = createBacktrace(BacktraceArgs() .skipTop(skip) .ignoreArgs(ignore_args) .setLimit(limit)); int i = 0; for (ArrayIter it = bt.begin(); !it.end(); it.next(), i++) { Array frame = it.second().toArray(); buf.append('#'); buf.append(i); if (i < 10) buf.append(' '); buf.append(' '); if (frame.exists(s_class)) { buf.append(frame->get(s_class).toString()); buf.append(frame->get(s_type).toString()); } buf.append(frame->get(s_function).toString()); buf.append("("); if (!ignore_args) { bool first = true; for (ArrayIter argsIt(frame->get(s_args).toArray()); !argsIt.end(); argsIt.next()) { if (!first) { buf.append(", "); } else { first = false; } try { buf.append(argsIt.second().toString()); } catch (FatalErrorException& fe) { buf.append(fe.getMessage()); } } } buf.append(")"); if (frame.exists(s_file)) { buf.append(" called at ["); buf.append(frame->get(s_file).toString()); buf.append(':'); buf.append(frame->get(s_line).toString()); buf.append(']'); } buf.append('\n'); } return buf.detach(); }
/* This function is called repeatedly by rl_completion_matches. The first * invocation has state = 0, subsequent ones have state != 0. A return value of * nullptr indicates that all possible completions have been returned. */ static char* _readline_command_generator(const char* text, int state) { static ArrayIter iter; if (state == 0) { iter = s_readline->array.begin(); } auto text_str = String(text); while (iter) { auto value = iter.secondRef().toString(); ++iter; if (text_str == value.substr(0, text_str.length())) { // readline frees this using free(), so we must use malloc() and not new return strdup(value.data()); } } return nullptr; }
HOT_FUNC int64 iter_next_key(Iter* iter, TypedValue* valOut, TypedValue* keyOut) { TRACE(2, "iter_next: I %p\n", iter); ASSERT(iter->m_itype == Iter::TypeArray || iter->m_itype == Iter::TypeIterator); ArrayIter* arrIter = &iter->arr(); valOut = tvToCell(valOut); keyOut = tvToCell(keyOut); if (UNLIKELY(!arrIter->hasArrayData())) { goto cold; } { const ArrayData* ad = arrIter->getArrayData(); if (UNLIKELY(!IsHphpArray(ad))) { goto cold; } const HphpArray* arr = (HphpArray*)ad; ssize_t pos = arrIter->getPos(); if (size_t(pos) >= size_t(arr->getLastE())) { if (UNLIKELY(arr->getCount() == 1)) { goto cold; } arr->decRefCount(); iter->m_itype = Iter::TypeUndefined; return 0; } pos = pos + 1; HphpArray::Elm* elm = arr->getElm(pos); if (UNLIKELY(elm->data.m_type >= HphpArray::KindOfTombstone)) { goto cold; } if (UNLIKELY(tvWillBeReleased(valOut))) { goto cold; } if (UNLIKELY(tvWillBeReleased(keyOut))) { goto cold; } tvDecRefOnly(valOut); tvDecRefOnly(keyOut); arrIter->setPos(pos); getHphpArrayElm(elm, valOut, keyOut); return 1; } cold: return iter_next_cold(iter, valOut, keyOut); }
void BaseVector::zip(BaseVector* bvec, CVarRef iterable) { size_t itSize; ArrayIter iter = getArrayIterHelper(iterable, itSize); uint sz = m_size; bvec->reserve(std::min(itSize, size_t(sz))); for (uint i = 0; i < sz && iter; ++i, ++iter) { Variant v = iter.second(); if (bvec->m_capacity <= bvec->m_size) { bvec->grow(); } c_Pair* pair = NEWOBJ(c_Pair)(); pair->incRefCount(); pair->initAdd(&m_data[i]); pair->initAdd(cvarToCell(&v)); bvec->m_data[i].m_data.pobj = pair; bvec->m_data[i].m_type = KindOfObject; ++bvec->m_size; } }
String debug_string_backtrace(bool skip, bool ignore_args /* = false */, int limit /* = 0 */) { if (RuntimeOption::InjectedStackTrace) { Array bt; StringBuffer buf; bt = g_context->debugBacktrace(skip, false, false, nullptr, ignore_args, limit); int i = 0; for (ArrayIter it = bt.begin(); !it.end(); it.next(), i++) { Array frame = it.second().toArray(); buf.append('#'); buf.append(i); if (i < 10) buf.append(' '); buf.append(' '); if (frame.exists(s_class)) { buf.append(frame->get(s_class).toString()); buf.append(frame->get(s_type).toString()); } buf.append(frame->get(s_function).toString()); buf.append("("); if (!ignore_args) { bool first = true; for (ArrayIter it = frame->get(s_args).begin(); !it.end(); it.next()) { if (!first) { buf.append(", "); } else { first = false; } try { buf.append(it.second().toString()); } catch (FatalErrorException& fe) { buf.append(fe.getMessage()); } } } buf.append(")"); if (frame.exists(s_file)) { buf.append(" called at ["); buf.append(frame->get(s_file).toString()); buf.append(':'); buf.append(frame->get(s_line).toString()); buf.append(']'); } buf.append('\n'); } return buf.detach(); } else { StackTrace st; return String(st.toString()); } }
ALWAYS_INLINE typename std::enable_if< std::is_base_of<BaseMap, TMap>::value, Object>::type BaseMap::FromItems(const Class*, const Variant& iterable) { if (iterable.isNull()) return Object{req::make<TMap>()}; VMRegGuard _; size_t sz; ArrayIter iter = getArrayIterHelper(iterable, sz); auto target = req::make<TMap>(); target->reserve(sz); for (; iter; ++iter) { Variant v = iter.second(); TypedValue* tv = v.asCell(); if (UNLIKELY(tv->m_type != KindOfObject || tv->m_data.pobj->getVMClass() != c_Pair::classof())) { SystemLib::throwInvalidArgumentExceptionObject( "Parameter must be an instance of Iterable<Pair>"); } auto pair = static_cast<c_Pair*>(tv->m_data.pobj); target->setRaw(&pair->elm0, &pair->elm1); } return Object{std::move(target)}; }
typename std::enable_if< std::is_base_of<BaseVector, TVector>::value, Object>::type BaseSet::php_concat(const Variant& iterable) { size_t itSize; ArrayIter iter = getArrayIterHelper(iterable, itSize); auto vec = req::make<TVector>(); uint32_t sz = m_size; vec->reserve((size_t)sz + itSize); assert(vec->canMutateBuffer()); vec->setSize(sz); uint32_t used = posLimit(); for (uint32_t i = 0, j = 0; i < used; ++i) { if (isTombstone(i)) { continue; } cellDup(data()[i].data, vec->data()[j]); ++j; } for (; iter; ++iter) { vec->addRaw(iter.second()); } return Object{std::move(vec)}; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) { if (Loaded) return true; Loaded = true; // load extension functions first, so system/classes may call them ParseExtFunctions(ar, ExtensionFunctions, false); AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult()); s_variables = VariableTablePtr(new VariableTable(*ar2.get())); s_constants = ConstantTablePtr(new ConstantTable(*ar2.get())); // parse all PHP files under system/classes if (!extOnly) { ar = AnalysisResultPtr(new AnalysisResult()); ar->loadBuiltinFunctions(); string slib = systemlib_path(); if (slib.empty()) { for (const char **cls = SystemClasses; *cls; cls++) { string phpBaseName = "/system/classes/"; phpBaseName += *cls; phpBaseName += ".php"; Parse(ar, phpBaseName, Option::GetSystemRoot() + phpBaseName); } } else { Parse(ar, slib, slib); } ar->analyzeProgram(true); ar->inferTypes(); const StringToFileScopePtrMap &files = ar->getAllFiles(); for (StringToFileScopePtrMap::const_iterator iterFile = files.begin(); iterFile != files.end(); iterFile++) { const StringToClassScopePtrVecMap &classes = iterFile->second->getClasses(); for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(); iter != classes.end(); ++iter) { assert(iter->second.size() == 1); iter->second[0]->setSystem(); assert(!s_classes[iter->first]); s_classes[iter->first] = iter->second[0]; } } } else { NoSuperGlobals = true; } // load extension constants, classes and dynamics ParseExtConsts(ar, ExtensionConsts, false); ParseExtClasses(ar, ExtensionClasses, false); for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) { Option::SepExtensionOptions &options = Option::SepExtensions[i]; string soname = options.soname; if (soname.empty()) { soname = string("lib") + options.name + ".so"; } if (!options.lib_path.empty()) { soname = options.lib_path + "/" + soname; } if (!LoadSepExtensionSymbols(ar, options.name, soname)) { return false; } } if (!extOnly) { Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (s_constants->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; s_constants->add(key.toCStrRef().data(), t, e, ar2, e); } s_variables = ar2->getVariables(); for (int i = 0, n = NumGlobalNames(); i < n; ++i) { s_variables->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } } s_constants->setDynamic(ar, "SID", true); return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar) { if (Loaded) return true; Loaded = true; if (g_context.isNull()) init_thread_locals(); ClassInfo::Load(); // load extension functions first, so system/php may call them ImportExtFunctions(ar, ClassInfo::GetSystem()); ConstantTablePtr cns = ar->getConstants(); // load extension constants, classes and dynamics ImportNativeConstants(ar, cns); ImportExtConstants(ar, cns, ClassInfo::GetSystem()); ImportExtClasses(ar); Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (cns->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar, ar, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; cns->add(key.toCStrRef().data(), t, e, ar, e); } for (int i = 0, n = NumGlobalNames(); i < n; ++i) { ar->getVariables()->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } cns->setDynamic(ar, "PHP_BINARY", true); cns->setDynamic(ar, "PHP_BINDIR", true); cns->setDynamic(ar, "PHP_OS", true); cns->setDynamic(ar, "PHP_SAPI", true); cns->setDynamic(ar, "SID", true); // Systemlib files were all parsed by hphp_process_init const StringToFileScopePtrMap &files = ar->getAllFiles(); for (const auto& file : files) { file.second->setSystem(); const auto& classes = file.second->getClasses(); for (const auto& clsVec : classes) { assert(clsVec.second.size() == 1); auto cls = clsVec.second[0]; cls->setSystem(); ar->addSystemClass(cls); for (const auto& func : cls->getFunctions()) { FunctionScope::RecordFunctionInfo(func.first, func.second); } } const auto& functions = file.second->getFunctions(); for (const auto& func : functions) { func.second->setSystem(); ar->addSystemFunction(func.second); FunctionScope::RecordFunctionInfo(func.first, func.second); } } return true; }
bool WddxPacket::recursiveAddVar(const String& varName, const Variant& varVariant, bool hasVarTag) { bool isArray = varVariant.isArray(); bool isObject = varVariant.isObject(); if (isArray || isObject) { if (hasVarTag) { m_packetString.append("<var name='"); m_packetString.append(varName.data()); m_packetString.append("'>"); } Array varAsArray; Object varAsObject = varVariant.toObject(); if (isArray) varAsArray = varVariant.toArray(); if (isObject) varAsArray = varAsObject.toArray(); int length = varAsArray.length(); if (length > 0) { ArrayIter it = ArrayIter(varAsArray); if (it.first().isString()) isObject = true; if (isObject) { m_packetString.append("<struct>"); if (!isArray) { m_packetString.append("<var name='php_class_name'><string>"); m_packetString.append(varAsObject->getClassName()); m_packetString.append("</string></var>"); } } else { m_packetString.append("<array length='"); m_packetString.append(std::to_string(length)); m_packetString.append("'>"); } for (ArrayIter it(varAsArray); it; ++it) { Variant key = it.first(); Variant value = it.second(); recursiveAddVar(key.toString(), value, isObject); } if (isObject) { m_packetString.append("</struct>"); } else { m_packetString.append("</array>"); } } else { //empty object if (isObject) { m_packetString.append("<struct>"); if (!isArray) { m_packetString.append("<var name='php_class_name'><string>"); m_packetString.append(varAsObject->getClassName()); m_packetString.append("</string></var>"); } m_packetString.append("</struct>"); } } if (hasVarTag) { m_packetString.append("</var>"); } return true; } String varType = getDataTypeString(varVariant.getType()); if (!getWddxEncoded(varType, "", varName, false).empty()) { String varValue; if (varType.compare("boolean") == 0) { varValue = varVariant.toBoolean() ? "true" : "false"; } else { varValue = StringUtil::HtmlEncode(varVariant.toString(), StringUtil::QuoteStyle::Double, "UTF-8", false, false).toCppString(); } m_packetString.append( getWddxEncoded(varType, varValue, varName, hasVarTag)); return true; } return false; }
bool TestCppBase::TestArray() { // Array::Create(), Array constructors and informational { Array arr; VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(arr.isNull()); arr = Array::Create(); VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(!arr.isNull()); arr = Array::Create(0); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY((int)arr[0] == 0); VS(arr, Array(ArrayInit(1).set(0).create())); arr = Array::Create("test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0] == "test"); VS(arr, Array(ArrayInit(1).set("test").create())); Array arrCopy = arr; arr = Array::Create(arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toArray().size() == 1); VS(arr[0], arrCopy); VS(arr, Array(ArrayInit(1).set(arrCopy).create())); arr = Array::Create("name", 1); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY((int)arr[s_name] == 1); VS(arr, Array(ArrayInit(1).set(s_name, 1).create())); arr = Array::Create(s_name, "test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[s_name] == "test"); VS(arr, Array(ArrayInit(1).set(s_name, "test").create())); arrCopy = arr; arr = Array::Create(s_name, arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VS(arr[s_name], arrCopy); VERIFY(arr[s_name].toArray().size() == 1); VS(arr, Array(ArrayInit(1).set(s_name, arrCopy).create())); } // iteration { Array arr = CREATE_MAP2("n1", "v1", "n2", "v2"); int i = 0; for (ArrayIter iter = arr.begin(); iter; ++iter, ++i) { if (i == 0) { VERIFY(iter.first() == "n1"); VERIFY(iter.second() == "v1"); } else { VERIFY(iter.first() == "n2"); VERIFY(iter.second() == "v2"); } } VERIFY(i == 2); } /* TODO: fix this { Variant arr = CREATE_MAP2("n1", "v1", "n2", "v2"); arr.escalate(); for (ArrayIterPtr iter = arr.begin(arr, true); !iter->end(); iter->next()){ unset(arr.lvalAt(iter->first())); } VS(arr, Array::Create()); } */ // conversions { Array arr0; VERIFY(arr0.toBoolean() == false); VERIFY(arr0.toByte() == 0); VERIFY(arr0.toInt16() == 0); VERIFY(arr0.toInt32() == 0); VERIFY(arr0.toInt64() == 0); VERIFY(arr0.toDouble() == 0.0); VERIFY(arr0.toString() == ""); Array arr1 = Array::Create("test"); VERIFY(arr1.toBoolean() == true); VERIFY(arr1.toByte() == 1); VERIFY(arr1.toInt16() == 1); VERIFY(arr1.toInt32() == 1); VERIFY(arr1.toInt64() == 1); VERIFY(arr1.toDouble() == 1.0); VERIFY(arr1.toString() == "Array"); } // offset { Array arr; arr.set(0, "v1"); arr.set(1, "v2"); VS(arr, CREATE_VECTOR2("v1", "v2")); } { Array arr; arr.set(s_n1, "v1"); arr.set(s_n2, "v2"); VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2")); } { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VS(arr, CREATE_VECTOR2("v1", "v2")); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VS(arr, CREATE_MAP2("n1", "v1", "n2", "v2")); } { Array arr; Variant name = "name"; arr.lvalAt(name) = String("value"); VS(arr, CREATE_MAP1("name", "value")); } { Array arr; arr.lvalAt(s_A) = 10; arr.lvalAt(s_A)++; VS(arr[s_A], 11); } { Array arr; arr.lvalAt(1) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant(1.5)) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(s_1) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant("1")) = 10; VS(arr[1], 10); VS(arr[1.5], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } // membership { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VERIFY(arr.exists(0)); arr.remove(0); VERIFY(!arr.exists(0)); VS(arr, Array::Create(1, "v2")); arr.append("v3"); VS(arr, CREATE_MAP2(1, "v2", 2, "v3")); } { static const StaticString s_0("0"); Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(String(s_0)); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant("0")); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant("0"))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant(0.5))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(Variant()) = 123; VERIFY(arr.exists(empty_string)); arr.remove(Variant()); VERIFY(!arr.exists(empty_string)); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VERIFY(arr.exists(s_n1)); arr.remove(s_n1); VERIFY(!arr.exists(s_n1)); VS(arr, Array::Create(s_n2, "v2")); arr.append("v3"); VS(arr, CREATE_MAP2("n2", "v2", 0, "v3")); } { Array arr; arr.lvalAt() = String("test"); VS(arr, CREATE_VECTOR1("test")); } { Array arr; arr.lvalAt(s_name) = String("value"); VERIFY(arr.exists(s_name)); } { Array arr; arr.lvalAt(1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(s_1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(1.5) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant(1.5)) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant("1")) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(1.5)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } // merge { Array arr = Array::Create(0) + Array::Create(1); VS(arr, Array::Create(0)); arr += CREATE_VECTOR2(0, 1); VS(arr, CREATE_VECTOR2(0, 1)); arr = Array::Create(0).merge(Array::Create(1)); VS(arr, CREATE_VECTOR2(0, 1)); arr = arr.merge(CREATE_VECTOR2(0, 1)); VS(arr, CREATE_VECTOR4(0, 1, 0, 1)); arr = Array::Create("s0").merge(Array::Create("s1")); VS(arr, CREATE_VECTOR2("s0", "s1")); arr = Array::Create("n0", "s0") + Array::Create("n1", "s1"); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); arr += CREATE_MAP2("n0", "s0", "n1", "s1"); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); arr = Array::Create("n0", "s0").merge(Array::Create("n1", "s1")); VS(arr, CREATE_MAP2("n0", "s0", "n1", "s1")); Array arrX = CREATE_MAP2("n0", "s2", "n1", "s3"); arr = arr.merge(arrX); VS(arr, CREATE_MAP2("n0", "s2", "n1", "s3")); } // slice { Array arr = CREATE_VECTOR2("test1", "test2"); Array sub = arr.slice(1, 1, true); VS(sub, CREATE_MAP1(1, "test2")); } { Array arr = CREATE_VECTOR2("test1", "test2"); Array sub = arr.slice(1, 1, false); VS(sub, CREATE_VECTOR1("test2")); } { Array arr = CREATE_MAP2("n1", "test1", "n2", "test2"); Array sub = arr.slice(1, 1, true); VS(sub, CREATE_MAP1("n2", "test2")); } { Array arr = CREATE_MAP2("n1", "test1", "n2", "test2"); Array sub = arr.slice(1, 1, false); VS(sub, CREATE_MAP1("n2", "test2")); } // escalation { Array arr; lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr; lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); lval(arr.lvalAt(0)).lvalAt(0) = 1.2; VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP1(s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create("test"); arr.lvalAt(0) = CREATE_VECTOR1(1.2); VS(arr, CREATE_VECTOR1(CREATE_VECTOR1(1.2))); } { Array arr = Array::Create("test"); lval(arr.lvalAt(s_name)).lvalAt(0) = 1.2; VS(arr, CREATE_MAP2(0, "test", s_name, CREATE_VECTOR1(1.2))); } { Array arr = Array::Create(); arr.append("apple"); arr.set(2, "pear"); VS(arr[2], "pear"); } { Array arr = CREATE_MAP2(0, "a", 1, "b"); VERIFY(arr->isVectorData()); } { Array arr = CREATE_MAP2(1, "a", 0, "b"); VERIFY(!arr->isVectorData()); } { Array arr = CREATE_MAP2(1, "a", 2, "b"); VERIFY(!arr->isVectorData()); } { Array arr = CREATE_MAP1(1, "a"); arr.set(0, "b"); VERIFY(!arr->isVectorData()); } return Count(true); }
static Variant yaf_route_rewrite_match(const Object& o, const char* req_uri, int req_uri_len) { char match[8192]; auto ptr_match = o->o_realProp(YAF_ROUTE_PROPETY_NAME_MATCH, ObjectData::RealPropUnchecked, "Yaf_Route_Rewrite"); snprintf(match, sizeof(match), "%s", ptr_match->toString().c_str()); std::string pattern; pattern.append(YAF_ROUTE_REGEX_DILIMITER_STR); pattern.append("^"); char* save_ptr; char* seg = strtok_r(match, YAF_ROUTER_URL_DELIMIETER, &save_ptr); while (seg != NULL) { int len = strlen(seg); if (len) { pattern.append(YAF_ROUTER_URL_DELIMIETER); if (*seg == '*') { pattern.append("(?P<__yaf_route_rest>.*)"); break; } if (*seg == ':') { pattern.append("(?P<"); pattern.append(std::string(seg+1)); pattern.append(std::string(">[^") + YAF_ROUTER_URL_DELIMIETER + "]+)"); } else { pattern.append(seg); } } seg = strtok_r(NULL, YAF_ROUTER_URL_DELIMIETER, &save_ptr); } pattern.append(YAF_ROUTE_REGEX_DILIMITER_STR); pattern.append("i"); Variant matches; Variant ret = preg_match_all(String(pattern), String(std::string(req_uri, req_uri_len)), matches); int match_count = 0; if (ret.isIntVal() ) { match_count = ret.toInt32(); } if (match_count <= 0) { return init_null_variant; } if (!matches.isArray()) { return init_null_variant; } Array args = Array::Create(); Array& arr_matches = matches.toArrRef(); ArrayIter iter = arr_matches.begin(); while (!iter.end()) { Variant key = iter.first(); Variant value = iter.second(); if (!key.isString()) { iter.next(); continue; } if (!strncmp(key.toString().c_str(), "__yaf_route_rest", key.toString().length())) { Variant retval = yaf_router_parse_parameters(value.toArrRef()[0].toString().c_str()); if (retval.isArray()) { args.merge(retval.toArray()); } } else { args.set(key, value.toArrRef()[0]); } iter.next(); } return args; }
void ForEachStatement::eval(VariableEnvironment &env) const { if (env.isGotoing()) return; ENTER_STMT; DECLARE_THREAD_INFO; LOOP_COUNTER(1); Variant map(m_source->eval(env)); if (m_key) { TempExpressionList *texp = m_key->cast<TempExpressionList>(); if (texp) { for (ArrayIter iter = map.begin(env.currentContext(), true); !iter.end(); iter.next()) { { LOOP_COUNTER_CHECK_INFO(1); const Variant &value = iter.second(); const Variant &key = iter.first(); TempExpressionHelper helper(texp, env); m_value->set(env, value); texp->setImpl(env, key); } if (!m_body) continue; EVAL_STMT_HANDLE_GOTO_BEGIN(restart1); EVAL_STMT_HANDLE_BREAK(m_body, env); EVAL_STMT_HANDLE_GOTO_END(restart1); } } else { for (ArrayIter iter = map.begin(env.currentContext(), true); !iter.end(); iter.next()) { LOOP_COUNTER_CHECK_INFO(1); const Variant &value = iter.second(); const Variant &key = iter.first(); m_value->set(env, value); m_key->set(env, key); if (!m_body) continue; EVAL_STMT_HANDLE_GOTO_BEGIN(restart2); EVAL_STMT_HANDLE_BREAK(m_body, env); EVAL_STMT_HANDLE_GOTO_END(restart2); } } } else { for (ArrayIter iter = map.begin(env.currentContext(), true); !iter.end(); iter.next()) { LOOP_COUNTER_CHECK_INFO(1); m_value->set(env, iter.second()); if (!m_body) continue; EVAL_STMT_HANDLE_GOTO_BEGIN(restart3); EVAL_STMT_HANDLE_BREAK(m_body, env); EVAL_STMT_HANDLE_GOTO_END(restart3); } } }
bool WddxPacket::recursiveAddVarImpl(const String& varName, const Variant& varVariant, bool hasVarTag, SeenContainers& seen) { bool isArray = varVariant.isArray(); bool isObject = varVariant.isObject(); if (isArray || isObject) { Array varAsArray; Object varAsObject; ArrayOrObject ptr; if (isArray) { varAsArray = varVariant.toArray(); ptr = varAsArray.get(); } if (isObject) { varAsObject = varVariant.toObject(); varAsArray = varAsObject.toArray(); ptr = varAsObject.get(); } assert(!ptr.isNull()); if (!seen.emplace(ptr).second) { raise_warning("recursion detected"); return false; } SCOPE_EXIT { seen.erase(ptr); }; if (hasVarTag) { m_packetString.append("<var name='"); m_packetString.append(varName.data()); m_packetString.append("'>"); } int length = varAsArray.length(); if (length > 0) { ArrayIter it = ArrayIter(varAsArray); if (it.first().isString()) isObject = true; if (isObject) { m_packetString.append("<struct>"); if (!isArray) { m_packetString.append("<var name='php_class_name'><string>"); m_packetString.append(varAsObject->getClassName()); m_packetString.append("</string></var>"); } } else { m_packetString.append("<array length='"); m_packetString.append(std::to_string(length)); m_packetString.append("'>"); } for (; it; ++it) { auto key = it.first(); auto const& value = it.secondRef(); recursiveAddVarImpl(key.toString(), value, isObject, seen); } if (isObject) { m_packetString.append("</struct>"); } else { m_packetString.append("</array>"); } } else { //empty object if (isObject) { m_packetString.append("<struct>"); if (!isArray) { m_packetString.append("<var name='php_class_name'><string>"); m_packetString.append(varAsObject->getClassName()); m_packetString.append("</string></var>"); } m_packetString.append("</struct>"); } } if (hasVarTag) { m_packetString.append("</var>"); } return true; }
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) { if (Loaded) return true; Loaded = true; if (g_context.isNull()) init_thread_locals(); ClassInfo::Load(); // load extension functions first, so system/classes may call them ImportExtFunctions(ar, s_functions, ClassInfo::GetSystem()); AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult()); s_variables = VariableTablePtr(new VariableTable(*ar2.get())); s_constants = ConstantTablePtr(new ConstantTable(*ar2.get())); // parse all PHP files under system/classes if (!extOnly) { ar = AnalysisResultPtr(new AnalysisResult()); ar->loadBuiltinFunctions(); string slib = get_systemlib(); Scanner scanner(slib.c_str(), slib.size(), Option::ScannerType, "systemlib.php"); Compiler::Parser parser(scanner, "systemlib.php", ar); if (!parser.parse()) { Logger::Error("Unable to parse systemlib.php: %s", parser.getMessage().c_str()); assert(false); } ar->analyzeProgram(true); ar->inferTypes(); const StringToFileScopePtrMap &files = ar->getAllFiles(); for (StringToFileScopePtrMap::const_iterator iterFile = files.begin(); iterFile != files.end(); iterFile++) { const StringToClassScopePtrVecMap &classes = iterFile->second->getClasses(); for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(); iter != classes.end(); ++iter) { assert(iter->second.size() == 1); iter->second[0]->setSystem(); assert(!s_classes[iter->first]); s_classes[iter->first] = iter->second[0]; } } } else { NoSuperGlobals = true; } // load extension constants, classes and dynamics ImportExtConstants(ar, s_constants, ClassInfo::GetSystem()); ImportExtClasses(ar); if (!extOnly) { Array constants = ClassInfo::GetSystemConstants(); LocationPtr loc(new Location); for (ArrayIter it = constants.begin(); it; ++it) { CVarRef key = it.first(); if (!key.isString()) continue; std::string name = key.toCStrRef().data(); if (s_constants->getSymbol(name)) continue; if (name == "true" || name == "false" || name == "null") continue; CVarRef value = it.secondRef(); if (!value.isInitialized() || value.isObject()) continue; ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value); TypePtr t = value.isNull() ? Type::Null : value.isBoolean() ? Type::Boolean : value.isInteger() ? Type::Int64 : value.isDouble() ? Type::Double : value.isArray() ? Type::Array : Type::Variant; s_constants->add(key.toCStrRef().data(), t, e, ar2, e); } s_variables = ar2->getVariables(); for (int i = 0, n = NumGlobalNames(); i < n; ++i) { s_variables->add(GlobalNames[i], Type::Variant, false, ar, ConstructPtr(), ModifierExpressionPtr()); } } s_constants->setDynamic(ar, "SID", true); return true; }
bool TestCppBase::TestArray() { // Array::Create(), Array constructors and informational { Array arr; VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(arr.isNull()); arr = Array::Create(); VERIFY(arr.empty()); VERIFY(arr.size() == 0); VERIFY(arr.length() == 0); VERIFY(!arr.isNull()); arr = Array::Create(0); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toInt32() == 0); arr = Array::Create("test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(equal(arr[0], String("test"))); Array arrCopy = arr; arr = Array::Create(arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[0].toArray().size() == 1); VS(arr[0], arrCopy); arr = Array::Create("name", 1); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(arr[s_name].toInt32() == 1); arr = Array::Create(s_name, "test"); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VERIFY(equal(arr[s_name], String("test"))); arrCopy = arr; arr = Array::Create(s_name, arr); VERIFY(!arr.empty()); VERIFY(arr.size() == 1); VERIFY(arr.length() == 1); VERIFY(!arr.isNull()); VS(arr[s_name], arrCopy); VERIFY(arr[s_name].toArray().size() == 1); } // iteration { Array arr = make_map_array("n1", "v1", "n2", "v2"); int i = 0; for (ArrayIter iter = arr.begin(); iter; ++iter, ++i) { if (i == 0) { VERIFY(equal(iter.first(), String("n1"))); VERIFY(equal(iter.second(), String("v1"))); } else { VERIFY(equal(iter.first(), String("n2"))); VERIFY(equal(iter.second(), String("v2"))); } } VERIFY(i == 2); } static const StaticString s_Array("Array"); // conversions { Array arr0; VERIFY(arr0.toBoolean() == false); VERIFY(arr0.toByte() == 0); VERIFY(arr0.toInt16() == 0); VERIFY(arr0.toInt32() == 0); VERIFY(arr0.toInt64() == 0); VERIFY(arr0.toDouble() == 0.0); VERIFY(arr0.toString().empty()); Array arr1 = Array::Create("test"); VERIFY(arr1.toBoolean() == true); VERIFY(arr1.toByte() == 1); VERIFY(arr1.toInt16() == 1); VERIFY(arr1.toInt32() == 1); VERIFY(arr1.toInt64() == 1); VERIFY(arr1.toDouble() == 1.0); VERIFY(arr1.toString() == s_Array); } // offset { Array arr; arr.set(0, "v1"); arr.set(1, "v2"); VS(arr, make_packed_array("v1", "v2")); } { Array arr; arr.set(s_n1, "v1"); arr.set(s_n2, "v2"); VS(arr, make_map_array("n1", "v1", "n2", "v2")); } { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VS(arr, make_packed_array("v1", "v2")); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VS(arr, make_map_array("n1", "v1", "n2", "v2")); } { Array arr; Variant name = "name"; arr.lvalAt(name) = String("value"); VS(arr, make_map_array("name", "value")); } { Array arr; arr.lvalAt(1) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant(1.5)) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(s_1) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } { Array arr; arr.lvalAt(Variant("1")) = 10; VS(arr[1], 10); VS(arr[Variant(1.5)], 10); VS(arr[s_1], 10); VS(arr[Variant("1")], 10); } // membership { Array arr; arr.lvalAt(0) = String("v1"); arr.lvalAt(1) = String("v2"); VERIFY(arr.exists(0)); arr.remove(0); VERIFY(!arr.exists(0)); VS(arr, Array::Create(1, "v2")); arr.append("v3"); VS(arr, make_map_array(1, "v2", 2, "v3")); } { static const StaticString s_0("0"); Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(String(s_0)); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant("0")); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant("0"))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(0) = String("v1"); VERIFY(arr.exists(0)); arr.remove(Variant(Variant(0.5))); VERIFY(!arr.exists(0)); } { Array arr; arr.lvalAt(Variant()) = 123; VERIFY(arr.exists(empty_string_ref)); arr.remove(Variant()); VERIFY(!arr.exists(empty_string_ref)); } { Array arr; arr.lvalAt(s_n1) = String("v1"); arr.lvalAt(s_n2) = String("v2"); VERIFY(arr.exists(s_n1)); arr.remove(s_n1); VERIFY(!arr.exists(s_n1)); VS(arr, Array::Create(s_n2, "v2")); arr.append("v3"); VS(arr, make_map_array("n2", "v2", 0, "v3")); } { Array arr; arr.lvalAt() = String("test"); VS(arr, make_packed_array("test")); } { Array arr; arr.lvalAt(s_name) = String("value"); VERIFY(arr.exists(s_name)); } { Array arr; arr.lvalAt(1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(s_1) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant(1.5)) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } { Array arr; arr.lvalAt(Variant("1")) = String("value"); VERIFY(arr.exists(1)); VERIFY(arr.exists(s_1)); VERIFY(arr.exists(Variant("1"))); VERIFY(arr.exists(Variant(1))); VERIFY(arr.exists(Variant(1.5))); } // merge { Array arr = Array::Create(0) + Array::Create(1); VS(arr, Array::Create(0)); arr += make_packed_array(0, 1); VS(arr, make_packed_array(0, 1)); arr = Array::Create(0).merge(Array::Create(1)); VS(arr, make_packed_array(0, 1)); arr = arr.merge(make_packed_array(0, 1)); VS(arr, make_packed_array(0, 1, 0, 1)); arr = Array::Create("s0").merge(Array::Create("s1")); VS(arr, make_packed_array("s0", "s1")); arr = Array::Create("n0", "s0") + Array::Create("n1", "s1"); VS(arr, make_map_array("n0", "s0", "n1", "s1")); arr += make_map_array("n0", "s0", "n1", "s1"); VS(arr, make_map_array("n0", "s0", "n1", "s1")); arr = Array::Create("n0", "s0").merge(Array::Create("n1", "s1")); VS(arr, make_map_array("n0", "s0", "n1", "s1")); Array arrX = make_map_array("n0", "s2", "n1", "s3"); arr = arr.merge(arrX); VS(arr, make_map_array("n0", "s2", "n1", "s3")); } { Array arr = make_map_array(0, "a", 1, "b"); VERIFY(arr->isVectorData()); } { Array arr = make_map_array(1, "a", 0, "b"); VERIFY(!arr->isVectorData()); } { Array arr = make_map_array(1, "a", 2, "b"); VERIFY(!arr->isVectorData()); } { Array arr = make_map_array(1, "a"); arr.set(0, "b"); VERIFY(!arr->isVectorData()); } return Count(true); }
bool TestExtPdo::test_pdo_sqlite() { CreateSqliteTestTable(); try { string source = "sqlite:/tmp/foo.db"; p_PDO dbh(NEWOBJ(c_PDO)()); dbh->t___construct(source.c_str(), TEST_USERNAME, TEST_PASSWORD, CREATE_MAP1(q_PDO$$ATTR_PERSISTENT, false)); Variant vstmt = dbh->t_prepare("select * from foo"); c_PDOStatement *stmt = vstmt.toObject().getTyped<c_PDOStatement>(); VERIFY(stmt->t_execute()); Variant rs = stmt->t_fetch(q_PDO$$FETCH_ASSOC); VS(rs, CREATE_MAP1("bar", "ABC")); rs = stmt->t_fetch(q_PDO$$FETCH_ASSOC); VS(rs, CREATE_MAP1("bar", "DEF")); } catch (Object &e) { VS(e, null); } try { string source = "sqlite:/tmp/foo.db"; p_PDO dbh(NEWOBJ(c_PDO)()); dbh->t___construct(source.c_str(), TEST_USERNAME, TEST_PASSWORD, CREATE_MAP1(q_PDO$$ATTR_PERSISTENT, false)); Variant vstmt = dbh->t_query("select * from foo"); ArrayIter iter = vstmt.begin(); VERIFY(!iter.end()); VS(iter.first(), 0); VS(iter.second(), CREATE_MAP2("bar", "ABC", 0, "ABC")); iter.next(); VERIFY(!iter.end()); VS(iter.first(), 1); VS(iter.second(), CREATE_MAP2("bar", "DEF", 0, "DEF")); iter.next(); VERIFY(iter.end()); } catch (Object &e) { VS(e, null); } try { string source = "sqlite:/tmp/foo.db"; p_PDO dbh(NEWOBJ(c_PDO)()); dbh->t___construct(source.c_str(), TEST_USERNAME, TEST_PASSWORD, CREATE_MAP1(q_PDO$$ATTR_PERSISTENT, false)); dbh->t_query("CREATE TABLE IF NOT EXISTS foobar (id INT)"); dbh->t_query("INSERT INTO foobar (id) VALUES (1)"); Variant res = dbh->t_query("SELECT id FROM foobar LIMIT 1"); c_PDOStatement *stmt = res.toObject().getTyped<c_PDOStatement>(); Variant ret = stmt->t_fetch(); VS(ret["id"], "1"); } catch (Object &e) { VS(e, null); } CleanupSqliteTestTable(); return Count(true); }