Bag.java

/**
* Copyright 2010,2021 Nikolas S Boyd.
Permission is granted to copy this work provided this copyright statement is retained in all copies.

*/
package Hoot.Collections;

import Hoot.Runtime.Functions.*;
import Hoot.Runtime.Faces.*;
import Hoot.Runtime.Values.*;
import Hoot.Runtime.Blocks.*;
import Smalltalk.Core.*;
import Smalltalk.Blocks.*;
import Smalltalk.Magnitudes.*;
import Hoot.Behaviors.*;
import Hoot.Behaviors.Nil;
import Hoot.Behaviors.Object;
import Hoot.Behaviors.True;
import Hoot.Behaviors.False;
import Hoot.Behaviors.Boolean;
import Hoot.Magnitudes.*;
import Hoot.Magnitudes.Integer;
import Hoot.Magnitudes.Character;
import Hoot.Magnitudes.Float;
import Hoot.Magnitudes.Double;
import java.util.Arrays;
import Hoot.Behaviors.Ordered;
import Hoot.Magnitudes.Integer;
import Hoot.Magnitudes.FastInteger;
import Hoot.Streams.WriteStream;
import Smalltalk.Blocks.*;
import Smalltalk.Core.Subject;
import Smalltalk.Collections.*;
import Smalltalk.Magnitudes.Ordinal;

public class Bag<ElementType extends Magnitude> extends Collection<ElementType> implements CollectedBaggage<ElementType>
{

  public static Metaclass type() { return (Metaclass)Metaclass.$class; }
  @Override public Metaclass $class() { return (Metaclass)Metaclass.$class; }
  public static class Metaclass extends Collection.Metaclass implements CollectedBaggage.Metatype
  {
    static final Bag.Metaclass $class = new Bag.Metaclass();
    public Metaclass() {
      this(Bag.Metaclass.class);
    }

    public Metaclass(java.lang.Class aClass) {
      super(aClass);
    }

    @Override public java.lang.Class outerClass() { return Bag.class; }


    /**
     * @return 
     */
    @Override public   Bag $new()
    {
      java.lang.String exitID = "BagMetatype>>$new";
      Frame f0 = new Frame(exitID);
      return f0.evaluate(() -> {
      return (Bag)f0.exit(exitID, this.$new(SmallInteger.from(10)));
      });
    }

    /**
     * @return 
     */
    @Override public   Bag $new(final Ordinal capacity)
    {
      java.lang.String exitID = "BagMetatype>>$new";
      Frame f0 = new Frame(exitID);
      return f0.evaluate(() -> {
      return (Bag)f0.exit(exitID, new Bag(capacity));
      });
    }
  }


  protected Dictionary<ElementType, Integer> contents = new Dictionary();

  /**
   * @return 
   */
  protected   Dictionary contents()
  {
    java.lang.String exitID = "Bag>>contents";
    Frame f0 = new Frame(exitID);
    return (Dictionary)contents;
  }

  /**
   * 
   */
  protected    Bag()
  {
    java.lang.String exitID = "Bag>>Bag";
    Frame f0 = new Frame(exitID);
  }

  /**
   * 
   */
  protected    Bag(final Ordinal capacity)
  {
    java.lang.String exitID = "Bag>>Bag";
    Frame f0 = new Frame(exitID);
     contents = new Dictionary(((Integer)capacity));
  }

  /**
   * @return 
   */
  @Override public   Integer size()
  {
    java.lang.String exitID = "Bag>>size";
    Frame f0 = new Frame(exitID);
    return (Integer)contents.size();
  }

  /**
   * @return 
   */
  @Override public   Integer occurrencesOf(final Subject element)
  {
    java.lang.String exitID = "Bag>>occurrencesOf";
    Frame f0 = new Frame(exitID);
    return (Integer)contents.at_ifAbsent(((ElementType)element), Closure.with(f2 -> {
      return SmallInteger.from(0);
    }, ""));
  }

  /**
   * @return 
   */
  public   ElementType add(final ElementType element)
  {
    java.lang.String exitID = "Bag>>add";
    Frame f0 = new Frame(exitID);
    contents.at_put(element, (SmallInteger.from(1).plus(this.occurrencesOf(element))));
    return (ElementType)element;
  }

  /**
   * @return 
   */
  public   ElementType add_withOccurrences(final ElementType element, final Ordinal count)
  {
    java.lang.String exitID = "Bag>>add_withOccurrences";
    Frame f0 = new Frame(exitID);
    contents.at_put(element, ((Integer)count));
    return (ElementType)element;
  }

  /**
   * @return 
   */
  public   Collected<ElementType> addAll(final Collected<ElementType> elements)
  {
    java.lang.String exitID = "Bag>>addAll";
    Frame f0 = new Frame(exitID);
    elements.$do(Closure.with(f2 -> {
      ElementType element = f2.getValue(0).value();
      return this.add(element);
    }, "element"));
    return (Collected<ElementType>)elements;
  }

