Variant EvalCreateFunction::InvokeImpl(VariableEnvironment &env, CArrRef params) { int size = params.size(); if (size != 2) return invalid_function_call("create_function"); Variant var = params.rvalAt(0); Variant body = params.rvalAt(1); vector<StaticStatementPtr> statics; ostringstream fnStream; string id(RequestEvalState::unique()); fnStream << "<?php function lambda_" << id << "(" << var.toString().data() << ") {" << body.toString().data() << "}\n"; StatementPtr bodyAst = Parser::ParseString(fnStream.str().c_str(), statics); if (!bodyAst) return false; ostringstream nameStream; nameStream << "$lambda_" << id; FunctionStatementPtr f = bodyAst->cast<StatementListStatement>()->stmts()[0]; ASSERT(f); f->changeName(nameStream.str()); SmartPtr<CodeContainer> cc(new StringCodeContainer(bodyAst)); RequestEvalState::addCodeContainer(cc); f->eval(env); return f->name(); }
Variant EvalFuncGetArg::InvokeImpl(VariableEnvironment &env, CArrRef params) { int size = params.size(); switch (size) { case 1: { int n = params.rvalAt(0); if (ObjectData *cont = env.getContinuation()) { return cont->o_invoke("get_arg", CREATE_VECTOR1(n)); } if (n >= 0 && n < env.getParams().size()) { return env.getParams().rvalAt(n); } return false; } default: return invalid_function_call("func_get_arg"); } }
Array Array::diffImpl(CArrRef array, bool by_key, bool by_value, bool match, PFUNC_CMP key_cmp_function, const void *key_data, PFUNC_CMP value_cmp_function, const void *value_data) const { ASSERT(by_key || by_value); ASSERT(by_key || key_cmp_function == NULL); ASSERT(by_value || value_cmp_function == NULL); PFUNC_CMP value_cmp_as_string_function = value_cmp_function; if (!value_cmp_function) { value_cmp_function = SortStringAscending; value_cmp_as_string_function = CompareAsStrings; } Array ret = Array::Create(); if (by_key && !key_cmp_function) { // Fast case for (ArrayIter iter(*this); iter; ++iter) { Variant key(iter.first()); CVarRef value(iter.secondRef()); bool found = false; if (array->exists(key)) { if (by_value) { found = value_cmp_as_string_function( value, array.rvalAt(key, AccessFlags::Key), value_data) == 0; } else { found = true; } } if (found == match) { ret.addLval(key, true).setWithRef(value); } } return ret; } if (!key_cmp_function) { key_cmp_function = SortRegularAscending; } vector<int> perm1; SortData opaque1; int bottom = 0; int top = array.size(); PFUNC_CMP cmp; const void *cmp_data; if (by_key) { cmp = key_cmp_function; cmp_data = key_data; } else { cmp = value_cmp_function; cmp_data = value_data; } SortImpl(perm1, array, opaque1, cmp, by_key, cmp_data); for (ArrayIter iter(*this); iter; ++iter) { Variant target; if (by_key) { target = iter.first(); } else { target = iter.second(); } int mid = -1; int min = bottom; int max = top; while (min < max) { mid = (max + min) / 2; ssize_t pos = opaque1.positions[perm1[mid]]; int cmp_res = cmp(target, by_key ? array->getKey(pos) : array->getValueRef(pos), cmp_data); if (cmp_res > 0) { // outer is bigger min = mid + 1; } else if (cmp_res == 0) { break; } else { max = mid; } } bool found = false; if (min < max) { // found // if checking both, check value if (by_key && by_value) { CVarRef val(iter.secondRef()); // Have to look up and down for matches for (int i = mid; i < max; i++) { ssize_t pos = opaque1.positions[perm1[i]]; if (key_cmp_function(target, array->getKey(pos), key_data) != 0) { break; } if (value_cmp_as_string_function(val, array->getValueRef(pos), value_data) == 0) { found = true; break; } } if (!found) { for (int i = mid-1; i >= min; i--) { ssize_t pos = opaque1.positions[perm1[i]]; if (key_cmp_function(target, array->getKey(pos), key_data) != 0) { break; } if (value_cmp_as_string_function(val, array->getValueRef(pos), value_data) == 0) { found = true; break; } } } } else { // found at mid found = true; } } if (found == match) { ret.addLval(iter.first(), true).setWithRef(iter.secondRef()); } } return ret; }
Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, CArrRef fieldspec) { Variant ret; switch (thrift_typeID) { case T_STOP: case T_VOID: return uninit_null(); case T_STRUCT: { Variant val; if ((val = fieldspec.rvalAt(PHPTransport::s_class)).isNull()) { throw_tprotocolexception("no class type in spec", INVALID_DATA); skip_element(T_STRUCT, transport); return uninit_null(); } String structType = val.toString(); ret = createObject(structType); if (ret.isNull()) { // unable to create class entry skip_element(T_STRUCT, transport); return uninit_null(); } Variant spec = f_hphp_get_static_property(structType, s_TSPEC, false); if (!spec.is(KindOfArray)) { char errbuf[128]; snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType.data(), ret.getType()); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); return uninit_null(); } binary_deserialize_spec(ret.toObject(), transport, spec.toArray()); return ret; } break; case T_BOOL: { uint8_t c; transport.readBytes(&c, 1); return c != 0; } //case T_I08: // same numeric value as T_BYTE case T_BYTE: { uint8_t c; transport.readBytes(&c, 1); return Variant((int8_t)c); } case T_I16: { uint16_t c; transport.readBytes(&c, 2); return Variant((int16_t)ntohs(c)); } case T_I32: { uint32_t c; transport.readBytes(&c, 4); return Variant((int32_t)ntohl(c)); } case T_U64: case T_I64: { uint64_t c; transport.readBytes(&c, 8); return Variant((int64_t)ntohll(c)); } case T_DOUBLE: { union { uint64_t c; double d; } a; transport.readBytes(&(a.c), 8); a.c = ntohll(a.c); return a.d; } case T_FLOAT: { union { uint32_t c; float d; } a; transport.readBytes(&(a.c), 4); a.c = ntohl(a.c); return a.d; } //case T_UTF7: // aliases T_STRING case T_UTF8: case T_UTF16: case T_STRING: { uint32_t size = transport.readU32(); if (size && (size + 1)) { String s = String(size, ReserveString); char* strbuf = s.bufferSlice().ptr; transport.readBytes(strbuf, size); return s.setSize(size); } else { return ""; } } case T_MAP: { // array of key -> value uint8_t types[2]; transport.readBytes(types, 2); uint32_t size = transport.readU32(); Array keyspec = fieldspec.rvalAt(PHPTransport::s_key, AccessFlags::Error_Key).toArray(); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); ret = Array::Create(); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(types[0], transport, keyspec); Variant value = binary_deserialize(types[1], transport, valspec); ret.set(key, value); } return ret; // return_value already populated } case T_LIST: { // array with autogenerated numeric keys int8_t type = transport.readI8(); uint32_t size = transport.readU32(); Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key); Array elemspec = elemvar.toArray(); ret = Array::Create(); for (uint32_t s = 0; s < size; ++s) { Variant value = binary_deserialize(type, transport, elemspec); ret.append(value); } return ret; } case T_SET: { // array of key -> TRUE uint8_t type; uint32_t size; transport.readBytes(&type, 1); transport.readBytes(&size, 4); size = ntohl(size); Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key); Array elemspec = elemvar.toArray(); ret = Array::Create(); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(type, transport, elemspec); if (key.isInteger()) { ret.set(key, true); } else { ret.set(key.toString(), true); } } return ret; } }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); return uninit_null(); }
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, CVarRef value, CArrRef fieldspec) { // At this point the typeID (and field num, if applicable) should've already // been written to the output so all we need to do is write the payload. switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: { if (!value.is(KindOfObject)) { throw_tprotocolexception("Attempt to send non-object " "type as a T_STRUCT", INVALID_DATA); } binary_serialize_spec(value.toObject(), transport, f_hphp_get_static_property(value.toObject()-> o_getClassName(), s_TSPEC, false).toArray()); } return; case T_BOOL: transport.writeI8(value.toBoolean() ? 1 : 0); return; case T_BYTE: transport.writeI8(value.toByte()); return; case T_I16: transport.writeI16(value.toInt16()); return; case T_I32: transport.writeI32(value.toInt32()); return; case T_I64: case T_U64: transport.writeI64(value.toInt64()); return; case T_DOUBLE: { union { int64_t c; double d; } a; a.d = value.toDouble(); transport.writeI64(a.c); } return; case T_FLOAT: { union { int32_t c; float d; } a; a.d = (float)value.toDouble(); transport.writeI32(a.c); } return; //case T_UTF7: case T_UTF8: case T_UTF16: case T_STRING: { String sv = value.toString(); transport.writeString(sv.data(), sv.size()); } return; case T_MAP: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_ktype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_vtype, AccessFlags::Error_Key).toByte(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_LIST: { Array ht = value.toArray(); Variant val; uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toInt64(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_SET: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); } } return; }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); }