├── .gitignore ├── LICENSE.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── alexandrepiveteau │ │ └── distributed │ │ └── sample │ │ └── HomeActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_home.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── distributed-causal-graphs ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── github │ └── alexandrepiveteau │ └── distributed │ └── causalGraphs │ ├── ArrayListCausalGraphYarn.kt │ ├── CausalGraph.common.kt │ ├── CausalGraph.kt │ ├── CausalGraphAtom.kt │ ├── CausalGraphIdentifier.kt │ ├── CausalGraphYarn.common.kt │ ├── CausalGraphYarn.kt │ ├── HashMapCausalGraph.kt │ ├── MutableCausalGraph.common.kt │ ├── MutableCausalGraph.kt │ ├── MutableCausalGraphYarn.common.kt │ └── MutableCausalGraphYarn.kt ├── distributed-cvrdts ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── github │ └── alexandrepiveteau │ └── distributed │ └── cvrdts │ ├── GSet.common.kt │ ├── GSet.kt │ ├── MCSet.common.kt │ ├── MCSet.kt │ ├── PNSet.common.kt │ └── PNSet.kt ├── distributed-woot ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── github │ └── alexandrepiveteau │ └── distributed │ └── woot │ ├── WootElement.kt │ ├── WootIdentifier.kt │ ├── WootList.kt │ ├── WootOperation.kt │ └── WootSequence.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS-specific files 2 | .DS_Store 3 | 4 | # User-specific properties (keys, etc.) 5 | signing.properties 6 | 7 | # Built application files 8 | *.apk 9 | *.ap_ 10 | 11 | # Files for the Dalvik VM 12 | *.dex 13 | 14 | # Java class files 15 | *.class 16 | 17 | # Generated files 18 | bin/ 19 | gen/ 20 | out/ 21 | 22 | # Gradle files 23 | .gradle/ 24 | build/ 25 | 26 | # Local configuration file (sdk path, etc) 27 | local.properties 28 | 29 | # Proguard folder generated by Eclipse 30 | proguard/ 31 | 32 | # Log Files 33 | *.log 34 | 35 | # Android Studio Navigation editor temp files 36 | .navigation/ 37 | 38 | # Android Studio captures folder 39 | captures/ 40 | /captures 41 | 42 | # Intellij 43 | *.idea 44 | /.idea/workspace.xml 45 | /.idea/libraries 46 | *.iml 47 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alexandre Piveteau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # distributed-kotlin 2 | 3 | [![](https://jitpack.io/v/alexandrepiveteau/distributed-kotlin.svg)](https://jitpack.io/#alexandrepiveteau/distributed-kotlin) 4 | 5 | This repository contains some utilies for distributed systems in the Kotlin programming language. 6 | The OSS license can be found in the LICENSE.md file of the repository. 7 | 8 | ## Installation 9 | This library is available on [JitPack.io](https://jitpack.io/#alexandrepiveteau/distributed-kotlin). Make 10 | sure to add the following Maven repository in your root **build.gradle** file : 11 | 12 | ```groovy 13 | allprojects { 14 | repositories { 15 | ... 16 | maven { url 'https://jitpack.io' } 17 | } 18 | } 19 | ``` 20 | 21 | You can now add the library modules in your application **build.gradle** file : 22 | 23 | ```groovy 24 | dependencies { 25 | implementation "com.github.alexandrepiveteau.distributed-kotlin:distributed-causal-graphs:1.1.0" 26 | implementation "com.github.alexandrepiveteau.distributed-kotlin:distributed-cvrdts:1.1.0" 27 | implementation "com.github.alexandrepiveteau.distributed-kotlin:distributed-woot:1.1.0" 28 | } 29 | ``` 30 | 31 | ## Usage 32 | The library contains the following modules : 33 | 34 | - **distributed-causal-graphs** - An implementation of **causal graphs**, including `CausalGraph` and `CausalGraphYarn` with their mutable counterparts. 35 | - **distributed-cvrdts** - An implementation of some popular **CvRDTs**, including `GSet`, `PNSet` and `MCSet`. 36 | - **distributed-woot** - An implementation of the **Woot** linear data structure. 37 | 38 | ### distributed-cvrdts 39 | 40 | The library offers multiple **CvRDT** data structures. Each data type is a state-based CRDT. Essentially, the `GSet`, `PNSet` and `MCSet` classes all implement the `Set` interface. Each of these data type is immutable, and multiple CRDTs of the same type can be merged by using their `merge(...)` function. 41 | 42 | Here is an example of usage for the `MCSet` data type : 43 | 44 | ```kotlin 45 | var first: MCSet = emptyMCSet() 46 | var second: MCSet = emptyMCSet() 47 | 48 | first += "Alice" 49 | first += "Bob" 50 | first -= "Bob" 51 | second += "Bob" 52 | second += "Charlie" 53 | 54 | val merged = first.merge(second) // Contains "Alice" and "Charlie". 55 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'com.android.application' 26 | apply plugin: 'kotlin-android' 27 | 28 | android { 29 | compileSdkVersion 28 30 | defaultConfig { 31 | applicationId "com.github.alexandrepiveteau.distributed.sample" 32 | minSdkVersion 15 33 | targetSdkVersion 28 34 | versionCode 1 35 | versionName "1.1.0" 36 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 37 | } 38 | buildTypes { 39 | release { 40 | minifyEnabled false 41 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 42 | } 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation fileTree(dir: 'libs', include: ['*.jar']) 48 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.0" 49 | implementation 'androidx.appcompat:appcompat:1.0.2' 50 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' 51 | implementation project(':distributed-causal-graphs') 52 | implementation project(':distributed-cvrdts') 53 | implementation project(':distributed-woot') 54 | } 55 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/alexandrepiveteau/distributed/sample/HomeActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.sample 26 | 27 | import androidx.appcompat.app.AppCompatActivity 28 | import android.os.Bundle 29 | import com.github.alexandrepiveteau.distributed.cvrdts.MCSet 30 | import com.github.alexandrepiveteau.distributed.cvrdts.emptyMCSet 31 | 32 | class HomeActivity : AppCompatActivity() { 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | setContentView(R.layout.activity_home) 37 | 38 | var first: MCSet = emptyMCSet() 39 | var second: MCSet = emptyMCSet() 40 | 41 | first += "Alice" 42 | first += "Bob" 43 | first -= "Bob" 44 | second += "Bob" 45 | second += "Charlie" 46 | 47 | val merged = first.merge(second) // Contains "Alice" and "Charlie". 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 31 | 36 | 37 | 43 | 46 | 49 | 50 | 51 | 52 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 31 | 34 | 39 | 44 | 49 | 54 | 59 | 64 | 69 | 74 | 79 | 84 | 89 | 94 | 99 | 104 | 109 | 114 | 119 | 124 | 129 | 134 | 139 | 144 | 149 | 154 | 159 | 164 | 169 | 174 | 179 | 184 | 189 | 194 | 195 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 32 | 33 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | #3F51B5 28 | #303F9F 29 | #FF4081 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | distributed-kotlin 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 26 | 27 | buildscript { 28 | repositories { 29 | google() 30 | jcenter() 31 | } 32 | dependencies { 33 | classpath "com.android.tools.build:gradle:3.2.1" 34 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.0" 35 | classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" 36 | } 37 | } 38 | 39 | allprojects { 40 | repositories { 41 | google() 42 | jcenter() 43 | maven { url "https://www.jitpack.io" } 44 | } 45 | } 46 | 47 | task clean(type: Delete) { 48 | delete rootProject.buildDir 49 | } 50 | -------------------------------------------------------------------------------- /distributed-causal-graphs/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /distributed-causal-graphs/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'java-library' 26 | apply plugin: 'kotlin' 27 | apply plugin: 'com.github.dcendents.android-maven' 28 | 29 | group='com.github.alexandrepiveteau' 30 | 31 | dependencies { 32 | testImplementation "junit:junit:4.12" 33 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.0" 34 | api "com.github.alexandrepiveteau.functional-kotlin:functional-monads:0.3.0" 35 | } 36 | 37 | sourceCompatibility = "1.7" 38 | targetCompatibility = "1.7" 39 | -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/ArrayListCausalGraphYarn.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | import com.github.alexandrepiveteau.functional.monads.map 28 | import com.github.alexandrepiveteau.functional.monads.toMaybe 29 | import com.github.alexandrepiveteau.functional.monads.withDefault 30 | 31 | internal class ArrayListCausalGraphYarn(private val elements: MutableList> = mutableListOf(), override val site: S) : 32 | MutableCausalGraphYarn, List> by elements { 33 | 34 | override fun insert(operation: O, dependencies: Set>): CausalGraphIdentifier { 35 | // TODO : Make this code prettier. 36 | val position = elements.lastOrNull() 37 | .toMaybe() 38 | .map { (_, identifier) -> identifier } 39 | .map { (_, position) -> position + 1 } 40 | .withDefault(0) 41 | val identifier = CausalGraphIdentifier(site, position) 42 | val atom = CausalGraphAtom(operation, identifier, dependencies) 43 | elements += atom 44 | return identifier 45 | } 46 | 47 | override fun merge(other: MutableCausalGraphYarn) { 48 | 49 | // Ensure that the two merges Yarns have the same origin site. 50 | check(site == other.site) { "Merged Yarns must have the same site identifier." } 51 | 52 | val aSequence = elements.asSequence() 53 | val bSequence = other.asSequence() 54 | 55 | val mergedList = sequenceOf(aSequence, bSequence).flatten() 56 | .distinctBy { it.identifier } 57 | .sortedBy { it.identifier.index } 58 | .toList() 59 | 60 | elements.clear() 61 | elements.addAll(mergedList) 62 | } 63 | 64 | override fun merge(other: CausalGraphYarn): CausalGraphYarn { 65 | 66 | // Ensure that the two merges Yarns have the same origin site. 67 | check(site == other.site) { "Merged Yarns must have the same site identifier." } 68 | 69 | val aSequence = elements.asSequence() 70 | val bSequence = other.asSequence() 71 | 72 | val mergedList = sequenceOf(aSequence, bSequence).flatten() 73 | .distinctBy { it.identifier } 74 | .sortedBy { it.identifier.index } 75 | .toMutableList() 76 | 77 | return ArrayListCausalGraphYarn(mergedList, site) 78 | } 79 | 80 | override fun remove(identifier: CausalGraphIdentifier) { 81 | 82 | // TODO : Make sure this work properly. 83 | elements.removeAll { (_, i, _) -> i == identifier } 84 | elements.map { (o, i, d) -> if (d.contains(identifier)) return@map CausalGraphAtom(o, i, d.minus(identifier)) else CausalGraphAtom(o, i, d) } 85 | } 86 | } -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraph.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | /** 28 | * Returns an instance of a [CausalGraph] that will be empty. This could be useful when some default 29 | * values have to be transmitted and forwarded from an API call. 30 | * 31 | * @param O The type of the operations that will be contained in this [CausalGraph]. 32 | * @param S The type of the sites that will be managing the Yarns of this [CausalGraph]. 33 | */ 34 | fun emptyCausalGraph(): CausalGraph = mutableCausalGraphOf() -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraph.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | /** 28 | * An interface representing a [CausalGraph] data structure. A [CausalGraph] will represent the 29 | * causality relationships between operations in a distributed system. It is structured around the 30 | * principle that each site will write only on its own Yarn, and that each operation written on a 31 | * Yarn will indicate its causality relationships to other operations. 32 | * 33 | * Essentially, a [CausalGraph] is a [Collection] of [CausalGraphYarn]s. These yarns will each be 34 | * managed by a single site, and it will be each site's responsibility to appropriately write on its 35 | * own Yarn. A control mechanism, such as site-signed operations, can be put in place to enforce 36 | * this guarantee across the distributed system. 37 | * 38 | * It is possible to merge multiple [CausalGraph]s together. This will make sure that all the Yarns 39 | * are properly merged, and will pick the available Yarn if one is available only in one of the two 40 | * sites. 41 | * 42 | * The particularity of the [CausalGraph] topology is that it lets each operation define an 43 | * arbitrary amount of causally linked operations. 44 | * 45 | * @param O The type of the operations that will be contained in this [CausalGraph]. 46 | * @param S The type of the sites that will be managing the Yarns of this [CausalGraph]. 47 | */ 48 | interface CausalGraph : Collection> { 49 | 50 | /** 51 | * Returns the [CausalGraphYarn] instance that corresponds to a particular [site] instance, and 52 | * creates and returns an empty [CausalGraphYarn] if needed. 53 | * 54 | * @param site The instance of the site for which a Yarn should be returned. 55 | */ 56 | operator fun get(site: S): CausalGraphYarn 57 | 58 | /** 59 | * Merges two immutable instances of a [CausalGraph], and returns them as a new instance of a 60 | * [CausalGraph]. This will mutate neither of the original instances. 61 | */ 62 | fun merge(other: CausalGraph): CausalGraph 63 | } -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraphAtom.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | /** 28 | * A class representing a [CausalGraphAtom], that will always be contained within an instance of 29 | * a [CausalGraphYarn]. The responsibility of the atom is to keep track of the [operation] that is 30 | * in the Yarn, as well as the unique [CausalGraphIdentifier] across the [CausalGraph], and the 31 | * [Set] of all [dependencies] that this [CausalGraphAtom] has. 32 | * 33 | * The dependencies help define the causality relationship across multiple sites, or what an 34 | * operation refers (for instance, when the operation is a delete token). The dependencies will be 35 | * referenced only by their [CausalGraphIdentifier]s. 36 | * 37 | * @param O The type of the operations that will be contained in this [CausalGraph]. 38 | * @param S The type of the sites that will be managing the Yarns of this [CausalGraph]. 39 | * 40 | * @param operation The instance of the operation saved in this atom. 41 | * @param identifier The unique [CausalGraphIdentifier] for this atom and operation. 42 | * @param dependencies The [Set] of causality dependencies that this atom has in the [CausalGraph]. 43 | */ 44 | data class CausalGraphAtom( 45 | val operation: O, 46 | val identifier: CausalGraphIdentifier, 47 | val dependencies: Set>) -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraphIdentifier.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | /** 28 | * A class representing a [CausalGraphIdentifier], that will be in charge of uniquely identifying 29 | * an instance of a [CausalGraphAtom]. Each identifier will act as a [Pair] of the site [S] that 30 | * the [CausalGraphAtom] was issued by, as well as an [Int] indicating the "index" of issuance for 31 | * the operation at this specific site. 32 | * 33 | * Using the [index], a total order of operations can be created on a per-site basis. This order 34 | * does not reflect any sort of causality between operations - it just provides some information 35 | * relevant to the source of operations. 36 | * 37 | * @param S The type of the sites that will be managing the Yarns of this [CausalGraph]. 38 | * 39 | * @param site The site that will have issued the atom linked to this [CausalGraphIdentifier]. 40 | * @param index The index of the operation referenced by this [CausalGraphIdentifier]. 41 | */ 42 | data class CausalGraphIdentifier(val site: S, val index: Int) -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraphYarn.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | fun emptyCausalGraphYarn(site: S): CausalGraphYarn = mutableCausalGraphYarnOf(site) -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/CausalGraphYarn.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | interface CausalGraphYarn: List> { 28 | val site: S 29 | fun merge(other: CausalGraphYarn): CausalGraphYarn 30 | } -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/HashMapCausalGraph.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | import com.github.alexandrepiveteau.functional.monads.fold 28 | import com.github.alexandrepiveteau.functional.monads.map 29 | import com.github.alexandrepiveteau.functional.monads.toMaybe 30 | import com.github.alexandrepiveteau.functional.monads.zip2 31 | 32 | internal class HashMapCausalGraph(private val yarns: MutableMap> = mutableMapOf()) : MutableCausalGraph { 33 | 34 | override val size: Int 35 | get() = yarns.size 36 | 37 | override fun get(site: S): MutableCausalGraphYarn = 38 | yarns.getOrPut(site) { ArrayListCausalGraphYarn(site = site) } 39 | 40 | override fun merge(other: CausalGraph): CausalGraph { 41 | val yarns: MutableMap> = mutableMapOf() 42 | val sites: Set = yarns.keys.toSet() + other.asSequence().map { it.site }.toSet() 43 | 44 | for (site in sites) { 45 | val aYarnMaybe = yarns[site].toMaybe() 46 | val bYarnMaybe = other[site].toMaybe() 47 | val mergedYarnMaybe = aYarnMaybe.zip2(bYarnMaybe).map { (a, b) -> a.merge(b) } 48 | mergedYarnMaybe.fold({ yarn -> 49 | val elements = yarn.toMutableList() 50 | yarns[site] = ArrayListCausalGraphYarn(elements, site) 51 | }, { /* Ignore. */ }) 52 | } 53 | 54 | return HashMapCausalGraph(yarns) 55 | } 56 | 57 | override fun merge(other: MutableCausalGraph) { 58 | val sites = yarns.keys.toSet() + other.asSequence().map { it.site } 59 | sites.forEach { site -> 60 | val otherSiteYarn: MutableCausalGraphYarn = other[site] 61 | this[site].merge(otherSiteYarn) 62 | } 63 | } 64 | 65 | override fun contains(element: CausalGraphYarn): Boolean { 66 | return yarns.values.contains(element) 67 | } 68 | 69 | override fun containsAll(elements: Collection>): Boolean { 70 | return yarns.values.containsAll(elements) 71 | } 72 | 73 | override fun isEmpty(): Boolean { 74 | return yarns.isEmpty() 75 | } 76 | 77 | override fun iterator(): Iterator> { 78 | return yarns.values.iterator() 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/MutableCausalGraph.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | fun mutableCausalGraphOf(): MutableCausalGraph = HashMapCausalGraph() 28 | fun mutableCausalGraphOf(vararg yarns: Pair>): MutableCausalGraph = HashMapCausalGraph(yarns.toMap().toMutableMap()) -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/MutableCausalGraph.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | interface MutableCausalGraph: CausalGraph { 28 | override operator fun get(site: S): MutableCausalGraphYarn 29 | fun merge(other: MutableCausalGraph) 30 | } -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/MutableCausalGraphYarn.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | fun mutableCausalGraphYarnOf(site: S): MutableCausalGraphYarn = ArrayListCausalGraphYarn(mutableListOf(), site) 28 | fun mutableCausalGraphYarnOf(site: S, elements: MutableList>): MutableCausalGraphYarn = ArrayListCausalGraphYarn(elements, site) -------------------------------------------------------------------------------- /distributed-causal-graphs/src/main/java/com/github/alexandrepiveteau/distributed/causalGraphs/MutableCausalGraphYarn.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.causalGraphs 26 | 27 | interface MutableCausalGraphYarn: CausalGraphYarn { 28 | fun insert(operation: O, dependencies: Set> = emptySet()): CausalGraphIdentifier 29 | fun merge(other: MutableCausalGraphYarn) 30 | fun remove(identifier: CausalGraphIdentifier) 31 | } -------------------------------------------------------------------------------- /distributed-cvrdts/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /distributed-cvrdts/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'java-library' 26 | apply plugin: 'kotlin' 27 | apply plugin: 'com.github.dcendents.android-maven' 28 | 29 | group='com.github.alexandrepiveteau' 30 | 31 | dependencies { 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.0" 33 | } 34 | 35 | sourceCompatibility = "1.7" 36 | targetCompatibility = "1.7" 37 | -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/GSet.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * Generates a new empty instance of a [GSet]. This method will be part of the only publicly 29 | * available constructors for generating some [GSet] instances. 30 | * 31 | * @param T The type of the elements of this [GSet]. 32 | * 33 | * @author Alexandre Piveteau 34 | */ 35 | fun emptyGSet() = GSet() 36 | 37 | /** 38 | * Generates a new instance of a [GSet]. This method will be the only publicly available 39 | * constructor for generating some [GSet] instances. 40 | * 41 | * @param elements The elements that the [GSet] instance should be generated with. 42 | * 43 | * @param T The type of the elements in this [GSet]. 44 | * 45 | * @author Alexandre Piveteau 46 | */ 47 | fun gSetOf(vararg elements: T) = GSet(elements.toSet()) -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/GSet.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * A class representing a [Collection] of elements that are a [GSet]. The particularity of this 29 | * collection is the fact that it can not see its internal number of elements being reduced; it will 30 | * always be growing. 31 | * 32 | * @param elements The [Set] of the elements that are contained in this [GSet]. 33 | * 34 | * @param T The type of the elements that are present in this [GSet]. 35 | * 36 | * @author Alexandre Piveteau 37 | */ 38 | class GSet internal constructor(private val elements: Set) : Set { 39 | 40 | /** 41 | * Instantiates a new [GSet] that is empty. 42 | */ 43 | constructor() : this(emptySet()) 44 | 45 | override val size = elements.size 46 | 47 | override fun contains(element: T) = elements.contains(element) 48 | 49 | override fun containsAll(elements: Collection) = this.elements.containsAll(elements) 50 | 51 | override fun isEmpty() = elements.isEmpty() 52 | 53 | override fun iterator() = elements.iterator() 54 | 55 | operator fun plus(element: T): GSet = GSet(elements + element) 56 | 57 | operator fun plus(other: Collection): GSet = GSet(elements + other) 58 | 59 | /** 60 | * Merges a [GSet] instance with another [GSet] instance. This operation is commutative, 61 | * since elements of the [GSet] that are equals will be merged. 62 | * 63 | * @param other Th [GSet] instance on which the operation of merging should be applied. 64 | * 65 | * @return A new [GSet] instance, containing the merged content. 66 | */ 67 | fun merge(other: GSet): GSet = GSet(elements + other.elements) 68 | } -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/MCSet.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * Generates a new empty instance of a [MCSet]. This method will be part of the only publicly 29 | * available constructors for generating some [MCSet] instances. 30 | * 31 | * @param T The type of the elements of this [MCSet]. 32 | * 33 | * @author Alexandre Piveteau 34 | */ 35 | fun emptyMCSet() = MCSet() 36 | 37 | /** 38 | * Generates a new instance of a [MCSet]. This method will be the only publicly available 39 | * constructor for generating some [MCSet] instances. 40 | * 41 | * @param elements The elements that the [MCSet] instance should be generated with. 42 | * 43 | * @param T The type of the elements of this [MCSet]. 44 | * 45 | * @author Alexandre Piveteau 46 | */ 47 | fun mcSetOf(vararg elements: T) = MCSet(elements.map { it to 0 }.toMap()) -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/MCSet.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * A class representing a [Collection] of elements that are a [MCSet], alias a MaxChangeSet. The 29 | * particularity of this collection is the fact that it can not see its internal numbers being 30 | * permanently removed, but still supports additions and deletions across multiple nodes. 31 | * 32 | * In particular, when some conflicting changes are detected across multiple nodes, it will keep 33 | * the results of the node that had the most changes (until synchronization is performed). 34 | * 35 | * @param elements The [Map] of the elements that are contained in this [MCSet]. 36 | * 37 | * @param T The type of the elements that are present in this [MCSet]. 38 | * 39 | * @author Alexandre Piveteau 40 | */ 41 | class MCSet constructor(private val elements: Map): Set { 42 | 43 | /** 44 | * Filters the values of a [Map] that are present, according to the inner [MCSet] semantics. 45 | */ 46 | private fun Map.filterPresent() = filterValues { modificationsCount -> 47 | modificationsCount % 2 == 0 48 | } 49 | 50 | /** 51 | * Instantiates a new [MCSet] that is empty. 52 | */ 53 | constructor() : this(emptyMap()) 54 | 55 | override val size = elements 56 | .filterPresent() 57 | .size 58 | 59 | override fun contains(element: T) = elements 60 | .filterPresent() 61 | .contains(element) 62 | 63 | override fun containsAll(elements: Collection) = this.elements 64 | .filterPresent() 65 | .keys 66 | .containsAll(elements) 67 | 68 | override fun isEmpty() = this.elements 69 | .filterPresent() 70 | .isEmpty() 71 | 72 | override fun iterator() = this.elements 73 | .filterPresent() 74 | .keys.iterator() 75 | 76 | operator fun minus(other: T): MCSet { 77 | return if (contains(other)) { 78 | increment(other) 79 | } else { 80 | this 81 | } 82 | } 83 | 84 | // TODO : operator fun minus(other: Collection): MCSet 85 | 86 | operator fun plus(other: T): MCSet { 87 | return if (contains(other).not()) { 88 | increment(other) 89 | } else { 90 | this 91 | } 92 | } 93 | 94 | // TODO : operator fun plus(other: Collection): MCSet 95 | 96 | /** 97 | * Performs an increment operation on a particular element of the inner [Map] structure. This 98 | * indicates that a change operation was performed on a particular element. 99 | * 100 | * @param element The element of type [T] that should register a change. 101 | * 102 | * @return A [MCSet] instance which reflects the change that occurred. 103 | */ 104 | private fun increment(element: T): MCSet { 105 | val mutableMap = elements.toMutableMap() 106 | mutableMap[element] = 1 + (mutableMap[element] ?: -1) 107 | return MCSet(mutableMap.toMap()) 108 | } 109 | 110 | /** 111 | * Merges a [MCSet] instance with another [MCSet] instance. This operation is commutative, since 112 | * elements of the [MCSet] that are equals will be merged. 113 | * 114 | * @param other The [PNSet] instance on which the operation of merging should be applied. 115 | * 116 | * @return A new [MCSet] instance, containing the merged content. 117 | */ 118 | fun merge(other: MCSet): MCSet { 119 | val mergedElements = elements.keys + other.elements.keys 120 | val mergedEntries = mergedElements.map { element -> 121 | element to maxOf(elements[element] ?: 0, other.elements[element] ?: 0) 122 | } 123 | return MCSet(mergedEntries.toMap()) 124 | } 125 | } -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/PNSet.common.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * Generates a new empty instance of a [PNSet]. This method will be part of the only publicly 29 | * available constructors for generating some [PNSet] instances. 30 | * 31 | * @param T The type of the elements of this [PNSet]. 32 | * 33 | * @author Alexandre Piveteau 34 | */ 35 | fun emptyPNSet() = PNSet() 36 | 37 | /** 38 | * Generates a new instance of a [PNSet]. This method will be the only publicly available 39 | * constructor for generating some [PNSet] instances. 40 | * 41 | * @param elements The elements that the [PNSet] instance should be generated with. 42 | * 43 | * @param T The type of the elements in this [GSet]. 44 | * 45 | * @author Alexandre Piveteau 46 | */ 47 | fun pnSetOf(vararg elements: T) = PNSet(elements.toSet(), emptySet()) -------------------------------------------------------------------------------- /distributed-cvrdts/src/main/java/com/github/alexandrepiveteau/distributed/cvrdts/PNSet.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.cvrdts 26 | 27 | /** 28 | * A class representing a [Collection] of elements that are a [PNSet]. The particularity of this 29 | * collection is the fact that it will support concurrent modifications and will always end in a 30 | * consistent states, since it's just the cross product of two [GSet]s. 31 | * 32 | * @param positive The [Set] of the elements that were added to this [PNSet]. 33 | * @param negative The [Set] of the elements that were removed from this [PNSet]. 34 | * 35 | * @param T The type of the elements that are present in this [GSet]. 36 | * 37 | * @author Alexandre Piveteau 38 | */ 39 | class PNSet internal constructor(private val positive: Set, private val negative: Set) : Collection { 40 | 41 | /** 42 | * Instantiates a new [PNSet] that is empty. 43 | */ 44 | constructor() : this(emptySet(), emptySet()) 45 | 46 | override val size = positive.size - (positive.union(negative).size) 47 | 48 | override fun contains(element: T) = positive.contains(element) && negative.contains(element).not() 49 | 50 | override fun containsAll(elements: Collection) = positive.containsAll(elements) && negative.containsAll(elements).not() 51 | 52 | override fun isEmpty() = positive.union(negative) == positive 53 | 54 | override fun iterator() = (positive - (positive.union(negative))).iterator() 55 | 56 | operator fun plus(element: T): PNSet = PNSet(positive + element, negative) 57 | 58 | operator fun plus(other: Collection): PNSet = PNSet(positive + other, negative) 59 | 60 | operator fun minus(element: T): PNSet = PNSet(positive, negative + element) 61 | 62 | operator fun minus(other: Collection): PNSet = PNSet(positive, negative + other) 63 | 64 | /** 65 | * Merges a [PNSet] with another [PNSet] instance. This operation is commutative, since elements 66 | * of the [PNSet] that are equal will be merged. 67 | * 68 | * @param other The [PNSet] instance on which the operation of merging should be applied. 69 | * 70 | * @return A new [PNSet] instance, containing the merged content. 71 | */ 72 | fun merge(other: PNSet): PNSet = PNSet(positive + other.positive, negative + other.negative) 73 | } -------------------------------------------------------------------------------- /distributed-woot/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /distributed-woot/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'java-library' 26 | apply plugin: 'kotlin' 27 | apply plugin: 'com.github.dcendents.android-maven' 28 | 29 | group='com.github.alexandrepiveteau' 30 | 31 | dependencies { 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.0" 33 | api "com.github.alexandrepiveteau.functional-kotlin:functional-monads:0.3.0" 34 | } 35 | 36 | sourceCompatibility = "1.7" 37 | targetCompatibility = "1.7" 38 | -------------------------------------------------------------------------------- /distributed-woot/src/main/java/com/github/alexandrepiveteau/distributed/woot/WootElement.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.woot 26 | 27 | import com.github.alexandrepiveteau.functional.monads.Maybe 28 | 29 | /** 30 | * An element of a [WootSequence] that will be used to represent an atomic, non-splittable block 31 | * of the sequence. Typically, this could be a single character in a text, or some sort of 32 | * logical block in a more complex linear structure like a tree. 33 | * 34 | * @param identifier The [WootIdentifier] that will be assigned to this specific block. 35 | * @param value The value of this particular [WootElement], that will be domain-specific. 36 | * @param visible A [Boolean] value, indicating whether this [WootElement] is present in the 37 | * sequence. 38 | * @param previousValueIdentifier The [WootIdentifier] of the previous element of the structure. 39 | * @param nextValueIdentifier The [WootIdentifier] of the next element of the structure. 40 | * 41 | * @author Alexandre Piveteau 42 | */ 43 | data class WootElement, out T>( 44 | val identifier: WootIdentifier, 45 | val value: Maybe, 46 | var visible: Boolean, 47 | val previousValueIdentifier: WootIdentifier, 48 | val nextValueIdentifier: WootIdentifier) -------------------------------------------------------------------------------- /distributed-woot/src/main/java/com/github/alexandrepiveteau/distributed/woot/WootIdentifier.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.woot 26 | 27 | /** 28 | * An identifier that will be used for the [WootSequence] elements and that will be used in 29 | * order to uniquely identify them. This will be required in order to create a linear ordering 30 | * of the operations performed on the sequence. 31 | * 32 | * Internally, a site-specific clock is managed using a [Long]. 33 | * 34 | * TODO : Change the [WootIdentifier] such that it supports other site-specific clock types. 35 | * 36 | * @param S The type of the site identifiers that will be used. Must be [Comparable]. 37 | * 38 | * @author Alexandre Piveteau 39 | */ 40 | sealed class WootIdentifier>: Comparable> { 41 | 42 | /** 43 | * An identifier for a [WootIdentifier] that is at the end of the sequence, i.e. no 44 | * user-defined characters can succeed it. 45 | * 46 | * @see WootIdentifier 47 | */ 48 | class End>: WootIdentifier() { 49 | 50 | override fun compareTo(other: WootIdentifier) = if (other is End) 0 else 1 51 | 52 | override fun equals(other: Any?) = other is End<*> 53 | 54 | override fun toString() = "WootIdentifier.End" 55 | } 56 | 57 | /** 58 | * An identifier for a [WootElement] that will be in the middle of the sequence, i.e. not at any 59 | * of the extremities. 60 | * 61 | * @param siteIdentifier The identifier of the [S]ite for this identifier. 62 | * @param siteClock The [Long] indicating the total ordering of the site operation. 63 | * 64 | * @see WootIdentifier 65 | */ 66 | data class Element>(val siteIdentifier: S, val siteClock: Long): WootIdentifier() { 67 | 68 | override fun compareTo(other: WootIdentifier) = when (other) { 69 | is Element -> { 70 | if (siteIdentifier.compareTo(other.siteIdentifier) != 0) { 71 | siteIdentifier.compareTo(other.siteIdentifier) 72 | } else { 73 | siteClock.compareTo(other.siteClock) 74 | } 75 | } 76 | is End -> -1 77 | is Start -> 1 78 | } 79 | } 80 | 81 | /** 82 | * An identifier for a [WootIdentifier] that is at the start of the sequence, i.e. no 83 | * user-defined characters can precede it. 84 | * 85 | * @see WootIdentifier 86 | */ 87 | class Start>: WootIdentifier() { 88 | 89 | override fun compareTo(other: WootIdentifier) = if (other is Start) 0 else -1 90 | 91 | override fun equals(other: Any?) = other is Start<*> 92 | 93 | override fun toString() = "WootIdentifier.Start" 94 | } 95 | } -------------------------------------------------------------------------------- /distributed-woot/src/main/java/com/github/alexandrepiveteau/distributed/woot/WootList.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.woot 26 | 27 | /** 28 | * An implementation of a [List] that uses the representation of the [WootList] provided by the 29 | * method [WootSequence.value]. 30 | * 31 | * TODO : Support the MutableList behavior at some point. 32 | * 33 | * @param sequence The [WootSequence] that will be used in order to internally represent the [List]. 34 | * 35 | * @param S The type of the site identifiers that will be used. Must be [Comparable]. 36 | * @param T The type of the elements that are present in this [WootSequence]. 37 | * 38 | * @author Alexandre Piveteau 39 | */ 40 | class WootList, out T>(private val sequence: WootSequence): List by sequence.value() -------------------------------------------------------------------------------- /distributed-woot/src/main/java/com/github/alexandrepiveteau/distributed/woot/WootOperation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.woot 26 | 27 | /** 28 | * A sealed class representing the different types of [WootOperation]s that can be applied to an 29 | * instance of a [WootSequence]. Each of the operations behavior will be defined by the 30 | * [WootElement] that is encoded in the operation. 31 | * 32 | * @param element The [WootElement] of the operation. 33 | * 34 | * @param S The type of the site identifiers that will be used. Must be [Comparable]. 35 | * @param T The type of the elements that are present in the [WootSequence]. 36 | * 37 | * @author Alexandre Piveteau 38 | */ 39 | sealed class WootOperation, out T>(val element: WootElement) { 40 | 41 | /** 42 | * A delete operation on a [WootSequence]. Use the [WootSequence] dedicated method to generate 43 | * this [WootOperation]. 44 | * 45 | * @see WootOperation 46 | * @see WootSequence 47 | */ 48 | data class DeleteOperation, out T>(private val deletedElement: WootElement): WootOperation(deletedElement) 49 | 50 | /** 51 | * An insert operation on a [WootSequence]. Use the [WootSequence] dedicated method to generate 52 | * this [WootOperation]. 53 | * 54 | * @see WootOperation 55 | */ 56 | data class InsertOperation, out T>(private val insertedElement: WootElement): WootOperation(insertedElement) 57 | } -------------------------------------------------------------------------------- /distributed-woot/src/main/java/com/github/alexandrepiveteau/distributed/woot/WootSequence.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.alexandrepiveteau.distributed.woot 26 | 27 | import com.github.alexandrepiveteau.functional.monads.Maybe 28 | import com.github.alexandrepiveteau.functional.monads.emptyMaybe 29 | import com.github.alexandrepiveteau.functional.monads.maybeOf 30 | 31 | /** 32 | * A class representing a [Collection] of elements that are a [WootSequence]. A [WootSequence] is a 33 | * CRDT sequence that works without Operation Transform. It supports commutative operations across 34 | * multiple independent peers. 35 | * 36 | * This data structure will be mutable, in order to provide some better performance on devices with 37 | * a high overhead for garbage collection. 38 | * 39 | * TODO : Change the [WootIdentifier] such that it supports other site-specific clock types. 40 | * 41 | * @param localIdentifier The identifier of the [S]ite where this [WootSequence] is stored. 42 | * @param localClock The [Long] representing the current clock at the local site. 43 | * 44 | * @param S The type of the site identifiers that will be used. Must be [Comparable]. 45 | * @param T The type of the elements that are present in this [WootSequence]. 46 | * 47 | * @author Alexandre Piveteau 48 | */ 49 | class WootSequence, T>( 50 | val localIdentifier: S, 51 | private var localClock: Long = 0) { 52 | 53 | /** 54 | * The local, site-specific [List] of [WootElement]s that will be used to define this 55 | * [WootSequence]. When the [WootSequence] has just been created, this [List] will be empty and 56 | * contain only the extremities. 57 | */ 58 | private val localElements: MutableList> = mutableListOf( 59 | WootElement(WootIdentifier.Start(), emptyMaybe(), false, WootIdentifier.Start(), WootIdentifier.End()), 60 | WootElement(WootIdentifier.End(), emptyMaybe(), false, WootIdentifier.Start(), WootIdentifier.End()) 61 | ) 62 | 63 | /** 64 | * The local, site-specific operations that are pending. They are preserved in a pool until they 65 | * will have been applied and integrated to the [localElements]. 66 | */ 67 | private val localPendingOperations: MutableList> = mutableListOf() 68 | 69 | /** 70 | * A [MutableSet] of all the [WootOperation]s that will have been already integrated into this 71 | * instance of [WootSequence]. This will also be used to ensure that the operations are not 72 | * played multiple times. 73 | */ 74 | private val localIntegratedOperations: MutableSet> = mutableSetOf() 75 | 76 | /** 77 | * Applies the pending [WootOperation]s that should be applied to this particular instance of a 78 | * [WootSequence]. The operations that will have to be applied will be performed in an order 79 | * that preserves the intention semantics of the user of the [WootSequence]. 80 | * 81 | * If the local pending operations still require some additional operations before being 82 | * performed, they will not be applied until the said operations have been successfully 83 | * dispatched to this [WootSequence] through the [enqueueOperation] method. 84 | */ 85 | fun applyPendingOperations() { 86 | while (localPendingOperations.isNotEmpty()) { 87 | if (checkOperationExecutable(localPendingOperations.first()).not()) { 88 | localPendingOperations.sortByDescending { checkOperationExecutable(it) } 89 | } 90 | if (checkOperationExecutable(localPendingOperations.first()).not()) { 91 | return // Ensures that we can apply the first operation. 92 | } 93 | val operation = localPendingOperations.removeAt(0) 94 | if (localIntegratedOperations.contains(operation)) { 95 | break // Ensures that we do not apply an operation multiple times. 96 | } 97 | val element = operation.element 98 | if (operation is WootOperation.DeleteOperation) { 99 | integrateDeletion(element) 100 | } else if (operation is WootOperation.InsertOperation) { 101 | integrateInsertion(element, element.previousValueIdentifier, element.nextValueIdentifier) 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * Checks whether a certain [WootOperation] is executable with the current state of the 108 | * [WootSequence] and returns a [Boolean] indicating whether it's the case or not. In fact, when 109 | * some missing operations have not been delivered yet, the [WootOperation]s might not be 110 | * applicable. 111 | * 112 | * @param operation The [WootOperation] for which we would like to know if it is executable. 113 | * 114 | * @return A [Boolean] value indicating if the operation is indeed executable or not. 115 | */ 116 | private fun checkOperationExecutable(operation: WootOperation): Boolean { 117 | val element = operation.element 118 | return when (operation) { 119 | is WootOperation.DeleteOperation -> { 120 | localElements.contains(element) 121 | } 122 | is WootOperation.InsertOperation -> { 123 | val localElementsIdentifiers = localElements.map { it.identifier } 124 | localElementsIdentifiers.contains(element.nextValueIdentifier) && 125 | localElementsIdentifiers.contains(element.previousValueIdentifier) 126 | } 127 | } 128 | } 129 | 130 | /** 131 | * Enqueues a [WootOperation] that will have to be applied to this [WootSequence] at some point 132 | * in the future. In particular, the [WootOperation] will be applied only once the dedicated 133 | * method [applyPendingOperations] will have been called. 134 | * 135 | * @param operation The [WootOperation] that will have to be applied on this [WootSequence]. 136 | * 137 | * @see applyPendingOperations 138 | */ 139 | fun enqueueOperation(operation: WootOperation) { 140 | // Check that this operation was not already applied anyhow. Identifier already there ? 141 | if (localElements.contains(operation.element).not() && localPendingOperations.contains(operation).not()) { 142 | localPendingOperations += operation 143 | } 144 | } 145 | 146 | /** 147 | * Deletes the element visible at the i-th index of the current [WootSequence] instance. Once an 148 | * element has been deleted from a [WootSequence] by a site, it will have to be re-added in 149 | * order to be visible again to the user. 150 | * 151 | * This method does not perform the operation, but generates a [WootOperation] that can then 152 | * be distributed and applied to each [WootSequence] independently. 153 | * 154 | * @param index The [Int] index that corresponds to the i-th visible element, that will be 155 | * deleted. 156 | * 157 | * @return The [WootOperation] that will have to be applied through the [enqueueOperation] 158 | * method. 159 | */ 160 | fun generateDeleteAt(index: Int): WootOperation { 161 | val element = visibleElementAt(index) ?: throw UnsupportedOperationException("No element at index $index.") 162 | return WootOperation.DeleteOperation(deletedElement = element).apply { integrateDeletion(element) } 163 | } 164 | 165 | /** 166 | * Inserts an element at the i-th index of the visible items of the current [WootSequence]. 167 | * 168 | * This method does not perform the operation, but generates a [WootOperation] that can then 169 | * be distributed and applied to each [WootSequence] independently. 170 | * 171 | * @param index The [Int] index that corresponds to the i-th visible position, that will be 172 | * deleted. 173 | * @param value The element of type [T] that should be inserted at the position [index]. 174 | * 175 | * @return The [WootOperation] that will have to be applied through the [enqueueOperation] 176 | * method. 177 | */ 178 | fun generateInsertAt(index: Int, value: T): WootOperation { 179 | localClock++ 180 | val previousVisibleIdentifier = visibleElementAt(index)?.identifier ?: WootIdentifier.Start() 181 | val nextVisibleIdentifier = visibleElementAt(index + 1)?.identifier ?: WootIdentifier.End() 182 | val elementIdentifier = WootIdentifier.Element(localIdentifier, localClock) 183 | val element = WootElement(elementIdentifier, maybeOf(value), true, previousVisibleIdentifier, nextVisibleIdentifier) 184 | return WootOperation.InsertOperation(insertedElement = element).apply { integrateInsertion(element, previousVisibleIdentifier, nextVisibleIdentifier) } 185 | } 186 | 187 | /** 188 | * Integrates the deletion of a [WootElement] into the current [WootSequence]. This will perform 189 | * all of the changes that are necessary to be performed once a [WootElement] has been selected 190 | * and should be deleted by this site. 191 | * 192 | * @param element The [WootElement] instance that should be deleted for this site. 193 | */ 194 | private fun integrateDeletion(element: WootElement) { 195 | element.visible = false 196 | localIntegratedOperations += WootOperation.DeleteOperation(element) 197 | } 198 | 199 | /** 200 | * Integrates the insertion of a [WootElement] into the current [WootSequence]. This will 201 | * perform all the changes that are necessary to be performed once a [WootElement] has been 202 | * chosen and should be inserted by this site. 203 | * 204 | * TODO : Optimize the recursion to check less elements. 205 | * 206 | * @param element The [WootElement] instance that should be added on this site. 207 | * @param previousIdentifier The [WootIdentifier] of the preceding element. 208 | * @param nextIdentifier The [WootIdentifier] of the succeeding element. 209 | */ 210 | private fun integrateInsertion(element: WootElement, 211 | previousIdentifier: WootIdentifier, 212 | nextIdentifier: WootIdentifier) { 213 | val localElementsIdentifiers = localElements.toList().map { it.identifier } 214 | val previousElementIndex = localElementsIdentifiers.indexOf(previousIdentifier) 215 | val nextElementIndex = localElementsIdentifiers.indexOf(nextIdentifier) 216 | 217 | if (nextElementIndex - 1 == previousElementIndex) { 218 | // No space between the elements, so we can directly add the new element. 219 | localElements.add(nextElementIndex, element) 220 | localIntegratedOperations += WootOperation.InsertOperation(element) 221 | } else { 222 | // There is some free room between the elements, so we need to recursively perform some 223 | // calculations to insert properly. 224 | 225 | var index = 0 226 | while (index < localElements.size && localElements[index].identifier < element.identifier) { 227 | index++ 228 | } 229 | 230 | // Recursive call, as per the Woot algorithm. 231 | integrateInsertion(element, localElements[index - 1].identifier, localElements[index].identifier) 232 | } 233 | } 234 | 235 | /** 236 | * Returns the user-visible [Set] of all the [WootOperation]s that have already been integrated 237 | * into this instance of the [WootSequence]. Identical [WootOperation]s should not be replayed, 238 | * and a local log of the [WootOperation]s is kept to avoid this. 239 | */ 240 | fun integratedOperations(): Set> = localIntegratedOperations.toSet() 241 | 242 | /** 243 | * Returns the element visible at the index [Int] from the start of the sequence. Similarly to 244 | * a standard list, this will return the n-th element that is user-facing. 245 | */ 246 | private fun visibleElementAt(index: Int): WootElement? = localElements 247 | .toList() 248 | .filter { it.visible } 249 | .getOrNull(index) 250 | 251 | /** 252 | * Returns the user-visible value of the current [WootSequence] that can then be interpreted 253 | * and directly used by the users of the [WootSequence]. 254 | * 255 | * @return A [List] of elements of type [T]. 256 | */ 257 | fun value(): List = localElements 258 | .toList() 259 | .filter { it.visible && it.value is Maybe.Some } 260 | .map { it.value as Maybe.Some } 261 | .map { it.just } 262 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | # AndroidX project. 16 | android.enableJetifier=true 17 | android.useAndroidX=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandrepiveteau/distributed-kotlin/57856b67ff034b0cfc10891641c51abfabd5a144/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Sep 26 12:21:47 CEST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 Alexandre Piveteau 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | include ':app' 26 | include ':distributed-causal-graphs' 27 | include ':distributed-cvrdts' 28 | include ':distributed-woot' 29 | --------------------------------------------------------------------------------