1/*
2 * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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 ArrayBuffer_h
27#define ArrayBuffer_h
28
29#include "wtf/ArrayBufferContents.h"
30#include "wtf/HashSet.h"
31#include "wtf/PassRefPtr.h"
32#include "wtf/RefCounted.h"
33#include "wtf/WTFExport.h"
34
35namespace WTF {
36
37class ArrayBuffer;
38class ArrayBufferView;
39
40class WTF_EXPORT ArrayBuffer : public RefCounted<ArrayBuffer> {
41public:
42    static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
43    static inline PassRefPtr<ArrayBuffer> create(ArrayBuffer*);
44    static inline PassRefPtr<ArrayBuffer> create(const void* source, unsigned byteLength);
45    static inline PassRefPtr<ArrayBuffer> create(ArrayBufferContents&);
46
47    // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::getAsArrayBuffer.
48    static inline PassRefPtr<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
49
50    inline void* data();
51    inline const void* data() const;
52    inline unsigned byteLength() const;
53
54    // Creates a new ArrayBuffer object with copy of bytes in this object
55    // ranging from |begin| upto but not including |end|.
56    inline PassRefPtr<ArrayBuffer> slice(int begin, int end) const;
57    inline PassRefPtr<ArrayBuffer> slice(int begin) const;
58
59    void addView(ArrayBufferView*);
60    void removeView(ArrayBufferView*);
61
62    bool transfer(ArrayBufferContents&);
63    bool isNeutered() { return m_isNeutered; }
64
65    void setDeallocationObserver(ArrayBufferDeallocationObserver* observer) { m_contents.setDeallocationObserver(observer); }
66
67    ~ArrayBuffer() { }
68
69private:
70    static inline PassRefPtr<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
71
72    inline ArrayBuffer(ArrayBufferContents&);
73    inline PassRefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
74    inline unsigned clampIndex(int index) const;
75    static inline int clampValue(int x, int left, int right);
76
77    ArrayBufferContents m_contents;
78    ArrayBufferView* m_firstView;
79    bool m_isNeutered;
80};
81
82int ArrayBuffer::clampValue(int x, int left, int right)
83{
84    ASSERT(left <= right);
85    if (x < left)
86        x = left;
87    if (right < x)
88        x = right;
89    return x;
90}
91
92PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize)
93{
94    return create(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize);
95}
96
97PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBuffer* other)
98{
99    return ArrayBuffer::create(other->data(), other->byteLength());
100}
101
102PassRefPtr<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
103{
104    ArrayBufferContents contents(byteLength, 1, ArrayBufferContents::ZeroInitialize);
105    if (!contents.data())
106        return nullptr;
107    RefPtr<ArrayBuffer> buffer = adoptRef(new ArrayBuffer(contents));
108    memcpy(buffer->data(), source, byteLength);
109    return buffer.release();
110}
111
112PassRefPtr<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents& contents)
113{
114    return adoptRef(new ArrayBuffer(contents));
115}
116
117PassRefPtr<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize)
118{
119    return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
120}
121
122PassRefPtr<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
123{
124    ArrayBufferContents contents(numElements, elementByteSize, policy);
125    if (!contents.data())
126        return nullptr;
127    return adoptRef(new ArrayBuffer(contents));
128}
129
130ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents)
131    : m_firstView(0), m_isNeutered(false)
132{
133    contents.transfer(m_contents);
134}
135
136void* ArrayBuffer::data()
137{
138    return m_contents.data();
139}
140
141const void* ArrayBuffer::data() const
142{
143    return m_contents.data();
144}
145
146unsigned ArrayBuffer::byteLength() const
147{
148    return m_contents.sizeInBytes();
149}
150
151PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const
152{
153    return sliceImpl(clampIndex(begin), clampIndex(end));
154}
155
156PassRefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const
157{
158    return sliceImpl(clampIndex(begin), byteLength());
159}
160
161PassRefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
162{
163    unsigned size = begin <= end ? end - begin : 0;
164    return ArrayBuffer::create(static_cast<const char*>(data()) + begin, size);
165}
166
167unsigned ArrayBuffer::clampIndex(int index) const
168{
169    unsigned currentLength = byteLength();
170    if (index < 0)
171        index = currentLength + index;
172    return clampValue(index, 0, currentLength);
173}
174
175} // namespace WTF
176
177using WTF::ArrayBuffer;
178
179#endif // ArrayBuffer_h
180