Quinix

(This page might be a bit more readable if you enable 1st-party CSS.)

Proxies

While writing up memory mapped peripherals I needed to implement views on Array instances. In the QVM implementation memory is represented using a Uint32Array, which natively supports views, but in the series examples here we’ve stuck with arrays for simplicity. I didn’t want to create a cumbersome wrapper that didn’t support the natural indexing notation of arrays, and so I stumbled upon Proxy.

Here we wrap a given array in a proxy that translates array indices from the “view space” (ranging from 0 to the length of the view) to the underlying “array space”. The view begins at index base and is count long, so when you read index i from the view, you are really reading index base + i from the underlying array.

function view<T>(array: T[], base: number, count: number): T[] {
  return new Proxy(array, {
    get: (object, prop) => {
      // Translate view[n] to array[base+n].
      const index = parseInt(prop as any);
      if(!isNaN(index)){
        if(index >= 0 && index < count){
          return object[base + index];
        }
        return;
      }

      // Return the view's length, not the underlying array's.
      if(prop === 'length'){
        return count;
      }

      return object[prop as any];
    },

    set: (object, prop, value) => {
      // Translate view[n] to array[base+n].
      const index = parseInt(prop as any);
      if(!isNaN(index)){
        if(index >= 0 && index < count){
          object[base + index] = value;
          return true;
        }
        return false;
      }

      // Disallow changing the view's length.
      if(prop === 'length'){
        return false;
      }

      object[prop as any] = value;
      return true;
    },
  });
}

This view isn’t “safe”, of course – you can easily call e.g. view.forEach(...) to read all of the underlying array’s data. But it is convenient and serves the purpose of translating between view space and array space well enough.

« Back