Skip to content

Poweranimal/PowerCollections

Repository files navigation

PowerCollections

PowerCollections is a library with a set of useful Collections, Sets, Lists and Maps primary designed for the SDK / API development. It's entirely written in Kotlin.

Table of Contents

Contents

Name Description
BiMap Map with unique keys and unique values
BoundedList List with a max size of elements
BoundedMap Map with a max size of entries
ObservableList List that observes all content altering commands
ObservableMap Map that observes all content altering commands
WeakCollection Collection that wraps all elements in WeakReferences
WeakSet Set that wraps all elements in WeakReferences

Samples

BiMap

A Map with unique keys and unique values.

 // Creates the BiMap
 val biMap = BiMap<Int, String> by PowerCollections.biMap()
 
 biMap.put(0, "Hello") // adds the entry 0=Hello
 
 biMap.put(0, "World") // replaces the old value with the new value 0=World
 
 /*
 In this case, "World" would be twice in the map as value. 
 Hence, an exception is thrown, because every value must be unique. 
  */
 biMap.put(1, "World") // Throws IllegalArgumentException
 
 println(biMap) // {0=World}
 
 /*
 If you want to add the "Hello" value anyways, call this.
 It adds the new entry 1=World and removes the entry, that already contains "World".
 In this case, the entry 0=World gets removed.
 */
 biMap.forcePut(1, "World") // adds 1=World and removes 0=World
 
 println(biMap) // {1=World}
 
 val inversedBiMap = biMap.inverse // returns a new BiMap with inversed entries
 
 println(inversedBiMap) // {World=1}

BiMap extends from Map. You can do:

 val mutableBiMap: MutableBiMap<Int, String> by PowerCollections.biMap()
 
 val biMap: BiMap<Int, String> by PowerCollections.biMap()
 
 val mutableMap: MutableMap<Int, String> by PowerCollections.biMap()
 
 val map: Map<Int, String> by PowerCollections.biMap()

BiMap supports "kotlin-like" map initialization.

 val mutableBiMap = mutableBiMapOf()
  
 val boundedList = biMapOf()

BoundedList

A List with a max size of n-elements.

 /*
 Creates a list with a max size of 2 elements.
 */
 val boundedList: MutableBoundedList<String> by PowerCollections.boundedList(2)

 boundedList.addAll(listOf("hello", "world"))

 /*
 If the max capacity is going to be exceeded, an IndexOutOfBoundsException will be thrown.
 */
 boundedList.add("foo")

 /*
 If the max capacity is reached, additional elements can be added in the following way.
 This will remove the element at the head of the list (the eldest element) and adds the new element to the tail.  
 */
 boundedList.forceAdd("bar")
 
 println(boundedList) // [world, bar]
 
 boundedList.resize(3) // Changes the max size to 3 elements.
 
 boundedList.resize(1) // Resizing would loose elements. An IllegalStateException will be thrown.
 
 /*
 If the new max size is smaller than the current size, all elements at the head are going to be removed, until 
 the new max size is equal to the list's size.
 */
 boundedList.forceResize(1)
 
 println(boundedList) // [bar]

BoundedList extends from List. You can do:

 val mutableBoundedList: MutableBoundedList<String> by PowerCollections.boundedList(2)
  
 val boundedList: BoundedList<String> by PowerCollections.boundedList(2)
  
 val mutableList: MutableList<String> by PowerCollections.boundedList(2)
  
 val list: List<String> by PowerCollections.boundedList(2)

BoundedList supports "kotlin-like" list initialization.

 val mutableBoundedList = mutableBoundedListOf(2)
  
 val boundedList = boundedListOf(2)

BoundedMap

A Map with a max size of n-entries.

 /*
 Creates a map with a max size of 2 entries.
 */
 val boundedMap: MutableBoundedMap<Int, String> by PowerCollections.boundedMap(2)

 boundedMap.putAll(mapOf(0 to "hello", 1 to "world"))

 /*
 If the max capacity is going to be exceeded, an IndexOutOfBoundsException will be thrown.
 */
 boundedMap.put(2 to "foo")

 /*
 If the max capacity is reached, additional entries can be added in the following way.
 This will remove the entry at the head of the map (the eldest entry) and adds the new entry to the tail.  
 */
 boundedMap.forcePut(3 to "bar")
 
 println(boundedMap) // {0="world", 3="bar"}
 
 boundedMap.resize(3) // Changes the max size to 3 entries.
 
 boundedMap.resize(1) // Resizing would loose entries. An IllegalStateException will be thrown.
 
 /*
 If the new max size is smaller than the current size, all entries at the head are going to be removed, until 
 the new max size is equal to the map's size.
 */
 boundedMap.forceResize(1)
 
 println(boundedMap) // {3="bar"}

