jswrap_arraybuffer.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
  3. *
  4. * Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. *
  10. * ----------------------------------------------------------------------------
  11. * This file is designed to be parsed during the build process
  12. *
  13. * JavaScript methods for ArrayBuffers
  14. * ----------------------------------------------------------------------------
  15. */
  16. #include "jswrap_arraybuffer.h"
  17. #include "jsparse.h"
  18. #include "jsinteractive.h"
  19. /*JSON{ "type":"class",
  20. "class" : "ArrayBuffer",
  21. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_ARRAYBUFFER",
  22. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  23. "description" : ["This is the built-in JavaScript class for array buffers." ]
  24. }*/
  25. /*JSON{ "type":"class",
  26. "class" : "ArrayBufferView",
  27. "description" : ["This is the built-in JavaScript class that is the prototype for Uint8Array / Float32Array / etc" ]
  28. }*/
  29. /*JSON{ "type":"class",
  30. "class" : "Uint8Array", "prototype" : "ArrayBufferView",
  31. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT8",
  32. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  33. "description" : ["This is the built-in JavaScript class for a typed array.",
  34. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  35. }*/
  36. /*JSON{ "type":"class",
  37. "class" : "Int8Array", "prototype" : "ArrayBufferView",
  38. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT8",
  39. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  40. "description" : ["This is the built-in JavaScript class for a typed array.",
  41. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  42. }*/
  43. /*JSON{ "type":"class",
  44. "class" : "Uint16Array", "prototype" : "ArrayBufferView",
  45. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT16",
  46. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  47. "description" : ["This is the built-in JavaScript class for a typed array.",
  48. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  49. }*/
  50. /*JSON{ "type":"class",
  51. "class" : "Int16Array", "prototype" : "ArrayBufferView",
  52. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT16",
  53. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  54. "description" : ["This is the built-in JavaScript class for a typed array.",
  55. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  56. }*/
  57. /*JSON{ "type":"class",
  58. "class" : "Uint32Array", "prototype" : "ArrayBufferView",
  59. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_UINT32",
  60. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  61. "description" : ["This is the built-in JavaScript class for a typed array.",
  62. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  63. }*/
  64. /*JSON{ "type":"class",
  65. "class" : "Int32Array", "prototype" : "ArrayBufferView",
  66. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_INT32",
  67. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  68. "description" : ["This is the built-in JavaScript class for a typed array.",
  69. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  70. }*/
  71. /*JSON{ "type":"class",
  72. "class" : "Float32Array", "prototype" : "ArrayBufferView",
  73. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT32",
  74. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  75. "description" : ["This is the built-in JavaScript class for a typed array.",
  76. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  77. }*/
  78. /*JSON{ "type":"class",
  79. "class" : "Float64Array", "prototype" : "ArrayBufferView",
  80. "check" : "jsvIsArrayBuffer(var) && var->varData.arraybuffer.type==ARRAYBUFFERVIEW_FLOAT64",
  81. "not_real_object" : "Don't treat this as a real object - it's handled differently internally",
  82. "description" : ["This is the built-in JavaScript class for a typed array.",
  83. "Instantiate this in order to efficiently store arrays of data (Espruino's normal arrays store data in a map, which is inefficient for non-sparse arrays). " ]
  84. }*/
  85. /*JSON{ "type":"constructor", "class": "ArrayBuffer", "name": "ArrayBuffer",
  86. "description" : "Create an Array Buffer object",
  87. "generate" : "jswrap_arraybuffer_constructor",
  88. "params" : [ [ "byteLength", "int", "The length in Bytes" ] ],
  89. "return" : [ "JsVar", "An ArrayBuffer object" ]
  90. }*/
  91. JsVar *jswrap_arraybuffer_constructor(JsVarInt byteLength) {
  92. if (byteLength <= 0 || byteLength>65535) {
  93. jsError("Invalid length for ArrayBuffer\n");
  94. return 0;
  95. }
  96. if (byteLength > JSV_ARRAYBUFFER_MAX_LENGTH) {
  97. jsError("ArrayBuffer too long\n");
  98. return 0;
  99. }
  100. JsVar *arrData = jsvNewStringOfLength((unsigned int)byteLength);
  101. if (!arrData) return 0;
  102. JsVar *arr = jsvNewWithFlags(JSV_ARRAYBUFFER);
  103. if (!arr) {
  104. jsvUnLock(arrData);
  105. return 0;
  106. }
  107. arr->firstChild = jsvGetRef(jsvRef(arrData));
  108. jsvUnLock(arrData);
  109. arr->varData.arraybuffer.type = ARRAYBUFFERVIEW_ARRAYBUFFER;
  110. arr->varData.arraybuffer.byteOffset = 0;
  111. arr->varData.arraybuffer.length = (unsigned short)byteLength;
  112. return arr;
  113. }
  114. /*
  115. * Potential invocations:
  116. * Uint8Array Uint8Array(unsigned long length);
  117. * Uint8Array Uint8Array(TypedArray array);
  118. * Uint8Array Uint8Array(sequence<type> array);
  119. * Uint8Array Uint8Array(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length);
  120. */
  121. /*JSON{ "type":"constructor", "class": "Uint8Array", "name": "Uint8Array",
  122. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  123. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  124. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  125. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  126. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  127. "return" : [ "JsVar", "A typed array" ]
  128. }*/
  129. /*JSON{ "type":"constructor", "class": "Int8Array", "name": "Int8Array",
  130. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  131. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT8, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  132. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  133. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  134. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  135. "return" : [ "JsVar", "A typed array" ]
  136. }*/
  137. /*JSON{ "type":"constructor", "class": "Uint16Array", "name": "Uint16Array",
  138. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  139. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  140. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  141. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  142. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  143. "return" : [ "JsVar", "A typed array" ]
  144. }*/
  145. /*JSON{ "type":"constructor", "class": "Int16Array", "name": "Int16Array",
  146. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  147. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT16, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  148. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  149. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  150. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  151. "return" : [ "JsVar", "A typed array" ]
  152. }*/
  153. /*JSON{ "type":"constructor", "class": "Uint32Array", "name": "Uint32Array",
  154. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  155. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_UINT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  156. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  157. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  158. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  159. "return" : [ "JsVar", "A typed array" ]
  160. }*/
  161. /*JSON{ "type":"constructor", "class": "Int32Array", "name": "Int32Array",
  162. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  163. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_INT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  164. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  165. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  166. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  167. "return" : [ "JsVar", "A typed array" ]
  168. }*/
  169. /*JSON{ "type":"constructor", "class": "Float32Array", "name": "Float32Array",
  170. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  171. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT32, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  172. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  173. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  174. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  175. "return" : [ "JsVar", "A typed array" ]
  176. }*/
  177. /*JSON{ "type":"constructor", "class": "Float64Array", "name": "Float64Array",
  178. "description" : "Create a typed array based on the given input. Either an existing Array Buffer, an Integer as a Length, or a simple array",
  179. "generate_full" : "jswrap_typedarray_constructor(ARRAYBUFFERVIEW_FLOAT64, arr, jsvGetInteger(byteOffset), jsvGetInteger(length))",
  180. "params" : [ [ "arr", "JsVar", "The array or typed array to base this off, or an integer which is the array length" ],
  181. [ "byteOffset", "int", "The byte offset in the ArrayBuffer (ONLY IF the first argument was an ArrayBuffer)" ],
  182. [ "length", "int", "The length (ONLY IF the first argument was an ArrayBuffer)" ] ],
  183. "return" : [ "JsVar", "A typed array" ]
  184. }*/
  185. JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length) {
  186. JsVar *arrayBuffer = 0;
  187. if (jsvIsArrayBuffer(arr)) {
  188. arrayBuffer = jsvLockAgain(arr);
  189. } else if (jsvIsInt(arr)) {
  190. length = jsvGetInteger(arr);
  191. byteOffset = 0;
  192. arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length);
  193. } else if (jsvIsArray(arr)) {
  194. length = jsvGetArrayLength(arr);
  195. byteOffset = 0;
  196. arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length);
  197. // later on we'll populate this
  198. }
  199. if (!arrayBuffer) {
  200. jsError("Unsupported first argument\n");
  201. return 0;
  202. }
  203. if (length<=0) length = (JsVarInt)jsvGetArrayBufferLength(arrayBuffer) / JSV_ARRAYBUFFER_GET_SIZE(type);
  204. JsVar *typedArr = jsvNewWithFlags(JSV_ARRAYBUFFER);
  205. if (typedArr) {
  206. typedArr->varData.arraybuffer.type = type;
  207. typedArr->varData.arraybuffer.byteOffset = (unsigned short)byteOffset;
  208. typedArr->varData.arraybuffer.length = (unsigned short)length;
  209. typedArr->firstChild = jsvGetRef(jsvRef(arrayBuffer));
  210. if (jsvIsArray(arr)) {
  211. // if we were given an array, populate this ArrayBuffer
  212. JsArrayIterator it;
  213. jsvArrayIteratorNew(&it, arr);
  214. while (jsvArrayIteratorHasElement(&it)) {
  215. JsVar *idx = jsvArrayIteratorGetIndex(&it);
  216. if (jsvIsInt(idx)) {
  217. JsVar *val = jsvArrayIteratorGetElement(&it);
  218. jsvArrayBufferSet(typedArr, jsvGetInteger(idx), val);
  219. jsvUnLock(val);
  220. }
  221. jsvUnLock(idx);
  222. jsvArrayIteratorNext(&it);
  223. }
  224. jsvArrayIteratorFree(&it);
  225. }
  226. }
  227. jsvUnLock(arrayBuffer);
  228. return typedArr;
  229. }
  230. /*JSON{ "type":"property", "class": "ArrayBufferView", "name": "buffer",
  231. "description" : "The buffer this view references",
  232. "generate_full" : "jsvLock(parent->firstChild)",
  233. "return" : [ "JsVar", "An ArrayBuffer object" ]
  234. }*/
  235. /*JSON{ "type":"property", "class": "ArrayBufferView", "name": "byteLength",
  236. "description" : "The length, in bytes, of the view",
  237. "generate_full" : "parent->varData.arraybuffer.length * JSV_ARRAYBUFFER_GET_SIZE(parent->varData.arraybuffer.type)",
  238. "return" : [ "int", "The Length" ]
  239. }*/
  240. /*JSON{ "type":"property", "class": "ArrayBufferView", "name": "byteOffset",
  241. "description" : "The offset, in bytes, to the first byte of the view within the ArrayBuffer",
  242. "generate_full" : "parent->varData.arraybuffer.byteOffset",
  243. "return" : [ "int", "The byte Offset" ]
  244. }*/
  245. /*JSON{ "type":"method", "class": "ArrayBufferView", "name": "interpolate",
  246. "description" : "Interpolate between two adjacent values in the Typed Array",
  247. "generate" : "jswrap_arraybufferview_interpolate",
  248. "params" : [ [ "index", "float", "Floating point index to access" ] ],
  249. "return" : [ "float", "The result of interpolating between (int)index and (int)(index+1)" ]
  250. }*/
  251. JsVarFloat jswrap_arraybufferview_interpolate(JsVar *parent, JsVarFloat findex) {
  252. int idx = (int)findex;
  253. JsVarFloat a = findex-idx;
  254. JsvArrayBufferIterator it;
  255. jsvArrayBufferIteratorNew(&it, parent, idx);
  256. JsVarFloat fa = jsvArrayBufferIteratorGetFloatValue(&it);
  257. jsvArrayBufferIteratorNext(&it);
  258. JsVarFloat fb = jsvArrayBufferIteratorGetFloatValue(&it);
  259. jsvArrayBufferIteratorFree(&it);
  260. return fa*(1-a) + fb*a;
  261. }
  262. /*JSON{ "type":"method", "class": "ArrayBufferView", "name": "interpolate2d",
  263. "description" : "Interpolate between two adjacent values in the Typed Array",
  264. "generate" : "jswrap_arraybufferview_interpolate2d",
  265. "params" : [ [ "width", "int", "Integer 'width' of 2d array" ],
  266. [ "x", "float", "Floating point X index to access" ],
  267. [ "y", "float", "Floating point Y index to access" ] ],
  268. "return" : [ "float", "The result of interpolating in 2d between the 4 surrounding cells" ]
  269. }*/
  270. JsVarFloat jswrap_arraybufferview_interpolate2d(JsVar *parent, JsVarInt width, JsVarFloat x, JsVarFloat y) {
  271. int yidx = (int)y;
  272. JsVarFloat ay = y-yidx;
  273. JsVarFloat findex = x + (JsVarFloat)(yidx*width);
  274. int idx = (int)findex;
  275. JsVarFloat ax = findex-idx;
  276. JsvArrayBufferIterator it;
  277. jsvArrayBufferIteratorNew(&it, parent, idx);
  278. JsVarFloat xa,xb;
  279. int i;
  280. xa = jsvArrayBufferIteratorGetFloatValue(&it);
  281. jsvArrayBufferIteratorNext(&it);
  282. xb = jsvArrayBufferIteratorGetFloatValue(&it);
  283. JsVarFloat ya = xa*(1-ax) + xb*ax;
  284. for (i=1;i<width;i++) jsvArrayBufferIteratorNext(&it);
  285. xa = jsvArrayBufferIteratorGetFloatValue(&it);
  286. jsvArrayBufferIteratorNext(&it);
  287. xb = jsvArrayBufferIteratorGetFloatValue(&it);
  288. jsvArrayBufferIteratorFree(&it);
  289. JsVarFloat yb = xa*(1-ax) + xb*ax;
  290. return ya*(1-ay) + yb*ay;
  291. }