PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/hphp/runtime/base/array/array_data.cpp

https://bitbucket.org/asuhan/happy/
C++ | 374 lines | 273 code | 61 blank | 40 comment | 59 complexity | 7336a9f4d823dd94638289ea99d24a7d MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <runtime/base/array/array_data.h>
  17. #include <runtime/base/array/array_init.h>
  18. #include <runtime/base/array/array_iterator.h>
  19. #include <runtime/base/type_conversions.h>
  20. #include <runtime/base/builtin_functions.h>
  21. #include <runtime/base/complex_types.h>
  22. #include <util/exception.h>
  23. using namespace std;
  24. namespace HPHP {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // constructors/destructors
  27. ArrayData *ArrayData::Create() {
  28. return ArrayInit((ssize_t)0).create();
  29. }
  30. ArrayData *ArrayData::Create(CVarRef value) {
  31. ArrayInit init(1);
  32. init.set(value);
  33. return init.create();
  34. }
  35. ArrayData *ArrayData::Create(CVarRef name, CVarRef value) {
  36. ArrayInit init(1);
  37. // There is no toKey() call on name.
  38. init.set(name, value, true);
  39. return init.create();
  40. }
  41. ArrayData *ArrayData::CreateRef(CVarRef value) {
  42. ArrayInit init(1);
  43. init.setRef(value);
  44. return init.create();
  45. }
  46. ArrayData *ArrayData::CreateRef(CVarRef name, CVarRef value) {
  47. ArrayInit init(1);
  48. // There is no toKey() call on name.
  49. init.setRef(name, value, true);
  50. return init.create();
  51. }
  52. ArrayData::~ArrayData() {
  53. // If there are any strong iterators pointing to this array, they need
  54. // to be invalidated.
  55. if (!m_strongIterators.empty()) {
  56. freeStrongIterators();
  57. }
  58. }
  59. ArrayData *ArrayData::nonSmartCopy() const {
  60. throw FatalErrorException("nonSmartCopy not implemented.");
  61. }
  62. ///////////////////////////////////////////////////////////////////////////////
  63. // reads
  64. bool ArrayData::isVectorData() const {
  65. for (ssize_t i = 0; i < size(); i++) {
  66. if (getIndex(i) != i) {
  67. return false;
  68. }
  69. }
  70. return true;
  71. }
  72. bool ArrayData::isGlobalArrayWrapper() const {
  73. return false;
  74. }
  75. int ArrayData::compare(const ArrayData *v2) const {
  76. ASSERT(v2);
  77. int count1 = size();
  78. int count2 = v2->size();
  79. if (count1 < count2) return -1;
  80. if (count1 > count2) return 1;
  81. if (count1 == 0) return 0;
  82. for (ArrayIter iter(this); iter; ++iter) {
  83. Variant key(iter.first());
  84. if (!v2->exists(key)) return 1;
  85. Variant value1(iter.second());
  86. Variant value2(v2->get(key));
  87. if (value1.more(value2)) return 1;
  88. if (value1.less(value2)) return -1;
  89. }
  90. return 0;
  91. }
  92. bool ArrayData::equal(const ArrayData *v2, bool strict) const {
  93. ASSERT(v2);
  94. int count1 = size();
  95. int count2 = v2->size();
  96. if (count1 != count2) return false;
  97. if (count1 == 0) return true;
  98. if (strict) {
  99. for (ArrayIter iter1(this), iter2(v2); iter1 && iter2; ++iter1, ++iter2) {
  100. Variant key1(iter1.first());
  101. Variant key2(iter2.first());
  102. if (!key1.same(key2)) return false;
  103. Variant value1(iter1.second());
  104. Variant value2(iter2.second());
  105. if (!value1.same(value2)) return false;
  106. }
  107. } else {
  108. for (ArrayIter iter(this); iter; ++iter) {
  109. Variant key(iter.first());
  110. if (!v2->exists(key)) return false;
  111. Variant value1(iter.second());
  112. Variant value2(v2->get(key));
  113. if (!value1.equal(value2)) return false;
  114. }
  115. }
  116. return true;
  117. }
  118. void ArrayData::load(CVarRef k, Variant &v) const {
  119. if (exists(k)) v = get(k);
  120. }
  121. ArrayData *ArrayData::lvalPtr(CStrRef k, Variant *&ret, bool copy,
  122. bool create) {
  123. throw FatalErrorException("Unimplemented ArrayData::lvalPtr");
  124. }
  125. ArrayData *ArrayData::lvalPtr(int64 k, Variant *&ret, bool copy,
  126. bool create) {
  127. throw FatalErrorException("Unimplemented ArrayData::lvalPtr");
  128. }
  129. ArrayData *ArrayData::add(int64 k, CVarRef v, bool copy) {
  130. ASSERT(!exists(k));
  131. return set(k, v, copy);
  132. }
  133. ArrayData *ArrayData::add(CStrRef k, CVarRef v, bool copy) {
  134. ASSERT(!exists(k));
  135. return set(k, v, copy);
  136. }
  137. ArrayData *ArrayData::add(CVarRef k, CVarRef v, bool copy) {
  138. ASSERT(!exists(k));
  139. return set(k, v, copy);
  140. }
  141. ArrayData *ArrayData::addLval(int64 k, Variant *&ret, bool copy) {
  142. ASSERT(!exists(k));
  143. return lval(k, ret, copy);
  144. }
  145. ArrayData *ArrayData::addLval(CStrRef k, Variant *&ret, bool copy) {
  146. ASSERT(!exists(k));
  147. return lval(k, ret, copy);
  148. }
  149. ArrayData *ArrayData::addLval(CVarRef k, Variant *&ret, bool copy) {
  150. ASSERT(!exists(k));
  151. return lval(k, ret, copy);
  152. }
  153. ArrayData *ArrayData::set(litstr k, CVarRef v, bool copy) {
  154. return set(String(k), v, copy);
  155. }
  156. ArrayData *ArrayData::setRef(litstr k, CVarRef v, bool copy) {
  157. return setRef(String(k), v, copy);
  158. }
  159. ArrayData *ArrayData::remove(litstr k, bool copy) {
  160. return remove(String(k), copy);
  161. }
  162. ///////////////////////////////////////////////////////////////////////////////
  163. // stack and queue operations
  164. ArrayData *ArrayData::pop(Variant &value) {
  165. if (!empty()) {
  166. ssize_t pos = iter_end();
  167. value = getValue(pos);
  168. return remove(getKey(pos), getCount() > 1);
  169. }
  170. value = null;
  171. return NULL;
  172. }
  173. ArrayData *ArrayData::dequeue(Variant &value) {
  174. if (!empty()) {
  175. ssize_t pos = iter_begin();
  176. value = getValue(pos);
  177. ArrayData *ret = remove(getKey(pos), getCount() > 1);
  178. // In PHP, array_shift() will cause all numerically key-ed values re-keyed
  179. if (ret) {
  180. ret->renumber();
  181. } else {
  182. renumber();
  183. }
  184. return ret;
  185. }
  186. value = null;
  187. return NULL;
  188. }
  189. ///////////////////////////////////////////////////////////////////////////////
  190. // MutableArrayIter related functions
  191. void ArrayData::newFullPos(FullPos &fp) {
  192. ASSERT(fp.container == NULL);
  193. m_strongIterators.push(&fp);
  194. fp.container = (ArrayData*)this;
  195. getFullPos(fp);
  196. }
  197. void ArrayData::freeFullPos(FullPos &fp) {
  198. ASSERT(fp.container == (ArrayData*)this);
  199. int sz = m_strongIterators.size();
  200. if (sz > 0) {
  201. // Common case: fp is at the end of the list
  202. if (m_strongIterators.get(sz - 1) == &fp) {
  203. m_strongIterators.pop();
  204. fp.container = NULL;
  205. return;
  206. }
  207. // Unusual case: somehow the strong iterator for an foreach loop
  208. // was freed before a strong iterator from a nested foreach loop,
  209. // so do a linear search for fp
  210. for (int k = sz - 2; k >= 0; --k) {
  211. if (m_strongIterators.get(k) == &fp) {
  212. // Swap fp with the last element in the list and then pop
  213. m_strongIterators.set(k, m_strongIterators.get(sz - 1));
  214. m_strongIterators.pop();
  215. fp.container = NULL;
  216. return;
  217. }
  218. }
  219. }
  220. // If the strong iterator list was empty or if fp could not be
  221. // found in the strong iterator list, then we are in a bad state
  222. ASSERT(false);
  223. }
  224. void ArrayData::getFullPos(FullPos &fp) {
  225. ASSERT(fp.container == (ArrayData*)this);
  226. fp.pos = ArrayData::invalid_index;
  227. }
  228. bool ArrayData::setFullPos(const FullPos &fp) {
  229. ASSERT(fp.container == (ArrayData*)this);
  230. return false;
  231. }
  232. void ArrayData::freeStrongIterators() {
  233. int sz = m_strongIterators.size();
  234. for (int i = 0; i < sz; ++i) {
  235. m_strongIterators.get(i)->container = NULL;
  236. }
  237. m_strongIterators.clear();
  238. }
  239. CVarRef ArrayData::currentRef() {
  240. if (m_pos >= 0 && m_pos < size()) {
  241. return getValueRef(m_pos);
  242. }
  243. throw FatalErrorException("invalid ArrayData::m_pos");
  244. }
  245. CVarRef ArrayData::endRef() {
  246. if (m_pos >= 0 && m_pos < size()) {
  247. return getValueRef(size() - 1);
  248. }
  249. throw FatalErrorException("invalid ArrayData::m_pos");
  250. }
  251. ///////////////////////////////////////////////////////////////////////////////
  252. // Default implementation of position-based iterations.
  253. Variant ArrayData::reset() { return value(m_pos = 0);}
  254. Variant ArrayData::prev() { return value(--m_pos);}
  255. Variant ArrayData::next() { return value(++m_pos);}
  256. Variant ArrayData::end() { return value(m_pos = size() - 1);}
  257. Variant ArrayData::key() const {
  258. if (m_pos >= 0 && m_pos < size()) {
  259. return getKey(m_pos);
  260. }
  261. return null;
  262. }
  263. Variant ArrayData::value(ssize_t &pos) const {
  264. if (pos >= 0 && pos < size()) {
  265. return getValue(pos);
  266. }
  267. pos = ArrayData::invalid_index;
  268. return false;
  269. }
  270. Variant ArrayData::current() const {
  271. if (m_pos >= 0 && m_pos < size()) {
  272. return getValue(m_pos);
  273. }
  274. return false;
  275. }
  276. Variant ArrayData::each() {
  277. if (m_pos >= 0 && m_pos < size()) {
  278. Array ret;
  279. Variant key(getKey(m_pos));
  280. Variant value(getValue(m_pos));
  281. ret.set(1, value);
  282. ret.set("value", value);
  283. ret.set(0, key);
  284. ret.set("key", key);
  285. ++m_pos;
  286. return ret;
  287. }
  288. return false;
  289. }
  290. ssize_t ArrayData::iter_begin() const {
  291. if (empty()) return ArrayData::invalid_index;
  292. return 0;
  293. }
  294. ssize_t ArrayData::iter_end() const {
  295. if (empty()) return ArrayData::invalid_index;
  296. return size() - 1;
  297. }
  298. ssize_t ArrayData::iter_advance(ssize_t prev) const {
  299. ASSERT(prev >= 0 && prev < size());
  300. ssize_t next = prev + 1;
  301. if (next >= size()) return ArrayData::invalid_index;
  302. return next;
  303. }
  304. ssize_t ArrayData::iter_rewind(ssize_t prev) const {
  305. ASSERT(prev >= 0 && prev < size());
  306. ssize_t next = prev - 1;
  307. if (next < 0) return ArrayData::invalid_index;
  308. return next;
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. // helpers
  312. ///////////////////////////////////////////////////////////////////////////////
  313. }