  /**
   * @return 
   */
  public   Collected<ElementType> addAll(final ElementType ... elements)
  {
    java.lang.String exitID = "Bag>>addAll";
    Frame f0 = new Frame(exitID);
    return (Collected<ElementType>)this.addAll(Set.from(Arrays.asList(elements)));
  }

  /**
   * @return 
   */
  @Override public   Boolean equals(final Collected aCollection)
  {
    java.lang.String exitID = "Bag>>equals";
    Frame f0 = new Frame(exitID);
    return (Boolean)(this.equals(aCollection.asBag()));
  }

  /**
   * @return 
   */
  public   Boolean equals(final CollectedBaggage<ElementType> aBag)
  {
    java.lang.String exitID = "Bag>>equals";
    Frame f0 = new Frame(exitID);
    return (Boolean)(contents.equals(((Bag)aBag).contents()));
  }

  /**
   * @return 
   */
  @Override public   int hashCode()
  {
    java.lang.String exitID = "Bag>>hashCode";
    Frame f0 = new Frame(exitID);
    return (int)contents.hashCode();
  }

  /**
   * @return 
   */
  @Override public   Bag asBag()
  {
    java.lang.String exitID = "Bag>>asBag";
    Frame f0 = new Frame(exitID);
    return (Bag)this;
  }

  /**
   * @return 
   */
  @Override public   Set asSet()
  {
    java.lang.String exitID = "Bag>>asSet";
    Frame f0 = new Frame(exitID);
    return (Set)contents.keys();
  }

  /**
   * @return 
   */
  public   Bag removeAll()
  {
    java.lang.String exitID = "Bag>>removeAll";
    Frame f0 = new Frame(exitID);
    contents.removeAll();
    return (Bag)this;
  }

  /**
   * @return 
   */
  public   ElementType remove(final ElementType element)
  {
    java.lang.String exitID = "Bag>>remove";
    Frame f0 = new Frame(exitID);
    return (ElementType)this.remove_ifAbsent(element, Closure.with(f2 -> {
      this.elementNotFound();
    return Nil.literal();
    }, ""));
  }

  /**
   * @return 
   */
  public   ElementType remove_ifAbsent(final ElementType element, final NiladicValuable aBlock)
  {
    java.lang.String exitID = "Bag>>remove_ifAbsent";
    Frame f0 = new Frame(exitID);
    return f0.evaluate(() -> {
    FastInteger count = FastInteger.fromInteger(this.occurrencesOf(element));
    (count.equals(SmallInteger.from(0))).ifTrue(Closure.with(f2 -> {
      return (ElementType)f0.exit(exitID, aBlock.value());
    }, ""));
    (count.equals(SmallInteger.from(1))).ifTrue_ifFalse(Closure.with(f2 -> {
      return contents.removeKey(element);
    }, ""), Closure.with(f2 -> {
      return count.subtract(SmallInteger.from(1));
    }, ""));
    return (ElementType)f0.exit(exitID, element);
    });
  }

  /**
   * @return 
   */
  public   Collected<ElementType> removeAll(final ElementType ... elements)
  {
    java.lang.String exitID = "Bag>>removeAll";
    Frame f0 = new Frame(exitID);
    return (Collected<ElementType>)this.removeAll(OrderedCollection.type().from(Utils.wrap(elements)));
  }

  /**
   * @return 
   */
  public   Collected<ElementType> removeAll(final Collected<ElementType> elements)
  {
    java.lang.String exitID = "Bag>>removeAll";
    Frame f0 = new Frame(exitID);
    elements.$do(Closure.with(f2 -> {
      ElementType element = f2.getValue(0).value();
      return this.remove(element);
    }, "element"));
    return (Collected<ElementType>)elements;
  }

  /**
   * @return 
   */
  public   Set<ElementType> removeAllSuchThat(final MonadicPredicate criteria)
  {
    java.lang.String exitID = "Bag>>removeAllSuchThat";
    Frame f0 = new Frame(exitID);
    Set<ElementType> results = Set.type().$new();
    this.$do(Closure.with(f2 -> {
      ElementType element = f2.getValue(0).value();
      criteria.value(element).ifTrue(Closure.with(f3 -> {
      results.add(element);
    this.remove(element);
    }, ""));
    }, "element"));
    return (Set<ElementType>)results;
  }

  /**
   * @return 
   */
  @Override public   Bag $do(final MonadicValuable aBlock)
  {
    java.lang.String exitID = "Bag>>$do";
    Frame f0 = new Frame(exitID);
    contents.keysAndValuesDo(Closure.with(f2 -> {
      ElementType element = f2.getValue(0).value();
      Integer count = f2.getValue(1).value();
      count.timesRepeat(Closure.with(f3 -> {
      aBlock.value(element);
    }, ""));
    }, "element", "count"));
    return (Bag)this;
  }

  /**
   * @return 
   */
  public   WriteStream writeStream()
  {
    java.lang.String exitID = "Bag>>writeStream";
    Frame f0 = new Frame(exitID);
    return (WriteStream)WriteStream.type().with(this);
  }
}