Hone logo
Hone
Problems

Copy-on-Write Array in JavaScript

Copy-on-write is a powerful optimization technique where data is shared until a modification is attempted. This challenge asks you to implement a copy-on-write array in JavaScript. This pattern is useful for scenarios where you have multiple references to an array, and you want to avoid unnecessary copying until a modification is actually needed, saving memory and potentially improving performance.

Problem Description

You are to create a CopyOnWriteArray class in JavaScript. This class should mimic the behavior of a standard JavaScript array, but with the copy-on-write optimization. The core idea is that multiple CopyOnWriteArray instances can initially point to the same underlying array data. Only when one instance attempts to modify the array does it create a new copy of the data, leaving other instances unaffected.

Key Requirements:

  • Constructor: The constructor should accept an initial array as an argument.
  • Read-Only Methods: Methods like length, at(index), slice(), map(), filter(), reduce(), forEach() should return the same values as a standard JavaScript array, without creating copies. These methods should operate on the shared underlying array.
  • Write-Only Methods: Methods like push(), pop(), shift(), unshift(), splice(), set(index, value), and direct assignment to elements (e.g., array[index] = value) should trigger a copy of the underlying array before performing the modification. After the copy, the modification should be applied to the copy, and the CopyOnWriteArray instance should then manage this new copy. Other instances should continue to use the original shared array.
  • Immutability of Original: Modifying one CopyOnWriteArray instance should never affect other instances that share the same underlying array.
  • Chaining: Methods that return a new CopyOnWriteArray (e.g., map(), filter()) should return a new instance of CopyOnWriteArray, not a standard JavaScript array.

Expected Behavior:

  • Multiple CopyOnWriteArray instances created from the same initial array should initially share the same data.
  • Modifying one instance should create a copy and only affect that instance.
  • Read operations on any instance should return the correct values, reflecting the state of the underlying array at the time of the read.
  • Methods that return arrays (like slice(), map(), filter()) should return new CopyOnWriteArray instances.

Edge Cases to Consider:

  • Empty initial array.
  • Modifying elements at the beginning, middle, and end of the array.
  • Chaining multiple write operations (e.g., map().filter().push()).
  • set() method with out-of-bounds indices (should throw an error, like standard arrays).
  • splice() with negative indices.

Examples

Example 1:

Input:
const arr = [1, 2, 3];
const copy1 = new CopyOnWriteArray(arr);
const copy2 = new CopyOnWriteArray(arr);

console.log(copy1.length); // Output: 3
console.log(copy2.length); // Output: 3
console.log(copy1[0] === copy2[0]); // Output: true

copy1[0] = 10;

console.log(copy1.length); // Output: 3
console.log(copy2.length); // Output: 3
console.log(copy1[0]); // Output: 10
console.log(copy2[0]); // Output: 1

Explanation: Initially, copy1 and copy2 share the same array. Modifying copy1 triggers a copy, so copy2 remains unchanged.

Example 2:

Input:
const arr = [1, 2, 3];
const copy1 = new CopyOnWriteArray(arr);
const copy2 = copy1.map(x => x * 2);

console.log(copy1[0]); // Output: 1
console.log(copy2[0]); // Output: 2
copy1[0] = 10;
console.log(copy1[0]); // Output: 10
console.log(copy2[0]); // Output: 2

Explanation: map() creates a new CopyOnWriteArray. Modifying copy1 after the map() operation doesn't affect copy2.

Example 3: (Edge Case)

Input:
const arr = [];
const copy1 = new CopyOnWriteArray(arr);
copy1.push(1);
console.log(copy1.length); // Output: 1
console.log(copy1[0]); // Output: 1

Explanation: Handles the case of an empty initial array correctly.

Constraints

  • The initial array can contain any valid JavaScript data types.
  • The array length will not exceed 1000.
  • Performance: While not a primary focus, avoid unnecessary copying. The copy should only happen when a write operation is performed.
  • The set() method should throw a RangeError if the index is out of bounds, mirroring standard JavaScript array behavior.

Notes

  • Consider using a private property to store the underlying array.
  • Think carefully about when and how to create copies.
  • The map() and filter() methods should return new CopyOnWriteArray instances, not standard JavaScript arrays. This is crucial for maintaining the copy-on-write behavior.
  • Pay close attention to how write operations affect other instances of the CopyOnWriteArray.
Loading editor...
javascript