Package com.almworks.integers.optimized

Source Code of com.almworks.integers.optimized.SameValuesLongList

/*
* Copyright 2010 ALM Works Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// CODE GENERATED FROM com/almworks/integers/optimized/SameValuesPList.tpl


package com.almworks.integers.optimized;

import com.almworks.integers.AbstractWritableLongList;
import com.almworks.integers.IntLongMap;
import com.almworks.integers.WritableLongListIterator;
import org.jetbrains.annotations.NotNull;

import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;

/**
* This list is memory-optimized to contain values where each value is
* likely to be the same as the previous one. Values are stored as
* a map index_where_value_starts=>value.
* <p/>
* Starting value is 0, that is, if map is empty, all values are 0.
*/
public class SameValuesLongList extends AbstractWritableLongList {
  /**
   * Maps index to the value that starts at that index
   */
  private final IntLongMap myMap;

  public SameValuesLongList() {
    this(new IntLongMap());
  }

  public SameValuesLongList(IntLongMap hostMap) {
    assert hostMap.isEmpty() : hostMap;
    myMap = hostMap;
  }

  public long get(int index) {
    assert checkInvariants();
    if (index < 0 || index >= size())
      throw new IndexOutOfBoundsException(index + " " + this);
    int ki = myMap.findKey(index);
    return valueForFind(ki);
  }

  private long valueForFind(int ki) {
    if (ki == -1) {
      // no earlier index
      return 0;
    } else if (ki < 0) {
      // take previous index
      ki = -ki - 2;
    }
    return myMap.getValueAt(ki);
  }

  public void add(long value) {
    assert checkInvariants();
    int sz = size();
    int msz = myMap.size();
    long lastValue = msz == 0 ? 0 : myMap.getValueAt(msz - 1);
    if (value != lastValue) {
      myMap.insertAt(msz, sz, value);
    }
    updateSize(sz + 1);
    assert checkInvariants();
  }

  public void insertMultiple(int index, long value, int count) {
    assert checkInvariants();
    if (count <= 0)
      return;
    int size = size();
    if (index < 0 || index > size)
      throw new IndexOutOfBoundsException(index + " " + this);
    int ki = myMap.findKey(index);
    // will shift all rightward indexes by +count
    int shiftFrom = ki >= 0 ? ki : -ki - 1;
    // previous value before this insertion
    long prevValue = prevValueForFindIndex(ki);
    int sz = myMap.size();
    // we have to adjust first, or insert will fail because keys will conflict
    if (shiftFrom < sz) {
      myMap.adjustKeys(shiftFrom, sz, count);
    }
    // if prevValue == value, then nothing needs to be inserted -- the values will be correct by themselves
    if (prevValue != value) {
      if (ki >= 0 && myMap.getValueAt(ki) == value) {
        // we have inserted the same value as following
        // so "move back" pointer at ki
        myMap.setKey(ki, index);
      } else {
        myMap.insertAt(shiftFrom, index, value);
        // now check if we have inserted in the middle of another range, splitting it in two. add second part if needed.
        if (index < size && ki < 0) {
          myMap.insertAt(shiftFrom + 1, index + count, prevValue);
        }
      }
    }
    updateSize(size + count);
    assert checkInvariants();
  }

  public void expand(int index, int count) {
    assert checkInvariants();
    if (count <= 0)
      return;
    int size = size();
    if (index < 0 || index > size)
      throw new IndexOutOfBoundsException(index + " " + this);
    int ki = myMap.findKey(index);
    // will shift all rightward indexes by +count
    int shiftFrom = ki >= 0 ? ki + 1 : -ki - 1;
    int sz = myMap.size();
    // we have to adjust first, or insert will fail because keys will conflict
    if (shiftFrom < sz) {
      myMap.adjustKeys(shiftFrom, sz, count);
    }
    updateSize(size + count);
    assert checkInvariants();
  }


  public void setRange(int from, int to, long value) {
    assert checkInvariants();

    if (from >= to)
      return;
    int size = size();
    if (from < 0 || to > size)
      throw new IndexOutOfBoundsException(from + " " + to + " " + this);

    int fi = myMap.findKey(from);
    int removeFrom = fi >= 0 ? fi : -fi - 1;
    long prevValue = prevValueForFindIndex(fi);
    int ti = myMap.findKey(to, removeFrom);
    int removeTo = ti >= 0 ? ti + 1 : -ti - 1;
    long nextValue = valueForFind(ti);

    if (removeFrom < removeTo) {
      myMap.removeRange(removeFrom, removeTo);
    }

    int p = removeFrom;
    if (value != prevValue) {
      if (p != 0 || value != 0) {
        myMap.insertAt(p, from, value);
        p++;
      }
    }

    if (to < size && value != nextValue) {
      myMap.insertAt(p, to, nextValue);
    }

    modified();
    assert checkInvariants();
  }

  private long prevValueForFindIndex(int findIndex) {
    return findIndex == -1 || findIndex == 0 ? 0 : myMap.getValueAt(findIndex < 0 ? -findIndex - 2 : findIndex - 1);
  }

