Skip to Content

Cirkle - A Circularly-addressable List for Kotlin

A Circularly-addressable List and MutableList for Kotlin

Posted on
Photo by Ricardo Gomez Angel on Unsplash
Photo by Ricardo Gomez Angel on Unsplash

Cirkle!

TL;DR: Cirkle is available on GitHub and as always, I appreciate feedback.

There were several times during the Advent of Code 2017 where I really wanted a List or MutableList that acted like a circle rather than a line. By that I mean I should be able to address it from the right or the left, kind of like I can in Python. So I went ahead and wrote one in Kotlin, and it was easy thanks to delegates and extension functions.

For instance, suppose I want to address the list from the right:

val cirkle = listOf("a", "b", "c").circular()

// Negative addressing:
cirkle[-1] // "c"

// Overly positive addressing:
cirkle[3] // "a"

This works for anything that can be indexed in List and MutableList:

val cirkle = mutableListOf("a", "b", "c").circular()

// Set:
cirkle[-1] = "d" // ["a", "b", "d"]

// SubList:
cirkle.subList(0, -1)  // ["a", "b"]

// Add:
cirkle.add(-1, "d") // ["a", "b", "d", "c"]

// etc (listIterator, addAll...)

Go check it out on GitHub if you find this interesting.

Implementation

Thanks to Kotlin’s Delegation support, implementing this was really easy. First, I created a concrete class that took a List or MutableList as an argument, implemented that interface, and delegated to the instance passed in:

// CircularList.kt

class CircularList<out T>(private val list: List<T>) : List<T> by list {

    override fun get(index: Int): T =
        list[index.safely()]

    // Other overrides removed for brevity.

    private fun Int.safely(): Int =
        if (this < 0) (this % size + size) % size
        else this % size

}

I used a similar approach for the MutableCircularList, and ended up providing extension functions to make creating these more idiomatic:

fun <T> List<T>.circular(): CircularList<T> = CircularList(this)
fun <T> MutableList<T>.circular(): MutableList<T> = MutableCircularList(this)

There are quite a few unit tests to look through, those should give you a complete idea as to Cirkle’s capabilities.

Cirkle is not a large or complicated library, but I had fun making it and I hope somebody out there finds a use for it one day.

Have fun!