Thursday, April 13, 2017

Javascript typed arrays - slice vs subarray



What

Both of these TypedArrays' methods appear to do the same thing, except for a cool difference. Let's start with examples..

const a = new Uint8Array([1, 2, 3, 4]);

const b = a.slice(1, 3); // b becomes Uint8Array [ 2, 3 ]
const c = a.subarray(1, 3); // c becomes Uint8Array [ 2, 3 ]

Now let's see what happens when we change the values of these new arrays

b[0] = 5; // b is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 2, 3, 4 ]

c[0] = 5; // c is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 5, 3, 4 ]

See what happened at line 5? when we changed c, a has changed too, where on the other hand, b doesn't have the same effect, that's the difference.


Why

As you know, subarray exists only for typed arrays, that's the key to understand what's going on.

TypedArrays in javascript are represented in the memory as a single slab of bytes with the size reflecting the number of array items (if every item is one byte and the array has 3 items, then the memory taken is 3 bytes). Let's compare what slice does with what subarray does..

  • slice: Allocate a new space in memory and copy the items from the original array between the start and end indices provided in the arguments into these new memory locations, return the new array.
  • subarray: make a new empty typed array object, which points to a part of the original array between the start and end indices provided in the arguments.

So basically subarray lets a and c see and modify the same memory locations, it provides a smaller "view" (window) over the original array.

That makes subarray very fast compared to slice, because no copying is involved.


When

you can take advantage of this when you have a huge array that you want to convert a range of it into another type. One such situation that comes to mind is when the canvas demands a Uint8ClampedArray to draw its pixels.

const d = new Uint8ClampedArray(c);

the constructor sees c as a Uint8Array, because it really is an independent array which happens to look at the same memory location as a.

This gives you a new array d with the contents of a part of a without having to create an intermediate copy of the range that we want from a.


I hope I have managed to clear up the difference. feel free to ask questions, point out flaws and speak your mind in the comments.

Wednesday, March 15, 2017

Javascript - create fast lookup for string characters with this one-liner



This is another language shortcut, you may use it if you find yourself wanting to check if a string contains some character, and you want to do it fast, because it's inside a loop or something.

const stringy = "strings";

const stringLookup = new Set([...stringy]);

// stringLookup.has('s') === true

This is going to create a set, a hash-table-ish structure with all unique characters in the string.

The spread operator is creating an array from the string, which is essentially equivalent to stringy.split('').

So, stringLookup now has these entries { 's', 't', 'r', 'i', 'n', 'g' }.

View Set as a bag of unique elements, so it's most useful for quick character lookups.


A note about String.prototype.includes

This method uses the same algorithm used for String.prototype.indexOf, which in most implementations has an inside loop, which is not perfect for performance demanding apps.


I'm sure there are a lot of other ways, please share your favorite way of doing it in a comment.

Monday, January 9, 2017

How to use Swift's 'Data' structure to carry different types of data



Introduction


Swift provides the Data structure as an easy way to deal with byte buffers (sometimes called byte arrays). this means it holds raw bytes. This allows for very fast transfer of data (like over bluetooth).

It may be a little tricky to use it with some data types. This post provides ways to use Data to hold some of the most useful data types.

Just keep in mind that there has to be some kind of an "agreement" between your code and the consuming party of this data (it should know what data type and size are being sent).

If you are using a Swift playground, just import CoreData before you begin.

Code


UInt8 (and maybe booleans)

This is the primitive byte type as mentioned in the Swift docs; it is a raw byte after all 😅. It is the most straightforward to use as well.

Data can be used to hold an array of UInt8s directly.

let data = Data([1, 5])

/* or maybe create a flag,
 * change it in different places of the app
 * and send it like so..
 */
var flag: UInt8 = 0
let data = Data([flag])

This can also be used as a boolean flag by using 0 and 1 as values for a single element array (like you've seen in the above example).

String

Strings are also pretty easy to deal with.

let myString = "Cats are awesome"
let data = string.data(using: .utf8)

Just note that depending on your encoding of choice, the size is defferent. For this example with utf8, every character is 1 byte.

Float, Double and other number types

Other number types can take advantage of the flexibility of the UnsafeRawPointer to point directly to the memory location of the variable holding the data you want to send. This pointer is then used to initialize the Data object.

var myDouble = -9.52

let data = withUnsafePointer(to: &myDouble) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: myDouble))
}

This creates a Data object with the first parameter being a pointer to the myDouble variable.

The $0 is Swift's shorthand name of the UnsafePointer of myDouble. Check this answer if you need more info.

The second argument is the length which the Data initializer needs to walk through the memory to represent your variable, for this we have used the MemoryLayout.size(ofValue:) function to get the size of the myDouble variable automatically (which we know is 8 bytes, or 64 bits).

So this basically says: Starting at the position of myDouble in memory, walk 8 bytes, copy these bytes into a Data object.

Multiple data types with the same Data object


Most of the time, you would be okay with sending one type of data, but you might want to take advantage of the fact that you can send like double the size of the data you are sending at the moment to include other data.

Lets imagine that we want to send the price of a cat, along with a flag indicating if it is a kitten or a grown up cat.

// Like before, define a variable for the price
// and create a Data object with it
var price = 100.99

var data = withUnsafePointer(to: &price) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: price))
}
// now, define the kitten flag
var kitten: UInt8 = 1