  private boolean checkInvariants() {
    assert myMap != null;
    int size = size();
    assert size >= 0 : size;
    long lastValue = 0;
    int lastKey = -1;
    for (int i = 0; i < myMap.size(); i++) {
      int key = myMap.getKey(i);
      long value = myMap.getValueAt(i);
      assert key > lastKey : i + " " + lastKey + " " + key;
      assert value != lastValue : i + " " + value;
      assert key < size : i + " " + key + " " + size;
      lastKey = key;
      lastValue = value;
    }
    return true;
  }


  /**
   * Remove range from the list, keeping optimal structure
   */
  public void removeRange(int from, int to) {
    assert checkInvariants();

    if (from >= to)
      return;
    int size = size();
    if (from < 0 || to > size)
      throw new IndexOutOfBoundsException(from + " " + to + " " + this);
    int count = to - from;

    // fi will hold search result for "from", could be negative
    int fi = myMap.findKey(from);

    // removeFrom is the "insertion point" for "from" - pairs may be removed starting from that place.
    int removeFrom = fi;
    if (removeFrom < 0) {
      removeFrom = -removeFrom - 1;
    }

    // whether to set new boundary (if the end of removed range falls in the middle of current range
    boolean set = false;

    // the value that follows removed range, relevant only if set == true.
    long followingValue = 0;

    // exclusive high boundary for removing pairs from map
    int removeTo;

    if (to == size) {
      // remove all leftover pairs, don't set anything
      removeTo = myMap.size();
    } else {
      // ti will hold search result for "to", could be negative
      // search starts at "removeFrom", because to > from
      int ti = myMap.findKey(to, removeFrom);

      if (ti >= 0) {
        // exact boundary is found: don't set new boundary, remove everything up to this boundary
        removeTo = ti;
      } else {
        if (ti == -1) {
          // removal within leading zeroes
          removeTo = 0;
        } else {
          // will remove all up to the last boundary
          // removeTo is guaranteed to be less than myMap.size()
          removeTo = -ti - 2;
          followingValue = myMap.getValueAt(removeTo);

          // compare preceding and following values: if they are equal, don't set boundary - just remove
          long prevValue = prevValueForFindIndex(fi);
          if (followingValue != prevValue)
            set = true;
          else
            removeTo++;
        }
      }
    }

    // remove if needed
    if (removeFrom < removeTo) {
      myMap.removeRange(removeFrom, removeTo);
    }

    // pairs at "removeTo" are now at "removeFrom"
    if (set) {
      // set new boundary
      myMap.setAt(removeFrom, from, followingValue);
      removeFrom++;
    }
    /*else if (removeFrom < myMap.size()) {
      // check if we can collapse adjacent pairs with the same value
      int v = myMap.getValueAt(removeFrom);
      if (removeFrom == 0 && v == 0 || removeFrom > 0 && myMap.getValueAt(removeFrom - 1) == v) {
        myMap.removeAt(removeFrom);
      }
    }*/

    // decrement indexes that follow removed range
    myMap.adjustKeys(removeFrom, myMap.size(), -count);

    updateSize(size - count);
    assert checkInvariants();
  }

  @NotNull
  public WritableLongListIterator iterator(int from, int to) {
    if (from > to || from < 0 || to > size())
      throw new IndexOutOfBoundsException(from + " " + to + " " + this);
    return new SameValuesIterator(from, to);
  }

  public void clear() {
    myMap.clear();
    updateSize(0);
  }

  public int getChangeCount() {
    return myMap.size();
  }

  public int getNextDifferentValueIndex(int curIndex) {
    if (curIndex < 0 || curIndex >= size())
      throw new IndexOutOfBoundsException(curIndex + " " + this);
    int ki = myMap.findKey(curIndex);
    // find key ki for the index from which start the values equal to a[curIndex]
    if(ki < 0) ki = -ki - 2;
   // return index for the next differing value increasing the found key or -1 if the key todo[sank] text
    ++ki;
    return ki < myMap.size() ? myMap.getKey(ki) : -1;
  }


  private final class SameValuesIterator extends WritableIndexIterator {
    private IntLongMap.Iterator myIterator;
    private long myValue;
    private int myNextChangeIndex;

    public SameValuesIterator(int from, int to) {
      super(from, to);
      sync();
    }

    protected void sync() {
      super.sync();
      int p = myMap.findKey(getNextIndex());
      if (p == -1) {
        myValue = 0;
        myIterator = myMap.iterator();
      } else {
        if (p < 0)
          p = -p - 2;
        myIterator = myMap.iterator(p);
        myIterator.next();
        myValue = myIterator.value();
      }
      advanceToNextChange();
    }

    private void advanceToNextChange() {
      if (myIterator.hasNext()) {
        myIterator.next();
        myNextChangeIndex = myIterator.key();
      } else myNextChangeIndex = size();
    }

    public long next() throws ConcurrentModificationException, NoSuchElementException {
      checkMod();
      if (getNextIndex() >= getTo())
        throw new NoSuchElementException();
      if (getNextIndex() == myNextChangeIndex) {
        myValue = myIterator.value();
        advanceToNextChange();
      }
      setNext(getNextIndex() + 1);
      return myValue;
    }

    public void move(int count) throws ConcurrentModificationException, NoSuchElementException {
      super.move(count);
      if (count != 0)
        sync();
    }
  }
}
TOP

Related Classes of com.almworks.integers.optimized.SameValuesLongList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.