1/*
2 * Copyright (C) 2013-2019 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#pragma once
27
28#include "JSCJSValue.h"
29#include "MathCommon.h"
30#include "TypedArrayType.h"
31#include <wtf/MathExtras.h>
32
33namespace JSC {
34
35template<
36 typename TypeArg, typename ViewTypeArg, typename JSViewTypeArg,
37 TypedArrayType typeValueArg>
38struct IntegralTypedArrayAdaptor {
39 typedef TypeArg Type;
40 typedef ViewTypeArg ViewType;
41 typedef JSViewTypeArg JSViewType;
42 static const TypedArrayType typeValue = typeValueArg;
43 constexpr static const TypeArg minValue = std::numeric_limits<TypeArg>::lowest();
44 constexpr static const TypeArg maxValue = std::numeric_limits<TypeArg>::max();
45
46 static JSValue toJSValue(Type value)
47 {
48 static_assert(!std::is_floating_point<Type>::value, "");
49 return jsNumber(value);
50 }
51
52 static double toDouble(Type value)
53 {
54 return static_cast<double>(value);
55 }
56
57 static Type toNativeFromInt32(int32_t value)
58 {
59 return static_cast<Type>(value);
60 }
61
62 static Type toNativeFromUint32(uint32_t value)
63 {
64 return static_cast<Type>(value);
65 }
66
67 static Type toNativeFromDouble(double value)
68 {
69 int32_t result = static_cast<int32_t>(value);
70 if (static_cast<double>(result) != value)
71 result = toInt32(value);
72 return static_cast<Type>(result);
73 }
74
75 template<typename OtherAdaptor>
76 static typename OtherAdaptor::Type convertTo(Type value)
77 {
78 if (typeValue == TypeUint32)
79 return OtherAdaptor::toNativeFromUint32(value);
80 return OtherAdaptor::toNativeFromInt32(value);
81 }
82
83 static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
84 {
85 if ((value >= 0 && static_cast<uint32_t>(value) > static_cast<uint32_t>(maxValue)) || value < static_cast<int32_t>(minValue))
86 return WTF::nullopt;
87 return static_cast<Type>(value);
88 }
89
90 static Optional<Type> toNativeFromUint32WithoutCoercion(uint32_t value)
91 {
92 if (value > static_cast<uint32_t>(maxValue))
93 return WTF::nullopt;
94
95 return static_cast<Type>(value);
96 }
97
98 static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
99 {
100 Type integer = static_cast<Type>(value);
101 if (static_cast<double>(integer) != value)
102 return WTF::nullopt;
103
104 if (value < 0)
105 return toNativeFromInt32WithoutCoercion(static_cast<int32_t>(value));
106
107 return toNativeFromUint32WithoutCoercion(static_cast<uint32_t>(value));
108 }
109};
110
111template<
112 typename TypeArg, typename ViewTypeArg, typename JSViewTypeArg,
113 TypedArrayType typeValueArg>
114struct FloatTypedArrayAdaptor {
115 typedef TypeArg Type;
116 typedef ViewTypeArg ViewType;
117 typedef JSViewTypeArg JSViewType;
118 static const TypedArrayType typeValue = typeValueArg;
119 constexpr static const TypeArg minValue = std::numeric_limits<TypeArg>::lowest();
120 constexpr static const TypeArg maxValue = std::numeric_limits<TypeArg>::max();
121
122 static JSValue toJSValue(Type value)
123 {
124 return jsDoubleNumber(purifyNaN(value));
125 }
126
127 static double toDouble(Type value)
128 {
129 return static_cast<double>(value);
130 }
131
132 static Type toNativeFromInt32(int32_t value)
133 {
134 return static_cast<Type>(value);
135 }
136
137 static Type toNativeFromUint32(uint32_t value)
138 {
139 return static_cast<Type>(value);
140 }
141
142 static Type toNativeFromDouble(double value)
143 {
144 return static_cast<Type>(value);
145 }
146
147 template<typename OtherAdaptor>
148 static typename OtherAdaptor::Type convertTo(Type value)
149 {
150 return OtherAdaptor::toNativeFromDouble(value);
151 }
152
153 static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
154 {
155 return static_cast<Type>(value);
156 }
157
158 static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
159 {
160 if (std::isnan(value) || std::isinf(value))
161 return static_cast<Type>(value);
162
163 Type valueResult = static_cast<Type>(value);
164
165 if (static_cast<double>(valueResult) != value)
166 return WTF::nullopt;
167
168 if (value < minValue || value > maxValue)
169 return WTF::nullopt;
170
171 return valueResult;
172 }
173};
174
175struct Int8Adaptor;
176struct Int16Adaptor;
177struct Int32Adaptor;
178struct Uint8Adaptor;
179struct Uint8ClampedAdaptor;
180struct Uint16Adaptor;
181struct Uint32Adaptor;
182struct Float32Adaptor;
183struct Float64Adaptor;
184
185template<typename Adaptor> class GenericTypedArrayView;
186typedef GenericTypedArrayView<Int8Adaptor> Int8Array;
187typedef GenericTypedArrayView<Int16Adaptor> Int16Array;
188typedef GenericTypedArrayView<Int32Adaptor> Int32Array;
189typedef GenericTypedArrayView<Uint8Adaptor> Uint8Array;
190typedef GenericTypedArrayView<Uint8ClampedAdaptor> Uint8ClampedArray;
191typedef GenericTypedArrayView<Uint16Adaptor> Uint16Array;
192typedef GenericTypedArrayView<Uint32Adaptor> Uint32Array;
193typedef GenericTypedArrayView<Float32Adaptor> Float32Array;
194typedef GenericTypedArrayView<Float64Adaptor> Float64Array;
195
196template<typename Adaptor> class JSGenericTypedArrayView;
197typedef JSGenericTypedArrayView<Int8Adaptor> JSInt8Array;
198typedef JSGenericTypedArrayView<Int16Adaptor> JSInt16Array;
199typedef JSGenericTypedArrayView<Int32Adaptor> JSInt32Array;
200typedef JSGenericTypedArrayView<Uint8Adaptor> JSUint8Array;
201typedef JSGenericTypedArrayView<Uint8ClampedAdaptor> JSUint8ClampedArray;
202typedef JSGenericTypedArrayView<Uint16Adaptor> JSUint16Array;
203typedef JSGenericTypedArrayView<Uint32Adaptor> JSUint32Array;
204typedef JSGenericTypedArrayView<Float32Adaptor> JSFloat32Array;
205typedef JSGenericTypedArrayView<Float64Adaptor> JSFloat64Array;
206
207struct Int8Adaptor : IntegralTypedArrayAdaptor<int8_t, Int8Array, JSInt8Array, TypeInt8> { };
208struct Int16Adaptor : IntegralTypedArrayAdaptor<int16_t, Int16Array, JSInt16Array, TypeInt16> { };
209struct Int32Adaptor : IntegralTypedArrayAdaptor<int32_t, Int32Array, JSInt32Array, TypeInt32> { };
210struct Uint8Adaptor : IntegralTypedArrayAdaptor<uint8_t, Uint8Array, JSUint8Array, TypeUint8> { };
211struct Uint16Adaptor : IntegralTypedArrayAdaptor<uint16_t, Uint16Array, JSUint16Array, TypeUint16> { };
212struct Uint32Adaptor : IntegralTypedArrayAdaptor<uint32_t, Uint32Array, JSUint32Array, TypeUint32> { };
213struct Float32Adaptor : FloatTypedArrayAdaptor<float, Float32Array, JSFloat32Array, TypeFloat32> { };
214struct Float64Adaptor : FloatTypedArrayAdaptor<double, Float64Array, JSFloat64Array, TypeFloat64> { };
215
216struct Uint8ClampedAdaptor {
217 typedef uint8_t Type;
218 typedef Uint8ClampedArray ViewType;
219 typedef JSUint8ClampedArray JSViewType;
220 static const TypedArrayType typeValue = TypeUint8Clamped;
221 constexpr static const uint8_t minValue = std::numeric_limits<uint8_t>::lowest();
222 constexpr static const uint8_t maxValue = std::numeric_limits<uint8_t>::max();
223
224 static JSValue toJSValue(uint8_t value)
225 {
226 return jsNumber(value);
227 }
228
229 static double toDouble(uint8_t value)
230 {
231 return static_cast<double>(value);
232 }
233
234 static Type toNativeFromInt32(int32_t value)
235 {
236 return clamp(value);
237 }
238
239 static Type toNativeFromUint32(uint32_t value)
240 {
241 return std::min(static_cast<uint32_t>(255), value);
242 }
243
244 static Type toNativeFromDouble(double value)
245 {
246 if (std::isnan(value) || value < 0)
247 return 0;
248 if (value > 255)
249 return 255;
250 return static_cast<uint8_t>(lrint(value));
251 }
252
253 template<typename OtherAdaptor>
254 static typename OtherAdaptor::Type convertTo(uint8_t value)
255 {
256 return OtherAdaptor::toNativeFromInt32(value);
257 }
258
259 static Optional<Type> toNativeFromInt32WithoutCoercion(int32_t value)
260 {
261 if (value > maxValue || value < minValue)
262 return WTF::nullopt;
263
264 return static_cast<Type>(value);
265 }
266
267 static Optional<Type> toNativeFromDoubleWithoutCoercion(double value)
268 {
269 uint8_t integer = static_cast<uint8_t>(value);
270 if (static_cast<double>(integer) != value)
271 return WTF::nullopt;
272
273 return integer;
274 }
275
276private:
277 static uint8_t clamp(int32_t value)
278 {
279 if (value < 0)
280 return 0;
281 if (value > 255)
282 return 255;
283 return static_cast<uint8_t>(value);
284 }
285};
286
287} // namespace JSC
288