Rename runtime/base/zend_* to zend-
[hiphop-php.git] / hphp / runtime / base / tv_helpers.cpp
blobf60510bf35add8cebb54695bca4a8dc044684a27
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 2.00 of the Zend license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.zend.com/license/2_00.txt. |
12 | If you did not receive a copy of the Zend license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@zend.com so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/base/complex_types.h"
19 #include "hphp/runtime/base/dummy_resource.h"
20 #include "hphp/runtime/base/type_conversions.h"
21 #include "hphp/runtime/base/zend-functions.h"
23 #include "hphp/system/systemlib.h"
25 namespace HPHP {
27 //////////////////////////////////////////////////////////////////////
29 bool cellIsPlausible(const Cell cell) {
30 assert(cell.m_type != KindOfRef);
32 auto assertPtr = [](void* ptr) {
33 assert(ptr && (uintptr_t(ptr) % sizeof(ptr) == 0));
36 switch (cell.m_type) {
37 case KindOfUninit:
38 case KindOfNull:
39 break;
40 case KindOfBoolean:
41 assert(cell.m_data.num == 0 || cell.m_data.num == 1);
42 break;
43 case KindOfInt64:
44 case KindOfDouble:
45 break;
46 case KindOfStaticString:
47 assertPtr(cell.m_data.pstr);
48 assert(cell.m_data.pstr->isStatic());
49 break;
50 case KindOfString:
51 assertPtr(cell.m_data.pstr);
52 assert(is_refcount_realistic(cell.m_data.pstr->getCount()));
53 break;
54 case KindOfArray:
55 assertPtr(cell.m_data.parr);
56 assert(is_refcount_realistic(cell.m_data.parr->getCount()));
57 break;
58 case KindOfObject:
59 assertPtr(cell.m_data.pobj);
60 assert(!cell.m_data.pobj->isStatic());
61 break;
62 case KindOfResource:
63 assertPtr(cell.m_data.pres);
64 assert(!cell.m_data.pres->isStatic());
65 break;
66 case KindOfRef:
67 assert(!"KindOfRef found in a Cell");
68 break;
69 default:
70 not_reached();
72 return true;
75 bool tvIsPlausible(TypedValue tv) {
76 if (tv.m_type == KindOfRef) {
77 assert(tv.m_data.pref);
78 assert(uintptr_t(tv.m_data.pref) % sizeof(void*) == 0);
79 assert(is_refcount_realistic(tv.m_data.pref->getCount()));
80 tv = *tv.m_data.pref->tv();
82 return cellIsPlausible(tv);
85 bool refIsPlausible(const Ref ref) {
86 assert(ref.m_type == KindOfRef);
87 return tvIsPlausible(ref);
90 inline void tvUnboxIfNeeded(TypedValue *tv) {
91 if (tv->m_type == KindOfRef) {
92 tvUnbox(tv);
96 void tvCastToBooleanInPlace(TypedValue* tv) {
97 assert(tvIsPlausible(*tv));
98 tvUnboxIfNeeded(tv);
99 bool b;
100 switch (tv->m_type) {
101 case KindOfUninit:
102 case KindOfNull: b = false; break;
103 case KindOfBoolean: return;
104 case KindOfInt64: b = (tv->m_data.num != 0LL); break;
105 case KindOfDouble: b = (tv->m_data.dbl != 0); break;
106 case KindOfStaticString: b = tv->m_data.pstr->toBoolean(); break;
107 case KindOfString: b = tv->m_data.pstr->toBoolean(); tvDecRefStr(tv); break;
108 case KindOfArray: b = (!tv->m_data.parr->empty()); tvDecRefArr(tv); break;
109 case KindOfObject: b = tv->m_data.pobj->o_toBoolean();
110 tvDecRefObj(tv);
111 break;
112 case KindOfResource: b = tv->m_data.pres->o_toBoolean();
113 tvDecRefRes(tv);
114 break;
115 default: assert(false); b = false; break;
117 tv->m_data.num = b;
118 tv->m_type = KindOfBoolean;
121 void tvCastToDoubleInPlace(TypedValue* tv) {
122 assert(tvIsPlausible(*tv));
123 tvUnboxIfNeeded(tv);
125 double d;
126 switch (tv->m_type) {
127 case KindOfUninit:
128 case KindOfNull: d = 0.0; break;
129 case KindOfBoolean: assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL);
130 case KindOfInt64: d = (double)(tv->m_data.num); break;
131 case KindOfDouble: return;
132 case KindOfStaticString: d = tv->m_data.pstr->toDouble(); break;
133 case KindOfString: d = tv->m_data.pstr->toDouble(); tvDecRefStr(tv); break;
134 case KindOfArray: {
135 d = (double)(tv->m_data.parr->empty() ? 0LL : 1LL);
136 tvDecRefArr(tv);
137 break;
139 case KindOfObject: {
140 d = tv->m_data.pobj->o_toDouble();
141 tvDecRefObj(tv);
142 break;
144 case KindOfResource: {
145 d = tv->m_data.pres->o_toDouble();
146 tvDecRefRes(tv);
147 break;
149 default: assert(false); d = 0.0; break;
151 tv->m_data.dbl = d;
152 tv->m_type = KindOfDouble;
155 void cellCastToInt64InPlace(Cell* cell) {
156 assert(cellIsPlausible(*cell));
158 int64_t i;
159 switch (cell->m_type) {
160 case KindOfUninit:
161 case KindOfNull:
162 cell->m_data.num = 0LL;
163 // Fall through
164 case KindOfBoolean:
165 assert(cell->m_data.num == 0LL || cell->m_data.num == 1LL);
166 cell->m_type = KindOfInt64;
167 // Fall through
168 case KindOfInt64:
169 return;
170 case KindOfDouble: {
171 i = toInt64(cell->m_data.dbl);
172 break;
174 case KindOfStaticString: i = (cell->m_data.pstr->toInt64()); break;
175 case KindOfString: {
176 i = cell->m_data.pstr->toInt64();
177 tvDecRefStr(cell);
178 break;
180 case KindOfArray:
181 i = cell->m_data.parr->empty() ? 0 : 1;
182 tvDecRefArr(cell);
183 break;
184 case KindOfObject:
185 i = cell->m_data.pobj->o_toInt64();
186 tvDecRefObj(cell);
187 break;
188 case KindOfResource:
189 i = cell->m_data.pres->o_toInt64();
190 tvDecRefRes(cell);
191 break;
192 default:
193 not_reached();
195 cell->m_data.num = i;
196 cell->m_type = KindOfInt64;
199 void tvCastToInt64InPlace(TypedValue* tv) {
200 assert(tvIsPlausible(*tv));
201 tvUnboxIfNeeded(tv);
202 cellCastToInt64InPlace(tv);
205 double tvCastToDouble(TypedValue* tv) {
206 assert(tvIsPlausible(*tv));
207 if (tv->m_type == KindOfRef) {
208 tv = tv->m_data.pref->tv();
211 switch(tv->m_type) {
212 case KindOfUninit:
213 case KindOfNull:
214 return 0;
215 case KindOfBoolean:
216 assert(tv->m_data.num == 0LL || tv->m_data.num == 1LL);
217 // Fall through
218 case KindOfInt64:
219 return (double)(tv->m_data.num);
220 case KindOfDouble:
221 return tv->m_data.dbl;
222 case KindOfStaticString:
223 case KindOfString:
224 return tv->m_data.pstr->toDouble();
225 case KindOfArray:
226 return tv->m_data.parr->empty() ? 0.0 : 1.0;
227 case KindOfObject:
228 return tv->m_data.pobj->o_toDouble();
229 case KindOfResource:
230 return tv->m_data.pres->o_toDouble();
231 default:
232 not_reached();
236 const StaticString
237 s_1("1"),
238 s_Array("Array"),
239 s_scalar("scalar");
241 void tvCastToStringInPlace(TypedValue* tv) {
242 assert(tvIsPlausible(*tv));
243 tvUnboxIfNeeded(tv);
244 StringData * s;
245 switch (tv->m_type) {
246 case KindOfUninit:
247 case KindOfNull: s = empty_string.get(); goto static_string;
248 case KindOfBoolean:
249 s = tv->m_data.num ? s_1.get() : empty_string.get();
250 goto static_string;
251 case KindOfInt64: s = buildStringData(tv->m_data.num); break;
252 case KindOfDouble: s = buildStringData(tv->m_data.dbl); break;
253 case KindOfStaticString:
254 case KindOfString: return;
255 case KindOfArray:
256 s = s_Array.get();
257 tvDecRefArr(tv);
258 goto static_string;
259 case KindOfObject:
260 // For objects, we fall back on the Variant machinery
261 tvAsVariant(tv) = tv->m_data.pobj->invokeToString();
262 return;
263 case KindOfResource:
264 // For resources, we fall back on the Variant machinery
265 tvAsVariant(tv) = tv->m_data.pres->o_toString();
266 return;
267 default:
268 not_reached();
271 s->incRefCount();
272 tv->m_data.pstr = s;
273 tv->m_type = KindOfString;
274 return;
275 static_string:
276 tv->m_data.pstr = s;
277 tv->m_type = KindOfStaticString;
280 StringData* tvCastToString(TypedValue* tv) {
281 assert(tvIsPlausible(*tv));
282 if (tv->m_type == KindOfRef) {
283 tv = tv->m_data.pref->tv();
286 StringData* s;
287 switch (tv->m_type) {
288 case KindOfUninit:
289 case KindOfNull: return empty_string.get();
290 case KindOfBoolean: return tv->m_data.num ? s_1.get() : empty_string.get();
291 case KindOfInt64: s = buildStringData(tv->m_data.num); break;
292 case KindOfDouble: s = buildStringData(tv->m_data.dbl); break;
293 case KindOfStaticString: return tv->m_data.pstr;
294 case KindOfString: s = tv->m_data.pstr; break;
295 case KindOfArray: return s_Array.get();
296 case KindOfObject: return tv->m_data.pobj->invokeToString().detach();
297 case KindOfResource: return tv->m_data.pres->o_toString().detach();
298 default: not_reached();
301 s->incRefCount();
302 return s;
305 void tvCastToArrayInPlace(TypedValue* tv) {
306 assert(tvIsPlausible(*tv));
307 tvUnboxIfNeeded(tv);
308 ArrayData * a;
309 switch (tv->m_type) {
310 case KindOfUninit:
311 case KindOfNull: a = ArrayData::Create(); break;
312 case KindOfBoolean:
313 case KindOfInt64:
314 case KindOfDouble:
315 case KindOfStaticString: a = ArrayData::Create(tvAsVariant(tv)); break;
316 case KindOfString: {
317 a = ArrayData::Create(tvAsVariant(tv));
318 tvDecRefStr(tv);
319 break;
321 case KindOfArray: return;
322 case KindOfObject: {
323 // For objects, we fall back on the Variant machinery
324 tvAsVariant(tv) = tv->m_data.pobj->o_toArray();
325 return;
327 case KindOfResource: {
328 // For resources, we fall back on the Variant machinery
329 tvAsVariant(tv) = tv->m_data.pres->o_toArray();
330 return;
332 default: assert(false); a = ArrayData::Create(); break;
334 tv->m_data.parr = a;
335 tv->m_type = KindOfArray;
336 tv->m_data.parr->incRefCount();
339 void tvCastToObjectInPlace(TypedValue* tv) {
340 assert(tvIsPlausible(*tv));
341 tvUnboxIfNeeded(tv);
342 ObjectData* o;
343 switch (tv->m_type) {
344 case KindOfUninit:
345 case KindOfNull: o = SystemLib::AllocStdClassObject(); break;
346 case KindOfBoolean:
347 case KindOfInt64:
348 case KindOfDouble:
349 case KindOfStaticString: {
350 o = SystemLib::AllocStdClassObject();
351 o->o_set(s_scalar, tvAsVariant(tv));
352 break;
354 case KindOfString: {
355 o = SystemLib::AllocStdClassObject();
356 o->o_set(s_scalar, tvAsVariant(tv));
357 tvDecRefStr(tv);
358 break;
360 case KindOfArray: {
361 // For arrays, we fall back on the Variant machinery
362 tvAsVariant(tv) = tv->m_data.parr->toObject();
363 return;
365 case KindOfObject: return;
366 case KindOfResource: return;
367 default: assert(false); o = SystemLib::AllocStdClassObject(); break;
369 tv->m_data.pobj = o;
370 tv->m_type = KindOfObject;
371 tv->m_data.pobj->incRefCount();
374 void tvCastToResourceInPlace(TypedValue* tv) {
375 assert(tvIsPlausible(*tv));
376 tvUnboxIfNeeded(tv);
377 switch (tv->m_type) {
378 case KindOfUninit:
379 case KindOfNull:
380 case KindOfBoolean:
381 case KindOfInt64:
382 case KindOfDouble:
383 case KindOfStaticString:
384 break;
385 case KindOfString:
386 case KindOfArray:
387 case KindOfObject:
388 tvDecRef(tv);
389 break;
390 case KindOfResource:
391 // no op, return
392 return;
393 default:
394 assert(false);
395 break;
397 tv->m_type = KindOfResource;
398 tv->m_data.pres = NEWOBJ(DummyResource);
399 tv->m_data.pres->incRefCount();
400 return;
403 bool tvCoerceParamToBooleanInPlace(TypedValue* tv) {
404 assert(tvIsPlausible(*tv));
405 tvUnboxIfNeeded(tv);
406 if (tv->m_type == KindOfArray || tv->m_type == KindOfObject ||
407 tv->m_type == KindOfResource) {
408 return false;
410 tvCastToBooleanInPlace(tv);
411 return true;
414 bool tvCanBeCoercedToNumber(TypedValue* tv) {
415 switch (tv->m_type) {
416 case KindOfStaticString:
417 case KindOfString:
418 StringData* s;
419 DataType type;
420 s = tv->m_data.pstr;
421 type = is_numeric_string(s->data(), s->size(), nullptr, nullptr);
422 if (type != KindOfDouble && type != KindOfInt64) {
423 return false;
425 break;
426 case KindOfArray:
427 case KindOfObject:
428 case KindOfResource:
429 return false;
430 default:
431 break;
433 return true;
436 bool tvCoerceParamToInt64InPlace(TypedValue* tv) {
437 assert(tvIsPlausible(*tv));
438 tvUnboxIfNeeded(tv);
439 if (!tvCanBeCoercedToNumber(tv)) {
440 return false;
442 tvCastToInt64InPlace(tv);
443 return true;
446 bool tvCoerceParamToDoubleInPlace(TypedValue* tv) {
447 assert(tvIsPlausible(*tv));
448 tvUnboxIfNeeded(tv);
449 if (!tvCanBeCoercedToNumber(tv)) {
450 return false;
452 tvCastToDoubleInPlace(tv);
453 return true;
456 bool tvCoerceParamToStringInPlace(TypedValue* tv) {
457 assert(tvIsPlausible(*tv));
458 tvUnboxIfNeeded(tv);
459 switch (tv->m_type) {
460 case KindOfArray:
461 return false;
462 case KindOfObject:
463 if (tv->m_data.pobj->hasToString()) {
464 tvAsVariant(tv) = tv->m_data.pobj->invokeToString();
465 return true;
467 return false;
468 case KindOfResource:
469 return false;
470 default:
471 break;
473 tvCastToStringInPlace(tv);
474 return true;
477 bool tvCoerceParamToArrayInPlace(TypedValue* tv) {
478 assert(tvIsPlausible(*tv));
479 tvUnboxIfNeeded(tv);
480 if (tv->m_type == KindOfArray) {
481 return true;
482 } else if (tv->m_type == KindOfObject) {
483 tvAsVariant(tv) = tv->m_data.pobj->o_toArray();
484 return true;
485 } else if (tv->m_type == KindOfResource) {
486 tvAsVariant(tv) = tv->m_data.pres->o_toArray();
487 return true;
489 return false;
492 bool tvCoerceParamToObjectInPlace(TypedValue* tv) {
493 assert(tvIsPlausible(*tv));
494 tvUnboxIfNeeded(tv);
495 return tv->m_type == KindOfObject;
498 bool tvCoerceParamToResourceInPlace(TypedValue* tv) {
499 assert(tvIsPlausible(*tv));
500 tvUnboxIfNeeded(tv);
501 return tv->m_type == KindOfResource;
504 ///////////////////////////////////////////////////////////////////////////////