Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Use distinct XmlStore between saving and loading

AuthorDaveJarvis <email>
Date2022-01-01 13:17:01 GMT-0800
Commita94117117f09abf0677253e0384f00b79086cbcd
Parentabc7d8f
Delta1 line added, 293 lines removed, 292-line decrease
src/test/java/com/keenwrite/util/CircularQueueTest.java
package com.keenwrite.util;
+import com.keenwrite.collections.CircularQueue;
import org.junit.jupiter.api.Test;
src/main/java/com/keenwrite/util/CircularQueue.java
-/* Copyright 2021 White Magic Software, Ltd. -- All rights reserved. */
-package com.keenwrite.util;
-
-import java.util.*;
-
-import static java.lang.Math.min;
-
-/**
- * Responsible for maintaining a circular queue where newly added items will
- * overwrite existing items.
- *
- * <strong>Warning:</strong> This class is not thread-safe.
- *
- * @param <E> The type of elements to store in this collection.
- */
-@SuppressWarnings( "unchecked" )
-public class CircularQueue<E>
- extends AbstractCollection<E> implements Queue<E> {
-
- /**
- * Simplifies the code by reusing an existing list implementation.
- * Initialized with {@code null} values at construction time.
- */
- private final Object[] mElements;
-
- /**
- * Maximum number of elements allowed in the collection before old elements
- * are overwritten. Set at construction time.
- */
- private final int mCapacity;
-
- /**
- * Insertion position when a new element is added. Starts at zero.
- */
- private int mProducer;
-
- /**
- * Retrieval position when the oldest element is removed. Starts at zero.
- */
- private int mConsumer;
-
- /**
- * The number of elements in the collection. This cannot delegate to the
- * {@link #mElements} list. Starts at zero.
- */
- private int mSize;
-
- /**
- * Creates a new circular queue that has a limited number of elements that
- * may be added before newly added elements will overwrite the oldest
- * elements that were added previously.
- * <p>
- * <strong>Warning:</strong> Client classes must take care not to exceed
- * memory limits imposed by the Java Virtual Machine.
- *
- * @param capacity Maximum number elements allowed in the list, must be
- * greater than one.
- */
- public CircularQueue( final int capacity ) {
- assert capacity > 1;
-
- mCapacity = capacity;
- mElements = new Object[ capacity ];
- }
-
- /**
- * Adds an element to the end of the collection. This overwrites the oldest
- * element in the collection when the queue is full. The number of elements,
- * reflected by the return value of {@link #size()} will not exceed the
- * capacity.
- *
- * @param element The item to insert into the collection, must not be
- * {@code null}.
- * @return {@code true} Non-{@code null} items are always added.
- * @throws NullPointerException if the given element is {@code null}.
- * The iterator requires a consecutive
- * non-{@code null} range (no gaps).
- */
- @Override
- public boolean add( final E element ) {
- if( element == null ) {
- throw new NullPointerException();
- }
-
- mElements[ mProducer++ ] = element;
- mProducer %= mCapacity;
- mSize = min( mSize + 1, mCapacity );
-
- return true;
- }
-
- /**
- * Delegates to {@link #add(E)}.
- */
- @Override
- public boolean offer( final E element ) {
- return add( element );
- }
-
- /**
- * Removes the oldest element that was added to the collection. The number
- * of elements reflected by the return value of {@link #size()} will not
- * drop below zero.
- *
- * @return The oldest element.
- * @throws NoSuchElementException The collection is empty.
- */
- @Override
- public E remove() {
- if( isEmpty() ) {
- throw new NoSuchElementException();
- }
-
- final E element = (E) mElements[ mConsumer ];
-
- mElements[ mConsumer++ ] = null;
- mConsumer %= mCapacity;
- mSize--;
-
- return element;
- }
-
- /**
- * Delegates to {@link #remove()}, but does not throw an exception.
- *
- * @return The oldest element.
- */
- @Override
- public E poll() {
- return isEmpty() ? null : remove();
- }
-
- /**
- * Returns the oldest element that was added to the collection.
- *
- * @return The oldest element.
- * @throws NoSuchElementException The collection is empty.
- */
- @Override
- public E element() {
- if( isEmpty() ) {
- throw new NoSuchElementException();
- }
-
- return (E) mElements[ mConsumer ];
- }
-
- /**
- * Delegates to {@link #element()}, but does not throw an exception.
- *
- * @return The oldest element.
- */
- @Override
- public E peek() {
- return isEmpty() ? null : element();
- }
-
- /**
- * Answers how many elements are currently in the collection.
- *
- * @return The number of elements that have been added to but not removed
- * from the collection.
- */
- @Override
- public int size() {
- return mSize;
- }
-
- /**
- * Returns a facility to visit each of the elements in the
- * {@link CircularQueue}. This will start iterating at the oldest element
- * and stop when there are no more elements.
- * <p>
- * The iterator is not thread-safe; concurrent modifications to the number
- * of elements in the {@link CircularQueue} will result in undefined
- * behaviour.
- *
- * @return A new {@link Iterator} instance capable of visiting each element.
- */
- @Override
- public Iterator<E> iterator() {
- return new Iterator<>() {
- private int mIndex = mConsumer;
- private boolean mFirst = true;
-
- @Override
- public boolean hasNext() {
- return (mFirst || mIndex != mConsumer) && mElements[ mIndex ] != null;
- }
-
- @Override
- public E next() {
- final var element = mElements[ mIndex++ ];
- mIndex %= mCapacity;
- mFirst = false;
-
- return (E) element;
- }
- };
- }
-
- @Override
- public String toString() {
- return Arrays.toString( mElements );
- }
-}
src/main/java/com/keenwrite/util/InterpolatingMap.java
-/* Copyright 2021 White Magic Software, Ltd. -- All rights reserved. */
-package com.keenwrite.util;
-
-import com.keenwrite.sigils.SigilKeyOperator;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Responsible for interpolating key-value pairs in a map. That is, this will
- * iterate over all key-value pairs and replace keys wrapped in sigils
- * with corresponding definition value from the same map.
- */
-public class InterpolatingMap extends ConcurrentHashMap<String, String> {
- private static final int GROUP_DELIMITED = 1;
-
- /**
- * Used to override the default initial capacity in {@link HashMap}.
- */
- private static final int INITIAL_CAPACITY = 1 << 8;
-
- private final SigilKeyOperator mOperator;
-
- /**
- * @param operator Contains the opening and closing sigils that mark
- * where variable names begin and end.
- */
- public InterpolatingMap( final SigilKeyOperator operator ) {
- super( INITIAL_CAPACITY );
-
- assert operator != null;
- mOperator = operator;
- }
-
- /**
- * @param operator Contains the opening and closing sigils that mark
- * where variable names begin and end.
- * @param m The initial {@link Map} to copy into this instance.
- */
- public InterpolatingMap(
- final SigilKeyOperator operator, final Map<String, String> m ) {
- this( operator );
- putAll( m );
- }
-
- /**
- * Interpolates all values in the map that reference other values by way
- * of key names. Performs a non-greedy match of key names delimited by
- * definition tokens. This operation modifies the map directly.
- *
- * @return {@code this}
- */
- public Map<String, String> interpolate() {
- for( final var k : keySet() ) {
- replace( k, interpolate( get( k ) ) );
- }
-
- return this;
- }
-
- /**
- * Given a value with zero or more key references, this will resolve all
- * the values, recursively. If a key cannot be de-referenced, the value will
- * contain the key name, including the original sigils.
- *
- * @param value Value containing zero or more key references.
- * @return The given value with all embedded key references interpolated.
- */
- public String interpolate( String value ) {
- assert value != null;
-
- final var matcher = mOperator.match( value );
-
- while( matcher.find() ) {
- final var keyName = matcher.group( GROUP_DELIMITED );
- final var mapValue = get( keyName );
-
- if( mapValue != null ) {
- final var keyValue = interpolate( mapValue );
- value = value.replace( mOperator.apply( keyName ), keyValue );
- }
- }
-
- return value;
- }
-}