Hone logo
Hone
Problems

Implementing Copy-on-Write Strings in JavaScript

Copy-on-write strings are a powerful optimization technique where string modifications only create a new string when a change is actually made. This avoids unnecessary memory allocation and copying when a string is intended to be immutable. This challenge asks you to implement a basic copy-on-write string class in JavaScript, demonstrating this principle.

Problem Description

You are to implement a CopyOnWriteString class in JavaScript. This class should behave like a standard string for read operations but should create a new, independent string object when a modification method (e.g., toUpperCase, toLowerCase, substring, replace) is called. The original CopyOnWriteString instance should remain unchanged. The class should internally store the string data and a flag indicating whether the string has been modified.

Key Requirements:

  • Immutability (Original Instance): Calling any modification method on the original CopyOnWriteString instance must not modify that instance. It should return a new CopyOnWriteString instance with the modification applied.
  • String-like Behavior: The class should support standard string operations like length, accessing characters by index (e.g., str[0]), and implicit conversion to a string (e.g., using it in a console.log).
  • Copy-on-Write: Modifications should only create a new string when necessary. If a method doesn't actually change the string (e.g., toUpperCase on a string already in uppercase), it should return the original instance (or a new instance referencing the same internal string data).
  • Internal Data: The class should store the string data internally.

Expected Behavior:

  • Creating a CopyOnWriteString with a string should initialize the internal string data.
  • Read operations (e.g., length, character access) should work as expected on the original instance.
  • Modification methods should return a new CopyOnWriteString instance with the modification applied.
  • The original CopyOnWriteString instance should remain unchanged after a modification.

Edge Cases to Consider:

  • Creating a CopyOnWriteString with an empty string.
  • Calling modification methods on an empty string.
  • Chaining modification methods (e.g., str.toUpperCase().toLowerCase()).
  • Methods that don't modify the string (e.g., toUpperCase on an already uppercase string).

Examples

Example 1:

Input: const str = new CopyOnWriteString("hello");
       const upperStr = str.toUpperCase();
       const lowerStr = upperStr.toLowerCase();

Output:
str.valueOf() === "hello"
upperStr.valueOf() === "HELLO"
lowerStr.valueOf() === "hello"
str === upperStr // false
upperStr === lowerStr // false

Explanation: The original string "hello" remains unchanged. toUpperCase() creates a new string "HELLO", and toLowerCase() creates a new string "hello" from the "HELLO" instance. Each instance is distinct.

Example 2:

Input: const str = new CopyOnWriteString("WORLD");
       const upperStr = str.toUpperCase();

Output:
str.valueOf() === "WORLD"
upperStr.valueOf() === "WORLD"
str === upperStr // true

Explanation: Since "WORLD" is already uppercase, toUpperCase() returns the original instance (or a new instance referencing the same string data), demonstrating the copy-on-write optimization.

Example 3:

Input: const str = new CopyOnWriteString("");
       const upperStr = str.toUpperCase();

Output:
str.valueOf() === ""
upperStr.valueOf() === ""
str === upperStr // true

Explanation: Handles the edge case of an empty string correctly.

Constraints

  • The internal string data should be stored efficiently.
  • Modification methods should return a new CopyOnWriteString instance or the original instance if no modification is needed.
  • The class should support the following methods:
    • constructor(str: string): Initializes the CopyOnWriteString with the given string.
    • length(): number: Returns the length of the string.
    • valueOf(): string: Returns the string value.
    • toUpperCase(): CopyOnWriteString: Returns a new CopyOnWriteString with the string converted to uppercase.
    • toLowerCase(): CopyOnWriteString: Returns a new CopyOnWriteString with the string converted to lowercase.
    • substring(startIndex: number, endIndex: number): CopyOnWriteString: Returns a new CopyOnWriteString containing a substring.
    • replace(searchValue: string, replaceValue: string): CopyOnWriteString: Returns a new CopyOnWriteString with the specified search value replaced.
  • Character access using bracket notation (e.g., str[0]) should be supported.

Notes

  • Focus on the core copy-on-write principle. You don't need to implement all possible string methods. The provided methods are sufficient to demonstrate the concept.
  • Consider how to efficiently share string data between instances when no modification is needed.
  • Think about how to handle edge cases like empty strings and methods that don't modify the string.
  • The valueOf() method is crucial for allowing the CopyOnWriteString to be used in contexts where a regular string is expected (e.g., console.log).
  • You can use JavaScript's built-in string methods within your implementation, but be mindful of the copy-on-write requirement.
Loading editor...
javascript