2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/base_vector.h"
19 #include "hphp/runtime/ext/ext_array.h"
20 #include "hphp/runtime/ext/ext_collections.h"
23 ///////////////////////////////////////////////////////////////////////////////
27 bool BaseVector::isempty() {
31 int64_t BaseVector::count() {
35 Object
BaseVector::items() {
36 return SystemLib::AllocLazyIterableViewObject(this);
41 bool BaseVector::containskey(CVarRef key
) {
42 if (key
.isInteger()) {
43 return contains(key
.toInt64());
49 Variant
BaseVector::at(CVarRef key
) {
50 if (key
.isInteger()) {
51 return tvAsCVarRef(at(key
.toInt64()));
57 Variant
BaseVector::get(CVarRef key
) {
58 if (key
.isInteger()) {
59 TypedValue
* tv
= get(key
.toInt64());
61 return tvAsCVarRef(tv
);
72 Object
BaseVector::getiterator() {
73 c_VectorIterator
* it
= NEWOBJ(c_VectorIterator
)();
76 it
->m_version
= getVersion();
80 void BaseVector::map(BaseVector
* bvec
, CVarRef callback
) {
82 vm_decode_function(callback
, nullptr, false, ctx
);
84 Object
e(SystemLib::AllocInvalidArgumentExceptionObject(
85 "Parameter must be a valid callback"));
90 for (uint i
= 0; i
< sz
; ++i
) {
91 TypedValue
* tv
= &bvec
->m_data
[i
];
92 int32_t version
= m_version
;
93 g_vmContext
->invokeFuncFew(tv
, ctx
, 1, &m_data
[i
]);
94 if (UNLIKELY(version
!= m_version
)) {
95 tvRefcountedDecRef(tv
);
96 throw_collection_modified();
102 void BaseVector::mapwithkey(BaseVector
* bvec
, CVarRef callback
) {
104 vm_decode_function(callback
, nullptr, false, ctx
);
106 Object
e(SystemLib::AllocInvalidArgumentExceptionObject(
107 "Parameter must be a valid callback"));
112 for (uint i
= 0; i
< sz
; ++i
) {
113 TypedValue
* tv
= &bvec
->m_data
[i
];
114 int32_t version
= m_version
;
115 TypedValue args
[2] = {
116 make_tv
<KindOfInt64
>(i
),
119 g_vmContext
->invokeFuncFew(tv
, ctx
, 2, args
);
120 if (UNLIKELY(version
!= m_version
)) {
121 tvRefcountedDecRef(tv
);
122 throw_collection_modified();
128 void BaseVector::filter(BaseVector
* bvec
, CVarRef callback
) {
130 vm_decode_function(callback
, nullptr, false, ctx
);
132 Object
e(SystemLib::AllocInvalidArgumentExceptionObject(
133 "Parameter must be a valid callback"));
137 for (uint i
= 0; i
< sz
; ++i
) {
139 int32_t version
= m_version
;
140 g_vmContext
->invokeFuncFew(ret
.asTypedValue(), ctx
, 1, &m_data
[i
]);
141 if (UNLIKELY(version
!= m_version
)) {
142 throw_collection_modified();
144 if (ret
.toBoolean()) {
145 bvec
->add(&m_data
[i
]);
150 void BaseVector::filterwithkey(BaseVector
* bvec
, CVarRef callback
) {
152 vm_decode_function(callback
, nullptr, false, ctx
);
154 Object
e(SystemLib::AllocInvalidArgumentExceptionObject(
155 "Parameter must be a valid callback"));
159 for (uint i
= 0; i
< sz
; ++i
) {
161 int32_t version
= m_version
;
162 TypedValue args
[2] = {
163 make_tv
<KindOfInt64
>(i
),
166 g_vmContext
->invokeFuncFew(ret
.asTypedValue(), ctx
, 2, args
);
167 if (UNLIKELY(version
!= m_version
)) {
168 throw_collection_modified();
170 if (ret
.toBoolean()) {
171 bvec
->add(&m_data
[i
]);
176 void BaseVector::zip(BaseVector
* bvec
, CVarRef iterable
) {
178 ArrayIter iter
= getArrayIterHelper(iterable
, itSize
);
180 bvec
->reserve(std::min(itSize
, size_t(sz
)));
181 for (uint i
= 0; i
< sz
&& iter
; ++i
, ++iter
) {
182 Variant v
= iter
.second();
183 if (bvec
->m_capacity
<= bvec
->m_size
) {
186 c_Pair
* pair
= NEWOBJ(c_Pair
)();
188 pair
->initAdd(&m_data
[i
]);
189 pair
->initAdd(cvarToCell(&v
));
190 bvec
->m_data
[i
].m_data
.pobj
= pair
;
191 bvec
->m_data
[i
].m_type
= KindOfObject
;
196 void BaseVector::kvzip(BaseVector
* bvec
) {
197 bvec
->reserve(m_size
);
198 for (uint i
= 0; i
< m_size
; ++i
) {
199 c_Pair
* pair
= NEWOBJ(c_Pair
)();
201 pair
->elm0
.m_type
= KindOfInt64
;
202 pair
->elm0
.m_data
.num
= i
;
204 pair
->initAdd(&m_data
[i
]);
205 bvec
->m_data
[i
].m_data
.pobj
= pair
;
206 bvec
->m_data
[i
].m_type
= KindOfObject
;
211 void BaseVector::keys(BaseVector
* bvec
) {
212 bvec
->reserve(m_size
);
213 bvec
->m_size
= m_size
;
214 for (uint i
= 0; i
< m_size
; ++i
) {
215 bvec
->m_data
[i
].m_data
.num
= i
;
216 bvec
->m_data
[i
].m_type
= KindOfInt64
;
222 void BaseVector::construct(CVarRef iterable
/* = null_variant */) {
223 if (iterable
.isNull()) return;
227 Object
BaseVector::lazy() {
228 return SystemLib::AllocLazyKeyedIterableViewObject(this);
231 Array
BaseVector::toarray() {
232 return toArrayImpl();
235 Array
BaseVector::tokeysarray() {
236 PackedArrayInit
ai(m_size
);
238 for (uint i
= 0; i
< sz
; ++i
) {
239 ai
.append((int64_t)i
);
244 Array
BaseVector::tovaluesarray() {
245 return toArrayImpl();
248 int64_t BaseVector::linearsearch(CVarRef search_value
) {
250 for (uint i
= 0; i
< sz
; ++i
) {
251 if (same(search_value
, tvAsCVarRef(&m_data
[i
]))) {
258 // Non PHP-land methods.
260 bool BaseVector::OffsetIsset(ObjectData
* obj
, TypedValue
* key
) {
261 assert(key
->m_type
!= KindOfRef
);
262 auto vec
= static_cast<BaseVector
*>(obj
);
264 if (key
->m_type
== KindOfInt64
) {
265 result
= vec
->get(key
->m_data
.num
);
270 return result
? !cellIsNull(tvToCell(result
)) : false;
273 bool BaseVector::OffsetEmpty(ObjectData
* obj
, TypedValue
* key
) {
274 assert(key
->m_type
!= KindOfRef
);
275 auto vec
= static_cast<BaseVector
*>(obj
);
277 if (key
->m_type
== KindOfInt64
) {
278 result
= vec
->get(key
->m_data
.num
);
283 return result
? !cellToBool(*result
) : true;
286 bool BaseVector::OffsetContains(ObjectData
* obj
, TypedValue
* key
) {
287 assert(key
->m_type
!= KindOfRef
);
288 auto vec
= static_cast<BaseVector
*>(obj
);
289 if (key
->m_type
== KindOfInt64
) {
290 return vec
->contains(key
->m_data
.num
);
297 TypedValue
* BaseVector::OffsetGet(ObjectData
* obj
, TypedValue
* key
) {
298 assert(key
->m_type
!= KindOfRef
);
299 auto vec
= static_cast<BaseVector
*>(obj
);
300 if (key
->m_type
== KindOfInt64
) {
301 return vec
->at(key
->m_data
.num
);
307 bool BaseVector::Equals(const ObjectData
* obj1
, const ObjectData
* obj2
) {
308 auto bv1
= static_cast<const BaseVector
*>(obj1
);
309 auto bv2
= static_cast<const BaseVector
*>(obj2
);
311 uint sz
= bv1
->m_size
;
312 if (sz
!= bv2
->m_size
) {
316 for (uint i
= 0; i
< sz
; ++i
) {
317 if (!equal(tvAsCVarRef(&bv1
->m_data
[i
]),
318 tvAsCVarRef(&bv2
->m_data
[i
]))) {
327 void BaseVector::Unserialize(const char* vectorType
,
329 VariableUnserializer
* uns
,
333 throw Exception("%s does not support the '%c' serialization "
334 "format", vectorType
, type
);
336 auto bvec
= static_cast<BaseVector
*>(obj
);
338 for (int64_t i
= 0; i
< sz
; ++i
) {
339 auto tv
= &bvec
->m_data
[bvec
->m_size
];
340 tv
->m_type
= KindOfNull
;
342 tvAsVariant(tv
).unserialize(uns
, Uns::Mode::ColValue
);
348 Array
BaseVector::toArrayImpl() const {
349 PackedArrayInit
ai(m_size
);
351 for (uint i
= 0; i
< sz
; ++i
) {
352 ai
.append(tvAsCVarRef(&m_data
[i
]));
357 void BaseVector::grow() {
361 m_capacity
+= m_capacity
;
365 m_data
= (TypedValue
*)smart_realloc(m_data
, m_capacity
* sizeof(TypedValue
));
368 void BaseVector::reserve(int64_t sz
) {
371 if (m_capacity
< sz
) {
377 (TypedValue
*)smart_realloc(m_data
, m_capacity
* sizeof(TypedValue
));
381 BaseVector::BaseVector(Class
* cls
) : ExtObjectData(cls
),
382 m_size(0), m_data(nullptr), m_capacity(0),
383 m_version(0), m_frozenCopy(nullptr) {
387 * Delegate the responsibility for freeing the buffer to the
388 * frozen copy, if it exists.
390 BaseVector::~BaseVector() {
391 if (m_frozenCopy
.isNull() && m_data
) {
392 for (uint i
= 0; i
< m_size
; ++i
) {
393 tvRefcountedDecRef(&m_data
[i
]);
401 void BaseVector::throwBadKeyType() {
402 Object
e(SystemLib::AllocInvalidArgumentExceptionObject(
403 "Only integer keys may be used with Vectors"));
407 void BaseVector::init(CVarRef t
) {
409 ArrayIter iter
= getArrayIterHelper(t
, sz
);
413 for (; iter
; ++iter
) {
414 Variant v
= iter
.second();
415 TypedValue
* tv
= cvarToCell(&v
);
420 void BaseVector::cow() {
421 TypedValue
* newData
=
422 (TypedValue
*)smart_malloc(m_capacity
* sizeof(TypedValue
));
426 for (uint i
= 0; i
< m_size
; i
++) {
427 cellDup(m_data
[i
], newData
[i
]);
431 m_frozenCopy
.reset();
434 ///////////////////////////////////////////////////////////////////////////////