2 +----------------------------------------------------------------------+
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>
33 const String null_string
= String();
34 const StaticString
empty_string_ref("");
36 ///////////////////////////////////////////////////////////////////////////////
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
) {
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
);
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
72 for (int n
= String::MinPrecomputedInteger
;
73 n
<= String::MaxPrecomputedInteger
; n
++) {
74 String::ConvertInteger(n
);
76 }, InitFiniNode::When::PostRuntimeOptions
);
78 ///////////////////////////////////////////////////////////////////////////////
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
);
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
) {
104 n
= 0.0; // so to avoid "-0" output
106 vspprintf(pbuf
, 0, "%.*G", 14, n
);
109 StringData
* buildStringData(double n
) {
111 formatPhpDblStr(&buf
, n
);
112 return StringData::Make(buf
, AttachString
);
115 std::string
convDblToStrWithPhpFormat(double n
) {
117 formatPhpDblStr(&buf
, n
);
118 std::string
retVal(buf
);
123 String::String(double n
) : m_str(buildStringData(n
), NoIncRef
{}) { }
125 ///////////////////////////////////////////////////////////////////////////////
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
,
135 int String::find(const char *s
, int pos
/* = 0 */,
136 bool caseSensitive
/* = true */) const {
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
),
146 int String::find(const String
& s
, int pos
/* = 0 */,
147 bool caseSensitive
/* = true */) const {
148 if (empty()) return -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
,
163 int String::rfind(const char *s
, int pos
/* = 0 */,
164 bool caseSensitive
/* = true */) const {
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
),
174 int String::rfind(const String
& s
, int pos
/* = 0 */,
175 bool caseSensitive
/* = true */) const {
176 if (empty()) return -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();
193 ///////////////////////////////////////////////////////////////////////////////
196 String
& String::operator=(const char* s
) {
197 m_str
= req::ptr
<StringData
>::attach(
198 s
? StringData::Make(s
, CopyString
) : nullptr);
202 String
& String::operator=(const std::string
& s
) {
203 m_str
= req::ptr
<StringData
>::attach(
204 StringData::Make(s
.c_str(), s
.size(), CopyString
));
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;
223 // lhs is empty, just return str. No attempt to append in place even
224 // if lhs is private & reserved.
228 return operator+=(str
.slice());
231 String
& String::operator+=(folly::StringPiece slice
) {
236 m_str
= req::ptr
<StringData
>::attach(
237 StringData::Make(slice
.begin(), slice
.size(), CopyString
));
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
);
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
)
257 String
& String::operator+=(folly::MutableStringPiece slice
) {
258 return operator+=(folly::StringPiece
{slice
.begin(), slice
.size()});
261 String
&& operator+(String
&& lhs
, const char* 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 ///////////////////////////////////////////////////////////////////////////////
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
);
324 return memcmp(data(), v2
, length());
329 int String::compare(const String
& v2
) const {
330 int lengthDiff
= length() - v2
.length();
332 return memcmp(data(), v2
.data(), length());
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 ///////////////////////////////////////////////////////////////////////////////
359 void String::dump() const {
367 ///////////////////////////////////////////////////////////////////////////////
370 void StaticString::construct(const char* s
, size_t len
) {
371 m_str
= makeStaticStringSafe(s
, len
);
376 s_boolean("boolean"),
377 s_integer("integer"),
385 s_resource("resource"),
388 s_clsmeth("clsmeth"),
391 StaticString
getDataTypeString(DataType t
) {
394 case KindOfNull
: return s_null
;
395 case KindOfBoolean
: return s_boolean
;
396 case KindOfInt64
: return s_integer
;
397 case KindOfDouble
: return s_double
;
398 case KindOfPersistentString
:
399 case KindOfString
: return s_string
;
400 case KindOfPersistentVec
:
401 case KindOfVec
: return s_vec
;
402 case KindOfPersistentDict
:
403 case KindOfDict
: return s_dict
;
404 case KindOfPersistentKeyset
:
405 case KindOfKeyset
: return s_keyset
;
406 case KindOfPersistentArray
:
407 case KindOfArray
: return s_array
;
408 case KindOfObject
: return s_object
;
409 case KindOfResource
: return s_resource
;
410 case KindOfFunc
: return s_func
;
411 case KindOfClass
: return s_class
;
412 case KindOfClsMeth
: return s_clsmeth
;
413 case KindOfRecord
: return s_record
;
418 //////////////////////////////////////////////////////////////////////////////