initial import
[vuplus_webkit] / Source / JavaScriptCore / wtf / text / StringBuilder.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "StringBuilder.h"
28
29 #include "WTFString.h"
30
31 namespace WTF {
32
33 static const unsigned minimumCapacity = 16;
34
35 void StringBuilder::reifyString()
36 {
37     // Check if the string already exists.
38     if (!m_string.isNull()) {
39         ASSERT(m_string.length() == m_length);
40         return;
41     }
42
43     // Check for empty.
44     if (!m_length) {
45         m_string = StringImpl::empty();
46         return;
47     }
48
49     // Must be valid in the buffer, take a substring (unless string fills the buffer).
50     ASSERT(m_buffer && m_length <= m_buffer->length());
51     m_string = (m_length == m_buffer->length())
52         ? m_buffer.get()
53         : StringImpl::create(m_buffer, 0, m_length);
54 }
55
56 void StringBuilder::resize(unsigned newSize)
57 {
58     // Check newSize < m_length, hence m_length > 0.
59     ASSERT(newSize <= m_length);
60     if (newSize == m_length)
61         return;
62     ASSERT(m_length);
63
64     // If there is a buffer, we only need to duplicate it if it has more than one ref.
65     if (m_buffer) {
66         if (!m_buffer->hasOneRef())
67             allocateBuffer(m_buffer->characters(), m_buffer->length());
68         m_length = newSize;
69         m_string = String();
70         return;
71     }
72
73     // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
74     ASSERT(!m_string.isEmpty());
75     ASSERT(m_length == m_string.length());
76     ASSERT(newSize < m_string.length());
77     m_length = newSize;
78     m_string = StringImpl::create(m_string.impl(), 0, newSize);
79 }
80
81 void StringBuilder::reserveCapacity(unsigned newCapacity)
82 {
83     if (m_buffer) {
84         // If there is already a buffer, then grow if necessary.
85         if (newCapacity > m_buffer->length())
86             allocateBuffer(m_buffer->characters(), newCapacity);
87     } else {
88         // Grow the string, if necessary.
89         if (newCapacity > m_length)
90             allocateBuffer(m_string.characters(), newCapacity);
91     }
92 }
93
94 // Allocate a new buffer, copying in currentCharacters (these may come from either m_string
95 // or m_buffer,  neither will be reassigned until the copy has completed).
96 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
97 {
98     // Copy the existing data into a new buffer, set result to point to the end of the existing data.
99     RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters);
100     memcpy(m_bufferCharacters, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
101
102     // Update the builder state.
103     m_buffer = buffer.release();
104     m_string = String();
105 }
106
107 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
108 // return a pointer to the newly allocated storage.
109 UChar* StringBuilder::appendUninitialized(unsigned length)
110 {
111     ASSERT(length);
112
113     // Calcuate the new size of the builder after appending.
114     unsigned requiredLength = length + m_length;
115     if (requiredLength < length)
116         CRASH();
117
118     if (m_buffer) {
119         // If the buffer is valid it must be at least as long as the current builder contents!
120         ASSERT(m_buffer->length() >= m_length);
121
122         // Check if the buffer already has sufficient capacity.
123         if (requiredLength <= m_buffer->length()) {
124             unsigned currentLength = m_length;
125             m_string = String();
126             m_length = requiredLength;
127             return m_bufferCharacters + currentLength;
128         }
129
130         // We need to realloc the buffer.
131         allocateBuffer(m_buffer->characters(), std::max(requiredLength, std::max(minimumCapacity, m_buffer->length() * 2)));
132     } else {
133         ASSERT(m_string.length() == m_length);
134         allocateBuffer(m_string.characters(), std::max(requiredLength, std::max(minimumCapacity, m_length * 2)));
135     }
136
137     UChar* result = m_bufferCharacters + m_length;
138     m_length = requiredLength;
139     return result;
140 }
141
142 void StringBuilder::append(const UChar* characters, unsigned length)
143 {
144     if (!length)
145         return;
146     ASSERT(characters);
147
148     memcpy(appendUninitialized(length), characters, static_cast<size_t>(length) * 2);
149 }
150
151 void StringBuilder::append(const char* characters, unsigned length)
152 {
153     if (!length)
154         return;
155     ASSERT(characters);
156
157     UChar* dest = appendUninitialized(length);
158     const char* end = characters + length;
159     while (characters < end)
160         *(dest++) = *(const unsigned char*)(characters++);
161 }
162
163 void StringBuilder::shrinkToFit()
164 {
165     // If the buffer is at least 80% full, don't bother copying. Need to tune this heuristic!
166     if (m_buffer && m_buffer->length() > (m_length + (m_length >> 2))) {
167         UChar* result;
168         m_string = StringImpl::createUninitialized(m_length, result);
169         memcpy(result, m_buffer->characters(), static_cast<size_t>(m_length) * 2); // This can't overflow.
170         m_buffer = 0;
171     }
172 }
173
174 } // namespace WTF