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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_RUNTIME_BASE_STRING_DATA_INL_H_
17 #define incl_HPHP_RUNTIME_BASE_STRING_DATA_INL_H_
21 //////////////////////////////////////////////////////////////////////
24 inline StringData
* StringData::Make(folly::StringPiece s
) {
25 return Make(s
.begin(), s
.size(), CopyString
);
28 inline StringData
* StringData::Make(const char* data
, CopyStringMode
) {
29 return Make(data
, strlen(data
), CopyString
);
32 //////////////////////////////////////////////////////////////////////
35 inline StringData
* StringData::Make(char* data
, AttachStringMode
) {
36 SCOPE_EXIT
{ free(data
); };
37 return Make(data
, CopyString
);
40 //////////////////////////////////////////////////////////////////////
43 inline StringData
* StringData::Make(const StringData
* s1
,
44 folly::StringPiece s2
) {
45 return Make(s1
->slice(), s2
);
48 inline StringData
* StringData::Make(const StringData
* s1
, const char* lit2
) {
49 return Make(s1
->slice(), lit2
);
52 //////////////////////////////////////////////////////////////////////
54 inline folly::StringPiece
StringData::slice() const {
55 return folly::StringPiece
{data(), m_len
};
58 inline folly::MutableStringPiece
StringData::bufferSlice() {
59 assert(!isImmutable());
60 return folly::MutableStringPiece
{mutableData(), capacity()};
63 inline void StringData::invalidateHash() {
64 assert(!isImmutable());
65 assert(!hasMultipleRefs());
70 inline void StringData::setSize(int len
) {
71 assert(!isImmutable() && !hasMultipleRefs());
72 assert(len
>= 0 && len
<= capacity());
73 mutableData()[len
] = 0;
79 inline void StringData::checkStack() const {
80 assert(uintptr_t(this) - s_stackLimit
>= s_stackSize
);
83 inline const char* StringData::data() const {
84 // TODO: t1800106: re-enable this assert
85 // assert(data()[size()] == 0); // all strings must be null-terminated
87 return reinterpret_cast<const char*>(this + 1);
93 inline char* StringData::mutableData() const {
94 assert(!isImmutable());
95 return const_cast<char*>(data());
98 inline int StringData::size() const { return m_len
; }
99 inline bool StringData::empty() const { return size() == 0; }
100 inline uint32_t StringData::capacity() const {
101 return kSizeIndex2StringCapacity
[m_aux16
];
104 inline size_t StringData::heapSize() const {
107 ? MemoryManager::sizeIndex2Size(m_aux16
)
108 : size() + kStringOverhead
109 : sizeof(StringData
) + sizeof(Proxy
);
112 inline size_t StringData::estimateCap(size_t size
) {
113 assert(size
<= MaxSize
);
114 return MemoryManager::sizeClass(size
+ kStringOverhead
);
117 inline bool StringData::isStrictlyInteger(int64_t& res
) const {
118 // Exploit the NUL terminator and unsigned comparison. This single comparison
119 // checks whether the string is empty or if the first byte is greater than '9'
120 // or less than '-'. Note that '-' == 45 and '0' == 48, which makes this
121 // valid. (46 == '.' and 47 == '/', so if one of those is the first byte, this
122 // check will be a false positive, but it will still be caught later.)
123 if ((unsigned char)(data()[0] - '-') > ('9' - '-')) {
126 if (m_hash
< 0) return false;
127 auto const s
= slice();
128 return is_strictly_integer(s
.data(), s
.size(), res
);
131 inline bool StringData::isZero() const {
132 return size() == 1 && data()[0] == '0';
135 inline StringData
* StringData::modifyChar(int offset
, char c
) {
136 assert(offset
>= 0 && offset
< size());
137 assert(!hasMultipleRefs());
139 auto const sd
= isProxy() ? escalate(size()) : this;
140 sd
->mutableData()[offset
] = c
;
145 inline strhash_t
StringData::hash_unsafe(const char* s
, size_t len
) {
146 return hash_string_i_unsafe(s
, len
);
149 inline strhash_t
StringData::hash(const char* s
, size_t len
) {
150 return hash_string_i(s
, len
);
153 inline strhash_t
StringData::hash() const {
154 strhash_t h
= m_hash
& STRHASH_MASK
;
155 return h
? h
: hashHelper();
158 inline bool StringData::same(const StringData
* s
) const {
160 if (m_len
!= s
->m_len
) return false;
161 // The underlying buffer and its length are 8-byte aligned, ensured by
162 // StringData layout, req::malloc, or malloc. So compare words.
163 assert(uintptr_t(data()) % 8 == 0);
164 assert(uintptr_t(s
->data()) % 8 == 0);
165 return wordsame(data(), s
->data(), m_len
);
168 inline bool StringData::isame(const StringData
* s
) const {
170 if (m_len
!= s
->m_len
) return false;
171 return bstrcaseeq(data(), s
->data(), m_len
);
174 //////////////////////////////////////////////////////////////////////
176 inline const void* StringData::payload() const { return this + 1; }
177 inline void* StringData::payload() { return this + 1; }
179 inline const StringData::Proxy
* StringData::proxy() const {
180 return static_cast<const Proxy
*>(payload());
182 inline StringData::Proxy
* StringData::proxy() {
183 return static_cast<Proxy
*>(payload());
187 inline bool StringData::isFlat() const { return m_data
== payload(); }
188 inline bool StringData::isProxy() const { return m_data
!= payload(); }
191 inline bool StringData::isImmutable() const {
192 return !isRefCounted() || isProxy();
195 //////////////////////////////////////////////////////////////////////
197 ALWAYS_INLINE
void decRefStr(StringData
* s
) {
198 s
->decRefAndRelease();
201 struct string_data_hash
{
202 size_t operator()(const StringData
*s
) const {
207 struct string_data_same
{
208 bool operator()(const StringData
*s1
, const StringData
*s2
) const {
214 struct string_data_eq_same
{
215 bool operator()(const StringData
* a
, const StringData
* b
) const {
216 return a
== b
|| a
->same(b
);
220 struct string_data_isame
{
221 bool operator()(const StringData
*s1
, const StringData
*s2
) const {
223 return s1
->isame(s2
);
227 struct string_data_lt
{
228 bool operator()(const StringData
*s1
, const StringData
*s2
) const {
229 int len1
= s1
->size();
230 int len2
= s2
->size();
232 return (len1
== 0) || (memcmp(s1
->data(), s2
->data(), len1
) <= 0);
233 } else if (len1
== len2
) {
234 return (len1
!= 0) && (memcmp(s1
->data(), s2
->data(), len1
) < 0);
235 } else /* len1 > len2 */ {
236 return ((len2
!= 0) && (memcmp(s1
->data(), s2
->data(), len2
) < 0));
241 struct string_data_lti
{
242 bool operator()(const StringData
*s1
, const StringData
*s2
) const {
243 return bstrcasecmp(s1
->data(), s1
->size(), s2
->data(), s2
->size()) < 0;
247 //////////////////////////////////////////////////////////////////////