BoundedMap extends from Map. You can do:

 val mutableBoundedMap: MutableBoundedMap<Int, String> by PowerCollections.boundedMap(2)
  
 val boundedMap: BoundedMap<Int, String> by PowerCollections.boundedMap(2)
  
 val mutableMap: MutableMap<Int, String> by PowerCollections.boundedMap(2)
  
 val map: Map<Int, String> by PowerCollections.boundedList(2)

BoundedMap supports "kotlin-like" map initialization.

 val mutableBoundedMap = mutableBoundedMapOf(2)
  
 val boundedMap = boundedMapOf(2)

ObservableList

A List that observes all content altering commands.

/*
 Creates a list with a delegate that listens to any altering commands.
 You don't have to implement all listening methods. However, if a not implemented method gets triggered, 
 a NotImplementedException gets thrown. To avoid this exception, set 'safetyMode' to 'false'.
 */
 val observableList: MutableObservableList<String> by PowerCollections.observableList {
    
    //If false, no NotImplementedException gets thrown.
    safetyMode = false
    
    // Triggered for all 'add' commands.
    wasAdded { index, element ->
        println("added $element at $index")
    }
    // Triggered for all 'addAll' commands.
    wasAdded { elements ->
        println("added $elements")
    }
    // Triggered for all 'remove' commands.
    wasRemoved { index, element ->
        println("removed $element at $index")
    }
    // Triggered for all 'removeAll' commands.
    wasRemoved { elements ->
        println("removed $elements")
    }
    // Triggered for all 'set' commands.
    wasReplaced { index, oldElement, newElement ->
        println("replaced $oldElement with $newElement at $index")
    }
    // Triggered for all 'setAll' commands.
    wasReplaced { map ->
        println("Replaced $map")
    }
 }

 observableList.addAll(listOf("hello", "world")) // prints: "added [hello, world]"

 observableList.add("foo") // prints "added foo at 2"

You can manually inform ObservableList, if changes are made inside a class.

 data class MyClass(var tag: String)

 val observableList: MutableObservableList<MyClass> by PowerCollections.observableList {
    
    safetyMode = false
    
    notifyDataChanged {
        println("data changed")
    }
    notifyDataChangedByIndex { index ->
        println("data changed at $index")
    }
 }
 
 val myClass = MyClass("Hello World")
 
 observableList.add(myClass)
 
 myClass.tag = "foo bar"
 
 observableList.notifyDataChanged(0) // prints: "data changed at 0"

ObservableList extends from List. You can do:

 val mutableObservableList: MutableObservableList<String> by PowerCollections.observableList { }
  
 val observableList: ObservableList<String> by PowerCollections.observableList { }
  
 val mutableList: MutableList<String> by PowerCollections.observableList { }
  
 val list: List<String> by PowerCollections.observableList { }

ObservableList supports "kotlin-like" list initialization.

 val mutableObservableList = mutableObservableListOf { }
  
 val observableList = observableListOf { }

ObservableMap

A Map that observes all content altering commands.

/*
 Creates a map with a delegate that listens to any altering commands.
 You don't have to implement all listening methods. However, if a not implemented method gets triggered, 
 a NotImplementedException gets thrown. To avoid this exception, set 'safetyMode' to 'false'.
 */
 val observableMap: MutableObservableMap<Int, String> by PowerCollections.observableMap {
    
    //If false, no NotImplementedException gets thrown.
    safetyMode = false
    
    // Triggered for all 'put' commands.
    wasAdded { key, value ->
        println("added $value at $key")
    }
    // Triggered for all 'putAll' commands.
    wasAdded { entries ->
        println("added $entries")
    }
    // Triggered for all 'remove' commands.
    wasRemoved { key, value ->
        println("removed $value at $key")
    }
    // Triggered for all 'removeAll' commands.
    wasRemoved { entries ->
        println("removed $entries")
    }
    // Triggered for all 'put' commands that are replacing.
    wasReplaced { key, oldValue, newValue ->
        println("replaced $oldValue with $newValue at $key")
    }
    // Triggered for all 'putAll' commands that are replacing.
    wasReplaced { entries ->
        println("Replaced $entries")
    }
 }

 observableMap.putAll(mapOf(0 to "hello", 1 to "world")) // prints: "added {0=hello, 1=world}"

 observableMap.put(1 to "foo") // prints "replaced world with foo at 2"

