EvalEmitDVArray: varray
[hiphop-php.git] / hphp / runtime / base / type-string.cpp
blob4d9de460462b92e8d6c9d8cf6eeb760767e6d5d0
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/base/type-string.h"
19 #include "hphp/runtime/base/builtin-functions.h"
20 #include "hphp/runtime/base/comparisons.h"
21 #include "hphp/runtime/base/init-fini-node.h"
22 #include "hphp/runtime/base/zend-functions.h"
23 #include "hphp/runtime/base/zend-string.h"
24 #include "hphp/runtime/base/zend-printf.h"
25 #include "hphp/util/conv-10.h"
27 #include <folly/tracing/StaticTracepoint.h>
29 #include <algorithm>
31 namespace HPHP {
33 const String null_string = String();
34 const StaticString empty_string_ref("");
36 ///////////////////////////////////////////////////////////////////////////////
37 // statics
39 #define NUM_CONVERTED_INTEGERS \
40 (String::MaxPrecomputedInteger - String::MinPrecomputedInteger + 1)
42 StringData const **String::converted_integers_raw;
43 StringData const **String::converted_integers;
45 static const StringData* convert_integer_helper(int64_t n) {
46 char tmpbuf[21];
47 tmpbuf[20] = '\0';
48 auto sl = conv_10(n, &tmpbuf[20]);
49 return makeStaticString(sl);
52 const StringData *String::ConvertInteger(int64_t n) {
53 StringData const **psd = converted_integers + n;
54 const StringData *sd = convert_integer_helper(n);
55 *psd = sd;
56 return sd;
59 static int precompute_integers();
60 static int precompute_integers() {
61 String::converted_integers_raw =
62 (StringData const **)calloc(NUM_CONVERTED_INTEGERS, sizeof(StringData*));
63 String::converted_integers = String::converted_integers_raw
64 - String::MinPrecomputedInteger;
65 return NUM_CONVERTED_INTEGERS;
68 static int ATTRIBUTE_UNUSED initIntegers = precompute_integers();
69 static InitFiniNode prepopulate_integers([] {
70 // Proactively populate, in order to increase cache locality for sequential
71 // access patterns.
72 for (int n = String::MinPrecomputedInteger;
73 n <= String::MaxPrecomputedInteger; n++) {
74 String::ConvertInteger(n);
76 }, InitFiniNode::When::PostRuntimeOptions);
78 ///////////////////////////////////////////////////////////////////////////////
79 // constructors
81 String::~String() {}
83 StringData* buildStringData(int n) {
84 return buildStringData(static_cast<int64_t>(n));
87 StringData* buildStringData(int64_t n) {
88 if (auto const sd = String::GetIntegerStringData(n)) {
89 assertx(sd->isStatic());
90 return const_cast<StringData*>(sd);
93 char tmpbuf[21];
94 tmpbuf[20] = '\0';
95 auto const sl = conv_10(n, &tmpbuf[20]);
96 return StringData::Make(sl, CopyString);
99 String::String(int n) : String(static_cast<int64_t>(n)) {}
100 String::String(int64_t n) : m_str(buildStringData(n), NoIncRef{}) {}
102 void formatPhpDblStr(char **pbuf, double n) {
103 if (n == 0.0) {
104 n = 0.0; // so to avoid "-0" output
106 vspprintf(pbuf, 0, "%.*G", 14, n);
109 StringData* buildStringData(double n) {
110 char *buf = nullptr;
111 formatPhpDblStr(&buf, n);
112 return StringData::Make(buf, AttachString);
115 std::string convDblToStrWithPhpFormat(double n) {
116 char *buf = nullptr;
117 formatPhpDblStr(&buf, n);
118 std::string retVal(buf);
119 free(buf);
120 return retVal;
123 String::String(double n) : m_str(buildStringData(n), NoIncRef{}) { }
125 ///////////////////////////////////////////////////////////////////////////////
126 // informational
128 int String::find(char ch, int pos /* = 0 */,
129 bool caseSensitive /* = true */) const {
130 if (empty()) return -1;
131 return string_find(m_str->data(), m_str->size(), ch, pos,
132 caseSensitive);
135 int String::find(const char *s, int pos /* = 0 */,
136 bool caseSensitive /* = true */) const {
137 assertx(s);
138 if (empty()) return -1;
139 if (*s && *(s+1) == 0) {
140 return find(*s, pos, caseSensitive);
142 return string_find(m_str->data(), m_str->size(), s, strlen(s),
143 pos, caseSensitive);
146 int String::find(const String& s, int pos /* = 0 */,
147 bool caseSensitive /* = true */) const {
148 if (empty()) return -1;
149 if (s.size() == 1) {
150 return find(*s.data(), pos, caseSensitive);
152 return string_find(m_str->data(), m_str->size(),
153 s.data(), s.size(), pos, caseSensitive);
156 int String::rfind(char ch, int pos /* = 0 */,
157 bool caseSensitive /* = true */) const {
158 if (empty()) return -1;
159 return string_rfind(m_str->data(), m_str->size(), ch,
160 pos, caseSensitive);
163 int String::rfind(const char *s, int pos /* = 0 */,
164 bool caseSensitive /* = true */) const {
165 assertx(s);
166 if (empty()) return -1;
167 if (*s && *(s+1) == 0) {
168 return rfind(*s, pos, caseSensitive);
170 return string_rfind(m_str->data(), m_str->size(), s, strlen(s),
171 pos, caseSensitive);
174 int String::rfind(const String& s, int pos /* = 0 */,
175 bool caseSensitive /* = true */) const {
176 if (empty()) return -1;
177 if (s.size() == 1) {
178 return rfind(*s.data(), pos, caseSensitive);
180 return string_rfind(m_str->data(), m_str->size(),
181 s.data(), s.size(), pos, caseSensitive);
184 ///////////////////////////////////////////////////////////////////////////////
185 // offset functions: cannot inline these due to dependencies
187 char String::charAt(int pos) const {
188 assertx(pos >= 0 && pos <= size());
189 const char *s = data();
190 return s[pos];
193 ///////////////////////////////////////////////////////////////////////////////
194 // assignments
196 String& String::operator=(const char* s) {
197 m_str = req::ptr<StringData>::attach(
198 s ? StringData::Make(s, CopyString) : nullptr);
199 return *this;
202 String& String::operator=(const std::string& s) {
203 m_str = req::ptr<StringData>::attach(
204 StringData::Make(s.c_str(), s.size(), CopyString));
205 return *this;
208 ///////////////////////////////////////////////////////////////////////////////
209 // concatenation and increments
211 String& String::operator+=(const char* s) {
212 if (!s) return *this;
213 return operator+=(folly::StringPiece{s, strlen(s)});
216 String& String::operator+=(const std::string& str) {
217 return operator+=(folly::StringPiece{str});
220 String& String::operator+=(const String& str) {
221 if (str.empty()) return *this;
222 if (empty()) {
223 // lhs is empty, just return str. No attempt to append in place even
224 // if lhs is private & reserved.
225 m_str = str.m_str;
226 return *this;
228 return operator+=(str.slice());
231 String& String::operator+=(folly::StringPiece slice) {
232 if (slice.empty()) {
233 return *this;
235 if (!m_str) {
236 m_str = req::ptr<StringData>::attach(
237 StringData::Make(slice.begin(), slice.size(), CopyString));
238 return *this;
240 if (!m_str->cowCheck()) {
241 UNUSED auto const lsize = m_str->size();
242 FOLLY_SDT(hhvm, hhvm_mut_concat, lsize, slice.size());
243 auto const tmp = m_str->append(slice);
244 if (UNLIKELY(tmp != m_str)) {
245 // had to realloc even though count==1
246 m_str = req::ptr<StringData>::attach(tmp);
248 return *this;
250 FOLLY_SDT(hhvm, hhvm_cow_concat, m_str->size(), slice.size());
251 m_str = req::ptr<StringData>::attach(
252 StringData::Make(m_str.get(), slice)
254 return *this;
257 String& String::operator+=(folly::MutableStringPiece slice) {
258 return operator+=(folly::StringPiece{slice.begin(), slice.size()});
261 String&& operator+(String&& lhs, const char* rhs) {
262 lhs += rhs;
263 return std::move(lhs);
266 String operator+(const String & lhs, const char* rhs) {
267 if (lhs.empty()) return rhs;
268 if (!rhs || !*rhs) return lhs;
269 return String::attach(StringData::Make(lhs.slice(), rhs));
272 String&& operator+(String&& lhs, String&& rhs) {
273 return std::move(lhs += rhs);
276 String operator+(String&& lhs, const String & rhs) {
277 return std::move(lhs += rhs);
280 String operator+(const String & lhs, const String & rhs) {
281 if (lhs.empty()) return rhs;
282 if (rhs.empty()) return lhs;
283 return String::attach(StringData::Make(lhs.slice(), rhs.slice()));
286 ///////////////////////////////////////////////////////////////////////////////
287 // comparisons
289 bool String::same(const StringData *v2) const {
290 return HPHP::same(get(), v2);
293 bool String::same(const String& v2) const {
294 return HPHP::same(get(), v2);
297 bool String::equal(const StringData *v2) const {
298 return HPHP::equal(get(), v2);
301 bool String::equal(const String& v2) const {
302 return HPHP::equal(get(), v2);
305 bool String::less(const StringData *v2) const {
306 return HPHP::less(get(), v2);
309 bool String::less(const String& v2) const {
310 return HPHP::less(get(), v2);
313 bool String::more(const StringData *v2) const {
314 return HPHP::more(get(), v2);
317 bool String::more(const String& v2) const {
318 return HPHP::more(get(), v2);
321 int String::compare(const char* v2) const {
322 int lengthDiff = length() - strlen(v2);
323 if(lengthDiff == 0)
324 return memcmp(data(), v2, length());
325 else
326 return lengthDiff;
329 int String::compare(const String& v2) const {
330 int lengthDiff = length() - v2.length();
331 if(lengthDiff == 0)
332 return memcmp(data(), v2.data(), length());
333 else
334 return lengthDiff;
337 ///////////////////////////////////////////////////////////////////////////////
338 // comparison operators
340 bool String::operator==(const String& v) const {
341 return HPHP::equal(get(), v);
344 bool String::operator!=(const String& v) const {
345 return !HPHP::equal(get(), v);
348 bool String::operator>(const String& v) const {
349 return HPHP::more(get(), v);
352 bool String::operator<(const String& v) const {
353 return HPHP::less(get(), v);
356 ///////////////////////////////////////////////////////////////////////////////
357 // debugging
359 void String::dump() const {
360 if (m_str) {
361 m_str->dump();
362 } else {
363 printf("(null)\n");
367 ///////////////////////////////////////////////////////////////////////////////
368 // StaticString
370 void StaticString::construct(const char* s, size_t len) {
371 m_str = makeStaticStringSafe(s, len);
374 const StaticString
375 s_null("null"),
376 s_boolean("boolean"),
377 s_integer("integer"),
378 s_double("double"),
379 s_string("string"),
380 s_varray("varray"),
381 s_darray("darray"),
382 s_array("array"),
383 s_vec("vec"),
384 s_dict("dict"),
385 s_keyset("keyset"),
386 s_object("object"),
387 s_resource("resource"),
388 s_func("function"),
389 s_class("class"),
390 s_clsmeth("clsmeth"),
391 s_record("record");
393 StaticString getDataTypeString(DataType t) {
394 switch (t) {
395 case KindOfUninit:
396 case KindOfNull: return s_null;
397 case KindOfBoolean: return s_boolean;
398 case KindOfInt64: return s_integer;
399 case KindOfDouble: return s_double;
400 case KindOfPersistentString:
401 case KindOfString: return s_string;
402 case KindOfPersistentVec:
403 case KindOfVec: return s_vec;
404 case KindOfPersistentDict:
405 case KindOfDict: return s_dict;
406 case KindOfPersistentKeyset:
407 case KindOfKeyset: return s_keyset;
408 case KindOfPersistentDArray:
409 case KindOfDArray: return s_darray;
410 case KindOfPersistentVArray:
411 case KindOfVArray:
412 return UNLIKELY(RuntimeOption::EvalSpecializeDVArray)
413 ? s_varray : s_array;
414 case KindOfPersistentArray:
415 case KindOfArray: return s_array;
416 case KindOfObject: return s_object;
417 case KindOfResource: return s_resource;
418 case KindOfFunc: return s_func;
419 case KindOfClass: return s_class;
420 case KindOfClsMeth: return s_clsmeth;
421 case KindOfRecord: return s_record;
423 not_reached();
426 //////////////////////////////////////////////////////////////////////////////