# TailHashMap.java

    /*
    ** Module   : TailHashMap.java
    ** Abstract : Dictionary that supports registering new items in a new dictionary while iterating.
    **
    ** Copyright (c) 2022, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- --JPRM-- ----------------------------Description----------------------------
    ** 001 TW  20220617          Initial implementation.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.util;

    import java.util.*;
    import static com.goldencode.p2j.util.TailMapInternal.*;

    /**
     * A dictionary that supports registering new items in a
     * new Map tail while iterating the collection.
     *
     * @param   <K>
     *          Dictionary key type
     * @param   <V>
     *          Dictionary value type
     */
    public class TailHashMap<K, V>
    extends HashMap<K, V>
    implements TailMapInternal<K, V>
    {

       /** Generated version UID */
       private static final long serialVersionUID = 4071035589841218096L;

       /** Flag iterating state */
       private boolean iteratingActive = false;

       /** Prevents nested use of IteratingActive */
       private AutoCloseable iteratingActiveSegment = null;

       /**
        * If {@link #iteratingActive} is true, new items
        * are added to {@link #tailingMap}, since adding while iterating is
        * prohibited.
        * Use {@link #pop} to take control of this tail dictionary.
        * The caller is responsible for iterating the tail.
        */
       private Map<K, V> tailingMap = null;

       /**
        * Default constructor.
        */
       public TailHashMap()
       {
          super();
       }

       /**
        * Constructor with expected maximum size.
        *
        * @param expectedMaxSize
        *        The expected maximum size of the hash map.
        */
       public TailHashMap(int expectedMaxSize)
       {
          super(expectedMaxSize);
       }

       /**
        * Do a 'pop' of the single tail dictionary.
        * The caller is responsible for iterating it.
        *
        * @return   <code>null</code> if no tail map present, otherwise a map with at least one item.
        */
       public Map<K, V> pop()
       {
          Map<K, V> ret = tailingMap;
          tailingMap = null;
          return ret;
       }

       /**
        * Add or replace a key value pair at this key.
        *
        * @return   <code>V</code>
        */
       @Override
       public V put(K key, V value)
       {
          return putAtDefault(this, key) ?
                 super.put(key, value) :
                 getOrCreateTailingMap().put(key, value);
       }

       /**
        * Reports if this dictionary has the "being iterated" flag.
        *
        * @return   <code>true</code> if this dictionary is being iterated.
        */
       public boolean isIteratingActive()
       {
          return iteratingActive;
       }

       /**
        * The caller is responsible for setting the iterating active flag, by
        * implementing a <code>try(AutoCloseable obj = dict.flagIterating())</code>
        * block.
        *
        * @return  a new AutoClosable object.
        */
       public AutoCloseable flagIterating()
       {
          if (iteratingActiveSegment != null)
          {
             throw new UnsupportedOperationException();
          }
          iteratingActiveSegment = new TailMapAutoClosable<>(this);
          return iteratingActiveSegment;
       }

       /**
        * Sets the iterating active flag
        *
        * @param   iteratingActive
        *          Iterating active true or false.
        */
       @Override
       public void setIteratingActive(boolean iteratingActive)
       {
          this.iteratingActive = iteratingActive;
       }

       /**
        * Sets the auto-closable object, which may be set once as soon as the iterating active flag becomes true.
        *
        * @param   iteratingActiveSegment
        *          Pass the auto-closable object at the instant the iterating active flag becomes true.
        *          Pass <code>null</code> as soon as the iterating active flag becomes false.
        */
       @Override
       public void setIteratingActiveSegment(AutoCloseable iteratingActiveSegment)
       {
          this.iteratingActiveSegment = iteratingActiveSegment;
       }

       /**
        * Get the tail map. Create it if not present.
        *
        * @return   {@link #tailingMap}.
        */
       private Map<K, V> getOrCreateTailingMap()
       {
          if (tailingMap == null)
          {
             tailingMap = new HashMap<>(4);
          }
          return tailingMap;
       }
    }