1/* 2 * Copyright (C) 2011 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#ifndef RefCountedArray_h 27#define RefCountedArray_h 28 29#include <wtf/FastMalloc.h> 30#include <wtf/StdLibExtras.h> 31#include <wtf/Vector.h> 32 33// This implements a reference counted array for POD** values, which is optimized for: 34// - An empty array only uses one word. 35// - A copy of the array only uses one word (i.e. assignment means aliasing). 36// - The vector can't grow beyond 2^32-1 elements. 37// - In all other regards this has similar space usage to a Vector. 38// 39// ** This could be modified to support non-POD values quite easily. It just 40// hasn't been, so far, because there has been no need. Moreover, even now, 41// it's used for things that aren't quite POD according to the official 42// defintion, such as JSC::Instruction. 43 44namespace WTF { 45 46template<typename T> 47class RefCountedArray { 48public: 49 RefCountedArray() 50 : m_data(0) 51 { 52 } 53 54 RefCountedArray(const RefCountedArray& other) 55 : m_data(other.m_data) 56 { 57 if (m_data) 58 Header::fromPayload(m_data)->refCount++; 59 } 60 61 explicit RefCountedArray(size_t size) 62 { 63 if (!size) { 64 m_data = 0; 65 return; 66 } 67 68 m_data = (static_cast<Header*>(fastMalloc(Header::size() + sizeof(T) * size)))->payload(); 69 Header::fromPayload(m_data)->refCount = 1; 70 Header::fromPayload(m_data)->length = size; 71 ASSERT(Header::fromPayload(m_data)->length == size); 72 VectorTypeOperations<T>::initialize(begin(), end()); 73 } 74 75 explicit RefCountedArray(const Vector<T>& other) 76 { 77 if (other.isEmpty()) { 78 m_data = 0; 79 return; 80 } 81 82 m_data = (static_cast<Header*>(fastMalloc(Header::size() + sizeof(T) * other.size())))->payload(); 83 Header::fromPayload(m_data)->refCount = 1; 84 Header::fromPayload(m_data)->length = other.size(); 85 ASSERT(Header::fromPayload(m_data)->length == other.size()); 86 VectorTypeOperations<T>::uninitializedCopy(other.begin(), other.end(), m_data); 87 } 88 89 RefCountedArray& operator=(const RefCountedArray& other) 90 { 91 T* oldData = m_data; 92 m_data = other.m_data; 93 if (m_data) 94 Header::fromPayload(m_data)->refCount++; 95 96 if (!oldData) 97 return *this; 98 if (--Header::fromPayload(oldData)->refCount) 99 return *this; 100 VectorTypeOperations<T>::destruct(oldData, oldData + Header::fromPayload(oldData)->length); 101 fastFree(Header::fromPayload(oldData)); 102 return *this; 103 } 104 105 ~RefCountedArray() 106 { 107 if (!m_data) 108 return; 109 if (--Header::fromPayload(m_data)->refCount) 110 return; 111 VectorTypeOperations<T>::destruct(begin(), end()); 112 fastFree(Header::fromPayload(m_data)); 113 } 114 115 unsigned refCount() const 116 { 117 if (!m_data) 118 return 0; 119 return Header::fromPayload(m_data)->refCount; 120 } 121 122 size_t size() const 123 { 124 if (!m_data) 125 return 0; 126 return Header::fromPayload(m_data)->length; 127 } 128 129 size_t byteSize() const { return size() * sizeof(T); } 130 131 T* data() { return m_data; } 132 T* begin() { return m_data; } 133 T* end() 134 { 135 if (!m_data) 136 return 0; 137 return m_data + Header::fromPayload(m_data)->length; 138 } 139 140 const T* data() const { return m_data; } 141 const T* begin() const { return m_data; } 142 const T* end() const { return const_cast<RefCountedArray*>(this)->end(); } 143 144 T& at(size_t i) 145 { 146 ASSERT_WITH_SECURITY_IMPLICATION(i < size()); 147 return begin()[i]; 148 } 149 150 const T& at(size_t i) const 151 { 152 ASSERT_WITH_SECURITY_IMPLICATION(i < size()); 153 return begin()[i]; 154 } 155 156 T& operator[](size_t i) { return at(i); } 157 const T& operator[](size_t i) const { return at(i); } 158 159 bool operator==(const RefCountedArray& other) const 160 { 161 if (m_data == other.m_data) 162 return true; 163 if (!m_data || !other.m_data) 164 return false; 165 unsigned length = Header::fromPayload(m_data)->length; 166 if (length != Header::fromPayload(other.m_data)->length) 167 return false; 168 for (unsigned i = 0; i < length; ++i) { 169 if (m_data[i] != other.m_data[i]) 170 return false; 171 } 172 return true; 173 } 174 175private: 176 struct Header { 177 unsigned refCount; 178 unsigned length; 179 180 static size_t size() 181 { 182 return (sizeof(Header) + 7) & ~7; 183 } 184 185 T* payload() 186 { 187 char* result = reinterpret_cast<char*>(this) + size(); 188 ASSERT(!(bitwise_cast<uintptr_t>(result) & 7)); 189 return reinterpret_cast_ptr<T*>(result); 190 } 191 192 static Header* fromPayload(T* payload) 193 { 194 return reinterpret_cast_ptr<Header*>(reinterpret_cast<char*>(payload) - size()); 195 } 196 }; 197 198 T* m_data; 199}; 200 201} // namespace WTF 202 203using WTF::RefCountedArray; 204 205#endif // RefCountedArray_h 206 207