You can manually inform ObservableMap, if changes are made inside a class.

 data class MyClass(var tag: String)

 val observableMap: MutableObservableMap<Int, MyClass> by PowerCollections.observableMap {
    
    safetyMode = false
    
    notifyDataChanged {
        println("data changed")
    }
    notifyDataChangedByKey { key ->
        println("data changed at $key")
    }
 }
 
 val myClass = MyClass("Hello World")
 
 observableMap.put(10 to myClass)
 
 myClass.tag = "foo bar"
 
 observableMap.notifyDataChanged(10) // prints: "data changed at 10"

ObservableMap extends from Map. You can do:

 val mutableObservableMap: MutableObservableMap<Int, String> by PowerCollections.observableMap { }
  
 val observableMap: ObservableMap<Int, String> by PowerCollections.observableMap { }
  
 val mutableMap: MutableMap<Int, String> by PowerCollections.observableMap { }
  
 val map: Map<Int, String> by PowerCollections.observableMap { }

ObservableMap supports "kotlin-like" map initialization.

 val mutableObservableMap = mutableObservableMapOf { }
  
 val observableMap = observableMapOf { }

WeakCollection

A Collection that wraps all elements in WeakReferences.

object MyGlobalClient {
    /*
    All classes that registered their 'MyListener' to 'MyGlobalClient' can be garbage collected, 
    if not needed anymore.
    Hence, 'MyGlobalClient' doesn't prevent the garbage collector from collecting.
    */
    val myListeners: MutableWeakCollection<MyListener?> by PowerCollections.weakCollection()
    
    fun processMyInterfaces() {
    
        /*
        Only processes not garbage collected elements. 
        Garbage collected items are temporarily stored in the collections as null-values.
        Those will be automatically removed out of the collection.
        */
        myListeners.forEach { it?.doSomething() }
        
        /*
        Manually deletes all garbage collected elements (stored as null-value) from
        the collection. Normally it's not needed to call this method.
        */
        myListeners.optimze()
        
        /*
        Manually forces to delete all garbage collected elements (stored as null-value) from
        the collection. Normally it's not needed to call this method.
        */
        myListeners.forceOptimze()
    }
}

WeakCollection extends from Collection. You can do:

 val mutableWeakCollection: MutableWeakCollection<MyListener?> by PowerCollections.weakCollection()
  
 val weakCollection: WeakCollection<MyListener?> by PowerCollections.weakCollection()
  
 val mutableCollection: MutableCollection<MyListener?> by PowerCollections.weakCollection()
  
 val collection: Collection<MyListener?> by PowerCollections.weakCollection()

WeakCollection supports "kotlin-like" initialization.

 val mutableWeakCollection = mutableWeakCollectionOf()
  
 val weakCollection = weakCollectionOf()

WeakSet

A Set that wraps all elements in WeakReferences.

object MyGlobalClient {
    /*
    All classes that registered their 'MyListener' to 'MyGlobalClient' can be garbage collected, 
    if not needed anymore.
    Hence, 'MyGlobalClient' doesn't prevent the garbage collector from collecting.
    */
    val myListeners: MutableWeakSet<MyListener?> by PowerCollections.weakSet()
    
    fun processMyInterfaces() {
    
        /*
        Only processes not garbage collected elements. 
        Garbage collected items are temporarily stored in the collections as null-values.
        Those will be automatically removed out of the collection.
        */
        myListeners.forEach { it?.doSomething() }
        
        /*
        Manually deletes all garbage collected elements (stored as null-value) from
        the set. Normally it's not needed to call this method.
        */
        myListeners.optimze()
        
        /*
        Manually forces to delete all garbage collected elements (stored as null-value) from
        the set. Normally it's not needed to call this method.
        */
        myListeners.forceOptimze()
    }
}

WeakSet extends from Set. You can do:

 val mutableWeakSet: MutableWeakSet<MyListener?> by PowerCollections.weakSet()
  
 val weakSet: WeakSet<MyListener?> by PowerCollections.weakSet()
  
 val mutableSet: MutableSet<MyListener?> by PowerCollections.weakSet()
  
 val set: Set<MyListener?> by PowerCollections.weakSet()

WeakSet supports "kotlin-like" set initialization.

 val mutableWeakSet = mutableWeakSetOf()
  
 val weakSet = weakSetOf()

Download

Add it in your root build.gradle at the end of repositories:

Step 1. Add the JitPack repository to your build file

allprojects {
	repositories {
		maven { url 'https://jitpack.io' }
	}
}

Step 2. Add the dependency

dependencies {
	implementation 'com.github.Poweranimal:PowerCollections:0.1.4'
}

License

See here.

 MIT License
 
 Copyright (c) 2018 Felix Pröhl
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.