content: // Copyright (c) 2023 Kodeco Inc.
  // For full license & permission details, see LICENSE.
  
  abstract interface class Queue<E> {
    bool enqueue(E element);
    E? dequeue();
    bool get isEmpty;
    E? get peek;
  }
  
  class QueueList<E> implements Queue<E> {
    final _list = <E>[];
  
    @override
    bool enqueue(E element) {
      _list.add(element);
      return true;
    }
  
    @override
    E? dequeue() => (isEmpty) ? null : _list.removeAt(0);
  
    @override
    bool get isEmpty => _list.isEmpty;
  
    @override
    E? get peek => (isEmpty) ? null : _list.first;
  
    @override
    String toString() => _list.toString();
  }
  
  class QueueStack<E> implements Queue<E> {
    final _leftStack = <E>[];
    final _rightStack = <E>[];
  
    @override
    bool enqueue(E element) {
      _rightStack.add(element);
      return true;
    }
  
    @override
    E? dequeue() {
      if (_leftStack.isEmpty) {
        _leftStack.addAll(_rightStack.reversed);
        _rightStack.clear();
      }
      if (_leftStack.isEmpty) return null;
      return _leftStack.removeLast();
    }
  
    @override
    bool get isEmpty => _leftStack.isEmpty && _rightStack.isEmpty;
  
    @override
    E? get peek => _leftStack.isNotEmpty ? _leftStack.last : _rightStack.first;
  
    @override
    String toString() {
      final combined = [
        ..._leftStack.reversed,
        ..._rightStack,
      ].join(', ');
      return '[$combined]';
    }
  }
  