All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.ikm.tinkar.collection.SpinedIntLongMap Maven / Gradle / Ivy

There is a newer version: 1.79.0
Show newest version
/*
 * Copyright © 2015 Integrated Knowledge Management ([email protected])
 *
 * 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.
 */
package dev.ikm.tinkar.collection;

import dev.ikm.tinkar.common.util.ArrayUtil;

import java.util.Spliterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.function.LongConsumer;
import java.util.function.LongUnaryOperator;
import java.util.function.Supplier;
import java.util.stream.LongStream;
import java.util.stream.StreamSupport;

/**
 *
 *
 */
public class SpinedIntLongMap {
  private static final int DEFAULT_SPINE_SIZE = 1024;
   private final int spineSize;
   private final ConcurrentMap spines = new ConcurrentHashMap<>();
   private final long INITIAL_VALUE = Long.MAX_VALUE;

   public SpinedIntLongMap() {
      this.spineSize = DEFAULT_SPINE_SIZE;
   }

   public int sizeInBytes() {
      int sizeInBytes = 0;
      sizeInBytes = sizeInBytes + ((spineSize * 8) * spines.size()); // 8 bytes = bytes of 64 bit integer
      return sizeInBytes;
   }

   private int getSpineCount() {
      int spineCount = 0;
      for (Integer spineKey:  spines.keySet()) {
         spineCount = Math.max(spineCount, spineKey + 1);
      }
      return spineCount; 
   }
   
   
   private AtomicLongArray newSpine(Integer spineKey) {
      return new AtomicLongArray(ArrayUtil.createAndFill(spineSize, INITIAL_VALUE));
   }

   public void put(int index, long element) {
       if (index < 0) {
           index = Integer.MAX_VALUE + index;
       }
      int spineIndex = index/spineSize;
      int indexInSpine = index % spineSize;
      this.spines.computeIfAbsent(spineIndex, this::newSpine).set(indexInSpine, element);
   }

   public long get(int index) {
       if (index < 0) {
           index = Integer.MAX_VALUE + index;
       }
      int spineIndex = index/spineSize;
      int indexInSpine = index % spineSize;
      return this.spines.computeIfAbsent(spineIndex, this::newSpine).get(indexInSpine);
   }

   public boolean containsKey(int index) {
       if (index < 0) {
           index = Integer.MAX_VALUE + index;
       }
      int spineIndex = index/spineSize;
      int indexInSpine = index % spineSize;
      return this.spines.computeIfAbsent(spineIndex, this::newSpine).get(indexInSpine) != INITIAL_VALUE;
   }
   
   public long getAndUpdate(int index, LongUnaryOperator generator) {
       if (index < 0) {
           index = Integer.MAX_VALUE + index;
       }
      int spineIndex = index/spineSize;
      int indexInSpine = index % spineSize;
      return this.spines.computeIfAbsent(spineIndex, this::newSpine).updateAndGet(indexInSpine, generator);
   }
   
   public void forEach(Processor processor) {
      int currentSpineCount = getSpineCount();
      int key = 0;
      for (int spineIndex = 0; spineIndex < currentSpineCount; spineIndex++) {
         AtomicLongArray spine = this.spines.computeIfAbsent(spineIndex, this::newSpine);
         for (int indexInSpine = 0; indexInSpine < spineSize; indexInSpine++) {
            long value = spine.get(indexInSpine);
            if (value != INITIAL_VALUE) {
               processor.process(key, value);
            }
         }
         key++;
      }
   } 
   
   public interface Processor {
      public void process(int key, long value);
   }   

   public LongStream stream() {
      final Supplier streamSupplier = this.get();

      return StreamSupport.longStream(streamSupplier, streamSupplier.get()
              .characteristics(), false);
   }

   /**
    * Gets the.
    *
    * @return the supplier
    */
   protected Supplier get() {
      return new SpliteratorSupplier();
   }

   /**
    * The Class SpliteratorSupplier.
    */
   private class SpliteratorSupplier
           implements Supplier {

      /**
       * Gets the.
       *
       * @return the spliterator of long
       */
      @Override
      public Spliterator.OfLong get() {
         return new SpinedValueSpliterator();
      }
   }

   private class SpinedValueSpliterator implements Spliterator.OfLong {
      int end;
      int currentPosition;

      public SpinedValueSpliterator() {
          this.end = DEFAULT_SPINE_SIZE * getSpineCount();
        this.currentPosition = 0;
      }
      
      public SpinedValueSpliterator(int start, int end) {
         this.currentPosition = start;
         this.end = end;
      }
      
      @Override
      public Spliterator.OfLong trySplit() {
         int splitEnd = end;
         int split = end - currentPosition;
         int half = split / 2;
         this.end = currentPosition + half;
         return new SpinedValueSpliterator(currentPosition + half + 1, splitEnd);
      }

      @Override
      public boolean tryAdvance(LongConsumer action) {
         while (currentPosition < end) {
            long value = get(currentPosition++);
            if (value != INITIAL_VALUE) {
               action.accept(value);
               return true;
            }
         }
         return false;
      }

      @Override
      public long estimateSize() {
         return end - currentPosition;
      }

      @Override
      public int characteristics() {
          return Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED
                | Spliterator.SIZED;
     }

   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy