This repository has been archived on 2024-02-08. You can view files and clone it, but cannot push or open issues or pull requests.
Gleb Koval e2764a5473
All checks were successful
Main Workflow / Lint and test library (push) Successful in 16m40s
Initial library implementations and tests (#1)
- [x] Implements library according to instructions, with tests.
- [x] GitHub Actions workflow to lint and test library.

Reviewed-on: #1
2023-12-01 20:42:07 +00:00

92 lines
2.8 KiB
Kotlin

package tinyvm
class HashCollisionException(hash: String) : Exception("Different object types with identical hash '$hash'")
class CommitTimeComparator : Comparator<Commit> {
override fun compare(
o1: Commit,
o2: Commit,
): Int = (o1.timestamp.epochSecond - o2.timestamp.epochSecond).toInt()
}
class Repository {
private val commits = sortedSetOf(CommitTimeComparator())
// Store all objects in one map like git does. This would simplify the data persistence implementation (if there was
// one) and allows for other objects to be added in the future without modifying the data persistence implementation
// at all.
private val objects = mutableMapOf<String, Object>()
/**
* (Deep) get or put a commit object into the repository.
* This will also get or put all child trees and blobs.
*/
fun commit(commit: Commit): Commit {
val hash = commit.hash()
val obj = findObject<Commit>(hash)
if (obj != null) return obj
val newCommit =
Commit(
tree = addTree(commit.tree),
author = commit.author,
message = commit.message,
timestamp = commit.timestamp,
)
objects[hash] = newCommit
commits.add(newCommit)
return newCommit
}
/**
* Get a commit by its hash.
*/
fun getCommit(hash: String): Commit? = findObject<Commit>(hash)
/**
* List all commits.
*/
fun listCommits(): List<Commit> = commits.toList()
/**
* Find commit.
*/
fun findCommit(predicate: (Commit) -> Boolean): Commit? = commits.find(predicate)
/**
* Dump repository objects
*/
fun dumpObjects(): Map<String, Object> = objects
/**
* (Deep) get or put a tree object into the repository.
* This will also get or put all child trees and blobs.
*/
private fun addTree(tree: Tree): Tree {
val hash = tree.hash()
val obj = findObject<Tree>(hash)
if (obj != null) return obj
val newTree =
Tree(
tree.nodes.map { (name, node) ->
when (node) {
is Tree -> name to addTree(node)
is Blob -> name to addObject(node)
}
}.toMap(),
)
objects[hash] = newTree
return tree
}
/**
* (Shallow) get or put an object into the repository.
*/
private inline fun <reified T : Object> addObject(obj: T): T =
objects.getOrPut(obj.hash()) { obj } as? T ?: throw HashCollisionException(obj.hash())
/**
* Find an object in the repository by its hash.
*/
private inline fun <reified T : Object> findObject(hash: String): T? =
objects[hash]?.let { it as? T ?: throw HashCollisionException(hash) }
}