Add sub-controls for Hack array compat runtime checks
[hiphop-php.git] / hphp / runtime / base / string-data-inl.h
blob7108b453adf15515c87e9a207feee89010d29159
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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_RUNTIME_BASE_STRING_DATA_INL_H_
17 #define incl_HPHP_RUNTIME_BASE_STRING_DATA_INL_H_
19 namespace HPHP {
21 //////////////////////////////////////////////////////////////////////
22 // CopyString
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 //////////////////////////////////////////////////////////////////////
33 // AttachString
35 inline StringData* StringData::Make(char* data, AttachStringMode) {
36 SCOPE_EXIT { free(data); };
37 return Make(data, CopyString);
40 //////////////////////////////////////////////////////////////////////
41 // Concat creation
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());
66 m_hash = 0;
67 assert(checkSane());
70 inline void StringData::setSize(int len) {
71 assert(!isImmutable() && !hasMultipleRefs());
72 assert(len >= 0 && len <= capacity());
73 mutableData()[len] = 0;
74 m_lenAndHash = len;
75 assert(m_hash == 0);
76 assert(checkSane());
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
86 #ifdef NO_M_DATA
87 return reinterpret_cast<const char*>(this + 1);
88 #else
89 return m_data;
90 #endif
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 {
105 return isFlat()
106 ? isRefCounted()
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' - '-')) {
124 return false;
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;
141 sd->m_hash = 0;
142 return sd;
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 {
159 assert(s);
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 {
169 assert(s);
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());
186 #ifndef NO_M_DATA
187 inline bool StringData::isFlat() const { return m_data == payload(); }
188 inline bool StringData::isProxy() const { return m_data != payload(); }
189 #endif
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 {
203 return s->hash();
207 struct string_data_same {
208 bool operator()(const StringData *s1, const StringData *s2) const {
209 assert(s1 && s2);
210 return s1->same(s2);
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 {
222 assert(s1 && s2);
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();
231 if (len1 < len2) {
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 //////////////////////////////////////////////////////////////////////
251 #endif