// Make a Data object with it
let kittenFlagData = Data([kitten])

// append the two objects
data.append(kittenFlagData)

data now has 9 bytes, 8 bytes for the price (which, from the prespective of the consuming party, starts at offset 0).

It also has 1 byte for the flag (which, from the prespective of the consuming party, starts at offset 8).


That's it. Feel free to provide any kind of feedback.

Tuesday, January 3, 2017

I have created a web game that can be controlled with an iPhone. here's what it was like


The story

A couple of weeks ago, I have managed to create a web game that is totally controlled with iPhone over bluetooth.

The project is composed of the web game itself and a companion iPhone app to be used as the controller.

You use your phones sensors to move the character and two buttons for game actions are drawn on the controller app for interaction with the game world, your score vibrates when you're hit by an enemy and stores your best score (on the phone, for better mobility).

This post is for documenting the incident :D


some details

  • The game is written to use just web standards (although web bluetooth is not yet a standard, but it's built into the latest Chrome). no external libraries have been used, except for Rollup just to bundle the files (no transpiling).

  • The game is inside a canvas (obviously), no game frameworks were used.

  • Web Bluetooth API is still an experimental subset inside Chrome at the time of writing this project.


Lessons learned

  • The web is turning into a beast, I feel sorry for those who don't code for the web, they're missing a whole lot of excitement and fun times.

  • New Web APIs are very well thought and developer-friendly. I haven't dealt with bluetooth ever before and yet I have managed to make that game with so much less hair pulling than I was expecting.

  • Your fights with the Garbage Collector are gonna be aggressive. at first, you can see things disappear, then you try to capture that moment but you can't cuz it fires at random times, then you'll fire it up manually and say some bad words because it is eating up a global variable, at the end you'll read the API specification and understand what's going on. These fights are nasty, don't give up.

  • Trigonometry and Geometry are fun, after someone points out that you need to use a function that you haven't been taught in school to do what you want :D

  • Drawing your own assets is much more fun than searching for hours for the perfect asset for your game.

  • Drawing and animations on the raw canvas are not as scary as they seem, go for it, you don't need a full gaming framework if you're gonna make a small-to-medium project.

  • Byte buffers may be a little tricky to get your head around at first, but once you know them, you appreciate how minimal and powerful they are. (I may make another post about that one).

  • Apple has made a very good job with providing sensor readings, but they don't provide a precise straight forward way to get tilting angles, so you should come up with your own ticks for that matter.

  • Apple's Developer membership fee is pretty high, make sure to check it out :D

That said, the result was very satisfactory, it was smooth and responsive.

I'm going to record a video of the project in action soon and show it here to give you a better idea of what it does.

Update: here it is. I know it's super boring but it should deliver..

Thursday, November 24, 2016

Why Javascript's fill doesn't work with nested arrays



There maybe a situation where you want to pre-populate a default value for an array before further modifications along the execution course.

For a flat, single dimensional arrays, this works just like intended

arr.fill(-1);

What if you want to fill arr with arrays? like a matrix or so, something like this, for a 2 x 3 matrix

let arr = [
[-1, -1, -1],
[-1, -1, -1]
];

One might say, well, I'm just gonna use fill and pass an array as a parameter

let arr = Array(2);
arr.fill([-1, -1, -1]);
console.log(arr); //Prints same array like above

Piece of cake, right? not quite, not like the cake you'd like a piece of.

The problem

Lets look at a misbehavior for that approach that might cause you headaches, and see why that happens

//This is the array after usng fill
// [ [ -1, -1, -1 ], [ -1, -1, -1 ] ]

//Now set an element in one of the sub-arrays
arr[0][1] = 5;
console.log(arr);
// [ [ -1, 5, -1 ], [ -1, 5, -1 ] ]
//Oops! what just happend?

You see that? you've just set one element in one array, yet all elements in that position of all sub-arrays were set to the same value (i.e. if you had a third sub-array -or more, its element at position 1 will be set to 5 as well).

Why fill won't work

if you look at the implementation docs for the Array.prototype.fill method, you can see the reason for this behavior. The simplified process of arr.fill(arg) is like that..

for every position in arr:
  arr[position] = arg

So the same arg is assigned to each position, and arrays in Javascript are objects, so what's really passed is a reference to the same object in memory, that's why any change to one element affects the rest, they are the same thing. This might be better demonstrated like below..

let b = [-1, -1, -1];
arr.fill(b);

the first line creates an array in memory and makes b reference it, then b is passed to the fill method that assigns it to every position in the array, imagine arr now is something like: [ [b], [b], [b] ].

The fix

One possible one-liner fix would be to use ES 2015's Array.from

let arr = Array.from(Array(2), ()=>[-1, -1, -1]);

The first parameter is an iterable (In our case it's an empty array of length 2). The second parameter is a map function that's executed for each element, so every element is gonna be its own unique array.

Another way to handle this is a little trick with apply on the Array function (Array can be used as a constructor or a function, so apply is available to it)

let arr = Array.apply(null, Array(2)).
    map(()=>[-1, -1, -1]);

The reason this works is that Array() creates a bunch of holes (empty spots), and map ignores these holes, so we use apply because it fills these holes with undefined so map can see these.

These are meant to be quick one-liners to solve the problem. You can always fall back to iterating through the array and assigning the value to each position

That's it, feel free to share thoughts, ask questions and fill in gaps.