├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ ├── MIT.xml
│ └── profiles_settings.xml
├── kotlinc.xml
├── markdown-exported-files.xml
├── markdown-navigator.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── modules
│ ├── PowerCollections_main.iml
│ └── PowerCollections_test.iml
└── vcs.xml
├── LICENSE.md
├── PowerCollections.iml
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
├── main
└── kotlin
│ └── io
│ └── bluego
│ └── powercollections
│ ├── BiMap.kt
│ ├── PowerCollections.kt
│ ├── Utils.kt
│ ├── bounded
│ ├── Boundable.kt
│ ├── BoundedList.kt
│ ├── BoundedMap.kt
│ └── Utils.kt
│ ├── observable
│ ├── list
│ │ ├── ListObserver.kt
│ │ ├── Observable.kt
│ │ ├── ObservableList.kt
│ │ └── adapter
│ │ │ └── ObservableListAdapter.kt
│ └── map
│ │ ├── MapObserver.kt
│ │ ├── Observable.kt
│ │ ├── ObservableMap.kt
│ │ └── adapter
│ │ └── ObservableMapAdapter.kt
│ └── weak
│ ├── WeakCollection.kt
│ ├── WeakSet.kt
│ ├── Weakable.kt
│ └── adapter
│ └── WeakCollectionAdapter.kt
└── test
└── kotlin
└── io
└── bluego
└── powercollections
├── BiMapTest.kt
├── PowerCollectionsTest.kt
├── _testutils
├── Utils.kt
└── templates
│ ├── CollectionTest.kt
│ ├── ListTest.kt
│ ├── MapTest.kt
│ └── SetTest.kt
├── bounded
├── BoundedListTest.kt
└── BoundedMapTest.kt
├── observable
├── AbstractDummyObserver.kt
├── list
│ ├── DummyListObserver.kt
│ └── ObservableListTest.kt
└── map
│ ├── DummyMapObserver.kt
│ └── ObservableMapTest.kt
└── weak
├── DummyClass.kt
├── WeakCollectionTest.kt
└── WeakSetTest.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Gradle template
3 | .gradle
4 | /build/
5 |
6 | # Ignore Gradle GUI config
7 | gradle-app.setting
8 |
9 | # Cache of project
10 | .gradletasknamecache
11 |
12 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
13 | # gradle/wrapper/gradle-wrapper.properties
14 | ### Kotlin template
15 | # Compiled class file
16 | #*.class
17 |
18 | # Log file
19 | *.log
20 |
21 | # BlueJ files
22 | *.ctxt
23 |
24 | # Mobile Tools for Java (J2ME)
25 | .mtj.tmp/
26 |
27 | # Package Files #
28 | *.jar
29 | *.war
30 | *.ear
31 | *.zip
32 | *.tar.gz
33 | *.rar
34 |
35 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
36 | !gradle-wrapper.jar
37 |
38 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
39 | hs_err_pid*
40 | ### JetBrains template
41 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
42 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
43 |
44 | # User-specific stuff:
45 | .idea/**/workspace.xml
46 | .idea/**/tasks.xml
47 | .idea/dictionaries
48 |
49 | # Sensitive or high-churn files:
50 | .idea/**/dataSources/
51 | .idea/**/dataSources.ids
52 | .idea/**/dataSources.xml
53 | .idea/**/dataSources.local.xml
54 | .idea/**/sqlDataSources.xml
55 | .idea/**/dynamic.xml
56 | .idea/**/uiDesigner.xml
57 |
58 | # Gradle:
59 | .idea/**/gradle.xml
60 | .idea/**/libraries
61 |
62 | # CMake
63 | cmake-build-debug/
64 | cmake-build-release/
65 |
66 | # Mongo Explorer plugin:
67 | .idea/**/mongoSettings.xml
68 |
69 | ## File-based project format:
70 | *.iws
71 |
72 | ## Plugin-specific files:
73 |
74 | # IntelliJ
75 | out/
76 |
77 | # mpeltonen/sbt-idea plugin
78 | .idea_modules/
79 |
80 | # JIRA plugin
81 | atlassian-ide-plugin.xml
82 |
83 | # Cursive Clojure plugin
84 | .idea/replstate.xml
85 |
86 | # Crashlytics plugin (for Android Studio and IntelliJ)
87 | com_crashlytics_export_strings.xml
88 | crashlytics.properties
89 | crashlytics-build.properties
90 | fabric.properties
91 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/copyright/MIT.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/markdown-exported-files.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/modules/PowerCollections_main.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.idea/modules/PowerCollections_test.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Felix Pröhl
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.
--------------------------------------------------------------------------------
/PowerCollections.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 |
26 | apply plugin: 'idea'
27 | apply plugin: 'maven'
28 | apply plugin: 'kotlin'
29 |
30 | group = "com.github.Poweranimal"
31 | version = "0.0.1"
32 |
33 | sourceCompatibility = 1.7 // java 7
34 | targetCompatibility = 1.7
35 |
36 | buildscript {
37 | ext.kotlin_version = '1.2.31'
38 | repositories {
39 | jcenter()
40 | }
41 | dependencies {
42 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
43 |
44 | // NOTE: Do not place your application dependencies here; they belong
45 | // in the individual module build.gradle files
46 | }
47 | }
48 |
49 | allprojects {
50 | repositories {
51 | jcenter()
52 | maven { url 'https://jitpack.io' }
53 | }
54 | }
55 | repositories {
56 | mavenCentral()
57 | }
58 |
59 | dependencies {
60 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
61 | testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
62 | testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
63 | }
64 |
65 | compileKotlin {
66 | kotlinOptions {
67 | jvmTarget = "1.8"
68 | }
69 | }
70 | compileTestKotlin {
71 | kotlinOptions {
72 | jvmTarget = "1.8"
73 | }
74 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Poweranimal/PowerCollections/ef93e98e24857608f14b0eeca5174a14c1867781/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/BiMap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections
26 |
27 | /**
28 | * This [Map] has unique keys [K] and unique values [V].
29 | */
30 | interface BiMap : Map {
31 |
32 | override val values: Set
33 |
34 | /**
35 | * Swaps [keys] and [values].
36 | * Grants search access to [keys] by [values].
37 | */
38 | val inverse: BiMap
39 | }
40 |
41 | /**
42 | * This [MutableMap] has unique [keys] and unique [values].
43 | */
44 | interface MutableBiMap : BiMap, MutableMap {
45 |
46 | override val values: MutableSet
47 |
48 | override val inverse: MutableBiMap
49 |
50 | /**
51 | * Removes an already existing pair that contains a value that is identical to the new [value].
52 | */
53 | fun forcePut(key: K, value: V): V?
54 | }
55 |
56 | abstract class AbstractBiMap protected constructor(
57 | private val mDirect: MutableMap,
58 | private val mReverse: MutableMap)
59 | : MutableBiMap
60 | {
61 | override val size: Int
62 | get() = mDirect.size
63 |
64 | override val inverse: MutableBiMap by lazy {
65 | object : AbstractBiMap(mReverse, mDirect) {
66 | override val inverse: MutableBiMap
67 | get() = this@AbstractBiMap
68 | }
69 | }
70 |
71 | override val entries: MutableSet> =
72 | BiMapSet(mDirect.entries, { it.key }, { BiMapEntry(it) })
73 |
74 | override val keys: MutableSet
75 | get() = BiMapSet(mDirect.keys, { it }, { it })
76 |
77 | override val values: MutableSet
78 | get() = inverse.keys
79 |
80 |
81 | constructor() : this(mutableMapOf(), mutableMapOf())
82 |
83 |
84 | override fun forcePut(key: K, value: V): V? {
85 | val oldValue = mDirect.put(key, value)?.also { mReverse.remove(it) }
86 | mReverse.put(value, key)?.also { mDirect.remove(it) }
87 | return oldValue
88 | }
89 |
90 | override fun put(key: K, value: V): V? {
91 | require(value !in mReverse) { "BiMap already contains value $value" }
92 | return forcePut(key, value)
93 | }
94 |
95 | override fun putAll(from: Map) {
96 | from.values.forEach { value ->
97 | require(value !in mReverse) { "BiMap already contains value $value" }
98 | }
99 | from.entries.forEach { forcePut(it.key, it.value) }
100 | }
101 |
102 | override fun remove(key: K): V? {
103 | return mDirect.remove(key)?.also { mReverse.remove(it) }
104 | }
105 |
106 | override fun clear() {
107 | mDirect.clear()
108 | mReverse.clear()
109 | }
110 |
111 | override fun get(key: K): V? = mDirect[key]
112 |
113 | override fun containsKey(key: K): Boolean = key in mDirect
114 |
115 | override fun containsValue(value: V): Boolean = value in mReverse
116 |
117 | override fun isEmpty(): Boolean = mDirect.isEmpty()
118 |
119 | private inner class BiMapSet(
120 | private val mElements: MutableSet,
121 | private val mKeyGetter: (T) -> K,
122 | private val mElementWrapper: (T) -> T)
123 | : MutableSet by mElements
124 | {
125 | override fun remove(element: T): Boolean {
126 | if (element !in this) return false
127 |
128 | val key = mKeyGetter(element)
129 | val value = mDirect.remove(key) ?: return false
130 | try {
131 | mReverse.remove(value)
132 | } catch (throwable: Throwable) {
133 | mDirect[key] = value
134 | throw throwable
135 | }
136 | return true
137 | }
138 |
139 | override fun clear() {
140 | mDirect.clear()
141 | mReverse.clear()
142 | }
143 |
144 | override fun iterator(): MutableIterator {
145 | val iterator = mElements.iterator()
146 | return BiMapSetIterator(iterator, mKeyGetter, mElementWrapper)
147 | }
148 | }
149 |
150 | private inner class BiMapSetIterator(
151 | private val mIterator: MutableIterator,
152 | private val mKeyGetter: (T) -> K,
153 | private val mElementWrapper: (T) -> T)
154 | : MutableIterator
155 | {
156 | private var mLast: T? = null
157 |
158 | override fun hasNext(): Boolean {
159 | return mIterator.hasNext()
160 | }
161 |
162 | override fun next(): T {
163 | val element = mIterator.next().apply {
164 | mLast = this
165 | }
166 | return mElementWrapper(element)
167 | }
168 |
169 | override fun remove() {
170 | checkNotNull(mLast as Any?) { "Move to an element before removing it" }
171 | try {
172 | val key = mKeyGetter(mLast!!)
173 | val value = mDirect[key] ?: throw IllegalStateException("BiMap doesn't contain key $key")
174 | mReverse.remove(value)
175 | try {
176 | mIterator.remove()
177 | } catch (throwable: Throwable) {
178 | mReverse[value] = key
179 | throw throwable
180 | }
181 | } finally {
182 | mLast = null
183 | }
184 | }
185 | }
186 |
187 | private inner class BiMapEntry(private val mEntry: MutableMap.MutableEntry)
188 | : MutableMap.MutableEntry by mEntry
189 | {
190 | override fun setValue(newValue: V): V {
191 | if (mEntry.value == newValue) {
192 | mReverse[newValue] = mEntry.key
193 | return try {
194 | mEntry.setValue(newValue)
195 | } catch (throwable: Throwable) {
196 | mReverse[mEntry.value] = mEntry.key
197 | throw throwable
198 | }
199 | } else {
200 | require(newValue !in mReverse) { "BiMap already contains value $newValue" }
201 | mReverse[newValue] = mEntry.key
202 | return try {
203 | mEntry.setValue(newValue)
204 | } catch (throwable: Throwable) {
205 | mReverse.remove(newValue)
206 | throw throwable
207 | }
208 | }
209 | }
210 | }
211 | }
212 |
213 | class HashBiMap(capacity: Int = 16) : AbstractBiMap(HashMap(capacity), HashMap(capacity)) {
214 | companion object {
215 | fun create(map: Map): HashBiMap {
216 | val biMap = HashBiMap()
217 | biMap.putAll(map)
218 | return biMap
219 | }
220 | }
221 | }
222 |
223 | /**
224 | * Creates an empty [MutableBiMap].
225 | *
226 | * @return Empty [MutableBiMap]
227 | */
228 | fun mutableBiMapOf(): MutableBiMap = HashBiMap()
229 |
230 | /**
231 | * Creates an [MutableBiMap] with [elements].
232 | *
233 | * @return [MutableBiMap] with [elements]
234 | */
235 | fun mutableBiMapOf(vararg elements: Pair): MutableBiMap
236 | = HashBiMap.create(mapOf(*elements))
237 |
238 | /**
239 | * Creates an [MutableBiMap] with [map].
240 | *
241 | * @return [MutableBiMap] with [map]
242 | */
243 | fun mutableBiMapOf(map: Map): MutableBiMap
244 | = HashBiMap.create(map)
245 |
246 | /**
247 | * Creates an empty [BiMap].
248 | *
249 | * @return Empty [BiMap]
250 | */
251 | fun biMapOf(): BiMap = mutableBiMapOf()
252 |
253 | /**
254 | * Creates an [BiMap] with [elements].
255 | *
256 | * @return [BiMap] with [elements]
257 | */
258 | fun biMapOf(vararg elements: Pair): BiMap
259 | = mutableBiMapOf(*elements)
260 |
261 | /**
262 | * Creates an [BiMap] with [map].
263 | *
264 | * @return [BiMap] with [map]
265 | */
266 | fun biMapOf(map: Map): BiMap
267 | = mutableBiMapOf(map)
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/PowerCollections.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections
26 |
27 | import io.bluego.powercollections.bounded.*
28 | import io.bluego.powercollections.observable.list.ListObserverDSL
29 | import io.bluego.powercollections.observable.list.MutableObservableList
30 | import io.bluego.powercollections.observable.list.mutableObservableListOf
31 | import io.bluego.powercollections.observable.map.MapObserverDSL
32 | import io.bluego.powercollections.observable.map.MutableObservableMap
33 | import io.bluego.powercollections.observable.map.mutableObservableMapOf
34 | import io.bluego.powercollections.weak.MutableWeakCollection
35 | import io.bluego.powercollections.weak.MutableWeakSet
36 | import io.bluego.powercollections.weak.mutableWeakCollectionOf
37 | import io.bluego.powercollections.weak.mutableWeakSetOf
38 | import kotlin.properties.ReadWriteProperty
39 | import kotlin.reflect.KProperty
40 |
41 | object PowerCollections {
42 |
43 | inline fun > observableList(noinline observer: ListObserverDSL<*>.() -> Unit): ReadWriteProperty
44 | = object : ReadWriteProperty {
45 |
46 | private var mList: MutableObservableList<*> = mutableObservableListOf(observer)
47 |
48 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
49 | return mList as T
50 | }
51 |
52 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
53 | mList = mutableObservableListOf(observer, *value.toTypedArray())
54 | }
55 | }
56 |
57 | inline fun > observableMap(noinline observer: MapObserverDSL<*, *>.() -> Unit): ReadWriteProperty
58 | = object : ReadWriteProperty {
59 |
60 | private var mMap: MutableObservableMap<*, *> = mutableObservableMapOf(observer)
61 |
62 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
63 | return mMap as T
64 | }
65 |
66 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
67 | mMap = mutableObservableMapOf(observer, value)
68 | }
69 | }
70 |
71 | inline fun > boundedList(size: Int): ReadWriteProperty
72 | = object : ReadWriteProperty {
73 |
74 | private var mList: MutableBoundedList<*> = mutableBoundedListOf(size)
75 |
76 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
77 | return mList as T
78 | }
79 |
80 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
81 | mList = mutableBoundedListOf(size, *value.toTypedArray())
82 | }
83 | }
84 |
85 | inline fun > boundedMap(size: Int): ReadWriteProperty
86 | = object : ReadWriteProperty {
87 |
88 | private var mMap: MutableBoundedMap<*, *> = mutableBoundedMapOf(size)
89 |
90 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
91 | return mMap as T
92 | }
93 |
94 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
95 | mMap = mutableBoundedMapOf(size, value)
96 | }
97 | }
98 |
99 | inline fun > weakCollection(): ReadWriteProperty
100 | = object : ReadWriteProperty {
101 |
102 | private var mCollection: MutableWeakCollection<*> = mutableWeakCollectionOf()
103 |
104 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
105 | return mCollection as T
106 | }
107 |
108 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
109 | mCollection = mutableWeakCollectionOf(*value.toTypedArray())
110 | }
111 | }
112 |
113 | inline fun > weakSet(): ReadWriteProperty
114 | = object : ReadWriteProperty {
115 |
116 | private var mSet: MutableWeakSet<*> = mutableWeakSetOf()
117 |
118 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
119 | return mSet as T
120 | }
121 |
122 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
123 | mSet = mutableWeakSetOf(*value.toTypedArray())
124 | }
125 | }
126 |
127 | inline fun > biMap(): ReadWriteProperty
128 | = object : ReadWriteProperty {
129 |
130 | private var mMap: MutableBiMap = mutableBiMapOf()
131 |
132 | override fun getValue(thisRef: Any?, property: KProperty<*>): T {
133 | return mMap as T
134 | }
135 |
136 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
137 | mMap = mutableBiMapOf(value)
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/Utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections
26 |
27 | internal fun Map.getKeyByValue(value: V): K? {
28 | for ((key, value1) in this) {
29 | if (value == value1) return key
30 | }
31 | return null
32 | }
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/bounded/Boundable.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.bounded
26 |
27 | interface Boundable {
28 |
29 | /**
30 | * The max capacity of the implementing list.
31 | * Cannot contain more items than the determined max capacity.
32 | */
33 | val maxCapacity: Int
34 | }
35 |
36 | interface MutableBoundable : Boundable {
37 |
38 | /**
39 | * Increases or decreases the [maxCapacity].
40 | */
41 | fun resize(newSize: Int)
42 |
43 | /**
44 | * Increases or decreases the [maxCapacity].
45 | * @return true, if item/s got removed
46 | */
47 | fun forceResize(newSize: Int): Boolean
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/bounded/BoundedMap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.bounded
26 |
27 | import io.bluego.powercollections.bounded.Utils.checkInitialMaxCapacity
28 | import io.bluego.powercollections.bounded.Utils.checkResize
29 |
30 | /**
31 | * A [Map] that has a fixed capacity of [Map.entries].
32 | */
33 | interface BoundedMap: Map, Boundable
34 |
35 | /**
36 | * A [MutableList] that has a fixed capacity of [Map.entries].
37 | */
38 | interface MutableBoundedMap: MutableMap, BoundedMap, MutableBoundable {
39 |
40 | /**
41 | * Puts the entry in the [MutableBoundedMap].
42 | * @throws IndexOutOfBoundsException, if the [MutableMap]'s [maxCapacity] is reached.
43 | */
44 | override fun put(key: K, value: V): V?
45 |
46 | /**
47 | * Puts the entries in the [MutableBoundedMap].
48 | * @throws IndexOutOfBoundsException, if the [MutableMap]'s [maxCapacity] is reached.
49 | */
50 | override fun putAll(from: Map)
51 |
52 | /**
53 | * Adds items to the [MutableBoundedMap].
54 | * If the [MutableBoundedMap]'s [maxCapacity] is reached, the item gets added to the tail
55 | * and the head (the oldest item) gets removed.
56 | * @return true, if head item was removed
57 | */
58 | fun forcePut(key: K, value: V): Boolean
59 |
60 | /**
61 | * Adds items to the [MutableBoundedMap].
62 | * If the [MutableBoundedMap]'s [maxCapacity] is reached, the item gets added to the tail
63 | * and the head (the oldest item) gets removed.
64 | * @return true, if head item was removed
65 | */
66 | fun forcePutAll(from: Map): Boolean
67 | }
68 |
69 | /**
70 | * A [MutableBoundedMap] baked by [LinkedHashMap] that has a fixed capacity determined by [maxCapacity].
71 | */
72 | abstract class AbstractBoundedMap
73 | : LinkedHashMap, MutableBoundedMap
74 | {
75 |
76 | constructor(maxCapacity: Int) : super() {
77 | checkInitialMaxCapacity(maxCapacity)
78 | this.maxCapacity = maxCapacity
79 | }
80 |
81 | constructor(maxCapacity: Int, initialCapacity: Int, loadFactor: Float)
82 | : super(initialCapacity, loadFactor) {
83 | checkInitialMaxCapacity(maxCapacity)
84 | this.maxCapacity = maxCapacity
85 | }
86 |
87 | constructor(maxCapacity: Int, initialCapacity: Int)
88 | : super(initialCapacity) {
89 | checkInitialMaxCapacity(maxCapacity)
90 | this.maxCapacity = maxCapacity
91 | }
92 |
93 | constructor(maxCapacity: Int, m: Map?)
94 | : super(m) {
95 | checkInitialMaxCapacity(maxCapacity)
96 | this.maxCapacity = maxCapacity
97 | }
98 |
99 | constructor(maxCapacity: Int, initialCapacity: Int, loadFactor: Float, accessOrder: Boolean)
100 | : super(initialCapacity, loadFactor, accessOrder) {
101 | checkInitialMaxCapacity(maxCapacity)
102 | this.maxCapacity = maxCapacity
103 | }
104 |
105 | /**
106 | * The max capacity of the [BoundedMap].
107 | * Cannot contain more entries than [maxCapacity].
108 | */
109 | final override var maxCapacity: Int
110 | private set
111 |
112 | private var mEldestEntryRemoved = false
113 | private var mIsRunningSensitive = false
114 |
115 | override val entries: MutableSet>
116 | get() = super.entries
117 |
118 | override val keys: MutableSet
119 | get() = super.keys
120 |
121 | override val values: MutableCollection
122 | get() = super.values
123 |
124 | override fun removeEldestEntry(p0: MutableMap.MutableEntry?): Boolean {
125 | val result = size > maxCapacity
126 | if (result) {
127 | mEldestEntryRemoved = true
128 | if (mIsRunningSensitive) {
129 | remove(entries.last().key) ?: throw NoSuchElementException()
130 | mEldestEntryRemoved = false
131 | throw IndexOutOfBoundsException(
132 | "The BoundedMap's maxCapacity of $maxCapacity is already reached")
133 | }
134 | }
135 | return result
136 | }
137 |
138 | override fun put(key: K, value: V): V? = runSensitive { super.put(key, value) }
139 |
140 | override fun putAll(from: Map) = runSensitive { super.putAll(from) }
141 |
142 | override fun putIfAbsent(key: K, value: V): V?
143 | = runSensitive { super.putIfAbsent(key, value) }
144 |
145 | @Suppress("ReplacePutWithAssignment")
146 | override fun forcePut(key: K, value: V): Boolean
147 | = checkEldestEntryRemoved { super.put(key, value) }
148 |
149 | override fun forcePutAll(from: Map): Boolean
150 | = checkEldestEntryRemoved { super.putAll(from) }
151 |
152 | override fun forceResize(newSize: Int): Boolean {
153 | maxCapacity = newSize
154 | return if (newSize < size) {
155 | this.iterator().removeAll(size - newSize)
156 | true
157 | } else false
158 | }
159 |
160 | override fun resize(newSize: Int) {
161 | checkResize(size, newSize)
162 | maxCapacity = newSize
163 | }
164 |
165 | private inline fun runSensitive(action: () -> E) : E {
166 | mIsRunningSensitive = true
167 | val result: E = action()
168 | mIsRunningSensitive = false
169 | return result
170 | }
171 |
172 | private inline fun checkEldestEntryRemoved(action: () -> Unit) : Boolean {
173 | action()
174 | val result = mEldestEntryRemoved
175 | mEldestEntryRemoved = false
176 | return result
177 | }
178 |
179 | /**
180 | * Remove [n] elements from [MutableIterator].
181 | * Starts removing from the first [Iterator.next] element.
182 | */
183 | private fun MutableIterator.removeAll(n: Int) {
184 | check(n > 0) { "n must be greater than 0" }
185 | var counter = 0
186 | do {
187 | if (!hasNext()) throw IndexOutOfBoundsException("ERROR: n (= $n) is greater than the " +
188 | "iterators max size (= $counter)!")
189 | if (counter >= n) return
190 | next()
191 | remove()
192 | counter++
193 | } while (true)
194 | }
195 | }
196 |
197 | internal class BoundedMapBuilder : AbstractBoundedMap {
198 |
199 | private constructor(maxCapacity: Int) : super(maxCapacity)
200 | private constructor(maxCapacity: Int, initialCapacity: Int, loadFactor: Float)
201 | : super(maxCapacity, initialCapacity, loadFactor)
202 | private constructor(maxCapacity: Int, initialCapacity: Int)
203 | : super(maxCapacity, initialCapacity)
204 | private constructor(maxCapacity: Int, m: Map?) : super(maxCapacity, m)
205 | private constructor(maxCapacity: Int, initialCapacity: Int, loadFactor: Float,
206 | accessOrder: Boolean)
207 | : super(maxCapacity, initialCapacity, loadFactor, accessOrder)
208 |
209 | companion object {
210 |
211 | fun create(maxCapacity: Int) = BoundedMapBuilder(maxCapacity)
212 |
213 | fun create(maxCapacity: Int, initialCapacity: Int)
214 | = BoundedMapBuilder(maxCapacity, initialCapacity)
215 |
216 | fun create(maxCapacity: Int, initialCapacity: Int, loadFactor: Float)
217 | = BoundedMapBuilder(maxCapacity, initialCapacity, loadFactor)
218 |
219 | fun create(maxCapacity: Int, initialCapacity: Int, loadFactor: Float,
220 | accessOrder: Boolean)
221 | = BoundedMapBuilder(maxCapacity, initialCapacity, loadFactor, accessOrder)
222 |
223 | fun create(maxCapacity: Int, map: Map) = BoundedMapBuilder(maxCapacity, map)
224 |
225 | }
226 | }
227 |
228 | /**
229 | * Creates an empty [MutableBoundedMap].
230 | *
231 | * @return Empty [MutableBoundedMap]
232 | */
233 | fun mutableBoundedMapOf(maxCapacity: Int): MutableBoundedMap
234 | = BoundedMapBuilder.create(maxCapacity)
235 |
236 | /**
237 | * Creates an [MutableBoundedMap] with [elements].
238 | *
239 | * @return [MutableBoundedMap] with [elements]
240 | */
241 | fun mutableBoundedMapOf(maxCapacity: Int, vararg elements: Pair): MutableBoundedMap =
242 | BoundedMapBuilder.create(maxCapacity, mapOf(*elements))
243 |
244 | /**
245 | * Creates an [MutableBoundedMap] with [map].
246 | *
247 | * @return [MutableBoundedMap] with [map]
248 | */
249 | fun mutableBoundedMapOf(maxCapacity: Int, map: Map): MutableBoundedMap =
250 | BoundedMapBuilder.create(maxCapacity, map)
251 |
252 | /**
253 | * Creates an empty [BoundedMap].
254 | *
255 | * @return Empty [BoundedMap]
256 | */
257 | fun boundedMapOf(maxCapacity: Int): BoundedMap = mutableBoundedMapOf(maxCapacity)
258 |
259 | /**
260 | * Creates an [BoundedMap] with [elements].
261 | *
262 | * @return [BoundedMap] with [elements]
263 | */
264 | fun boundedMapOf(maxCapacity: Int, vararg elements: Pair): BoundedMap =
265 | mutableBoundedMapOf(maxCapacity, *elements)
266 |
267 | /**
268 | * Creates an [BoundedMap] with [map].
269 | *
270 | * @return [BoundedMap] with [map]
271 | */
272 | fun boundedMapOf(maxCapacity: Int, map: Map): BoundedMap =
273 | mutableBoundedMapOf(maxCapacity, map)
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/bounded/Utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.bounded
26 |
27 | internal object Utils {
28 |
29 | fun checkResize(currentSize: Int, newSize: Int) {
30 | if (newSize < currentSize) throw IllegalStateException("Resizing would lose data")
31 | }
32 |
33 | fun checkInitialMaxCapacity(initialMaxCapacity: Int) {
34 | if (initialMaxCapacity <= 0) throw IndexOutOfBoundsException(
35 | "The minimum maxCapacity must be greater than 0")
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/observable/list/ListObserver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.observable.list
26 |
27 | interface ListObserver {
28 |
29 | /**
30 | * Manually called, if changes has been made
31 | */
32 | fun notifyDataChanged()
33 |
34 | /**
35 | * Manually called, if changes has been made at [index].
36 | */
37 | fun notifyDataChanged(index: Int)
38 |
39 | /**
40 | * Called when a new item was added.
41 | * Actions that may trigger this event:
42 | */
43 | fun wasAdded(index: Int, element: E)
44 |
45 | /**
46 | * Called when new items were added.
47 | */
48 | fun wasAdded(elements: Map)
49 |
50 | /**
51 | * Called when items were removed.
52 | */
53 | fun wasRemoved(index: Int, element: E)
54 |
55 | /**
56 | * Called when items were removed.
57 | */
58 | fun wasRemoved(elements: Map)
59 |
60 | /**
61 | * Called when a item was replaced by a new item.
62 | */
63 | fun wasReplaced(index: Int, lastElement: E, newElement: E)
64 |
65 | /**
66 | * Called when a item was replaced by a new item.
67 | */
68 | fun wasReplaced(map: Map>)
69 | }
70 |
71 | @Suppress("AddVarianceModifier")
72 | class ListObserverDSL private constructor() {
73 |
74 | companion object {
75 |
76 | private const val ERROR_MSG = "Set safetyMode to false in order to disable this error"
77 |
78 | fun create(listObserverDSL: ListObserverDSL.() -> Unit): ListObserver {
79 | return ListObserverDSL().apply(listObserverDSL).run {
80 | object : ListObserver {
81 | override fun notifyDataChanged() = mNotifyDataChanged()
82 |
83 | override fun notifyDataChanged(index: Int) = mNotifyDataChangedIndex(index)
84 |
85 | override fun wasAdded(index: Int, element: E) = mWasAdded(index, element)
86 |
87 | override fun wasAdded(elements: Map) = mWasAddedMultiple(elements)
88 |
89 | override fun wasRemoved(index: Int, element: E) = mWasRemoved(index, element)
90 |
91 | override fun wasRemoved(elements: Map) = mWasRemovedMultiple(elements)
92 |
93 | override fun wasReplaced(index: Int, lastElement: E, newElement: E)
94 | = mWasReplaced(index, lastElement, newElement)
95 |
96 | override fun wasReplaced(map: Map>) = mWasReplacedMultiple(map)
97 |
98 | }
99 | }
100 | }
101 | }
102 |
103 | private var mNotifyDataChanged: () -> Unit = { default() }
104 | private var mNotifyDataChangedIndex: (Int) -> Unit = { default() }
105 | private var mWasAdded: (Int, E) -> Unit = { _, _ -> }
106 | private var mWasAddedMultiple: (Map) -> Unit = { default() }
107 | private var mWasRemoved: (Int, E) -> Unit = { _, _ -> default() }
108 | private var mWasRemovedMultiple: (Map) -> Unit = { default() }
109 | private var mWasReplaced: (Int, E, E) -> Unit = { _, _, _ -> default() }
110 | private var mWasReplacedMultiple: (Map>) -> Unit = { default() }
111 |
112 | private fun default() {
113 | if (safetyMode) throw NotImplementedError(ERROR_MSG)
114 | }
115 |
116 | /**
117 | * If true, all methods of [ListObserver] that has not been added by [ListObserverDSL] will throw [NotImplementedError].
118 | */
119 | var safetyMode: Boolean = true
120 |
121 | /**
122 | * @see [ListObserver.notifyDataChanged]
123 | */
124 | fun notifyDataChanged(action: () -> Unit) {
125 | mNotifyDataChanged = action
126 | }
127 |
128 | /**
129 | * @see [ListObserver.notifyDataChanged]
130 | */
131 | fun notifyDataChangedByIndex(action: (index: Int) -> Unit) {
132 | mNotifyDataChangedIndex = action
133 | }
134 |
135 | /**
136 | * @see [ListObserver.wasAdded]
137 | */
138 | fun wasAdded(action: (index: Int, element: E) -> Unit) {
139 | mWasAdded = action
140 | }
141 |
142 | /**
143 | * @see [ListObserver.wasAdded]
144 | */
145 | fun wasAdded(action: (elements: Map) -> Unit) {
146 | mWasAddedMultiple = action
147 | }
148 |
149 | /**
150 | * @see [ListObserver.wasRemoved]
151 | */
152 | fun wasRemoved(action: (index: Int, element: E) -> Unit) {
153 | mWasRemoved = action
154 | }
155 |
156 | /**
157 | * @see [ListObserver.wasRemoved]
158 | */
159 | fun wasRemoved(action: (Map) -> Unit) {
160 | mWasRemovedMultiple = action
161 | }
162 |
163 | /**
164 | * @see [ListObserver.wasReplaced]
165 | */
166 | fun wasReplaced(action: (index: Int, lastElement: E, newElement: E) -> Unit) {
167 | mWasReplaced = action
168 | }
169 |
170 | /**
171 | * @see [ListObserver.wasReplaced]
172 | */
173 | fun wasReplaced(action: (Map>) -> Unit) {
174 | mWasReplacedMultiple = action
175 | }
176 | }
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/observable/list/Observable.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.observable.list
26 |
27 | interface Observable {
28 |
29 | val observer: ListObserver
30 |
31 | fun notifyDataChanged()
32 |
33 | fun notifyDataChanged(index: Int)
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/observable/list/ObservableList.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.observable.list
26 |
27 | import io.bluego.powercollections.observable.list.adapter.ObservableListAdapter
28 | import java.util.function.Predicate
29 | import java.util.function.UnaryOperator
30 |
31 | interface ObservableList: List
32 |
33 | interface MutableObservableList: ObservableList, MutableList, Observable {
34 |
35 | fun runSilentChanges(silentChanges: MutableList.() -> Unit)
36 |
37 | }
38 |
39 | abstract class AbstractObservableList: ArrayList, MutableObservableList
40 | {
41 | private val mAdapter: ObservableListAdapter, E> by lazy {
42 | ObservableListAdapter(observer, this)
43 | }
44 |
45 | constructor(initialCapacity: Int, observer: ListObserver) : super(initialCapacity)
46 | {
47 | this.observer = observer
48 | }
49 |
50 | constructor(observer: ListObserver) : super() {
51 | this.observer = observer
52 | }
53 |
54 | constructor(c: Collection?, observer: ListObserver) : super(c)
55 | {
56 | this.observer = observer
57 | }
58 |
59 | final override var observer: ListObserver
60 | private set
61 |
62 | override fun notifyDataChanged() = mAdapter.notifyDataChanged()
63 |
64 | override fun notifyDataChanged(index: Int) = mAdapter.notifyDataChanged(index)
65 |
66 | override fun runSilentChanges(silentChanges: MutableList.() -> Unit) = mAdapter.runSilentChanges(silentChanges)
67 |
68 | override fun add(element: E): Boolean = mAdapter.add(element) { e -> super.add(e) }
69 |
70 | override fun add(index: Int, element: E) = mAdapter.add(index, element) { i, e -> super.add(i, e) }
71 |
72 | override fun addAll(index: Int, elements: Collection): Boolean
73 | = mAdapter.addAll(index, elements) { i, collection -> super.addAll(i, collection) }
74 |
75 | override fun iterator(): MutableIterator = super.iterator()
76 |
77 | override fun listIterator(): MutableListIterator = super.listIterator()
78 |
79 | override fun listIterator(index: Int): MutableListIterator = super.listIterator(index)
80 |
81 | override fun subList(fromIndex: Int, toIndex: Int): MutableList
82 | = mAdapter.subList(fromIndex, toIndex) { fi, ti -> super.subList(fi, ti) }
83 |
84 | override fun addAll(elements: Collection): Boolean =
85 | mAdapter.addAll(elements) { collection -> super.addAll(collection) }
86 |
87 | override fun clear() = mAdapter.clear { super.clear() }
88 |
89 | override fun remove(element: E): Boolean = mAdapter.remove(element) { e -> super.remove(e) }
90 |
91 | override fun removeAll(elements: Collection): Boolean
92 | = mAdapter.removeAll(elements) { collection -> super.removeAll(collection) }
93 |
94 | override fun removeAt(index: Int): E = mAdapter.removeAt(index) { i -> super.removeAt(i) }
95 |
96 | override fun set(index: Int, element: E): E = mAdapter.set(index, element) { i, e -> super.set(i, e) }
97 |
98 | override fun replaceAll(p0: UnaryOperator) = mAdapter.replaceAll(p0) { super.replaceAll(p0) }
99 |
100 | override fun retainAll(elements: Collection): Boolean = mAdapter.retainAll(elements, this::listIterator)
101 |
102 | override fun removeIf(p0: Predicate): Boolean
103 | = mAdapter.removeIf(p0) { predicate -> super< ArrayList>.removeIf(predicate) }
104 |
105 | override fun removeRange(fromIndex: Int, toIndex: Int)
106 | = mAdapter.removeRange(fromIndex, toIndex) { fi, ti -> super.removeRange(fi, ti) }
107 |
108 | }
109 |
110 | class ArrayObservableList : AbstractObservableList
111 | {
112 | constructor(initialCapacity: Int, mObserver: ListObserver) : super(initialCapacity, mObserver)
113 | constructor(mObserver: ListObserver) : super(mObserver)
114 | constructor(c: Collection?, mObserver: ListObserver) : super(c, mObserver)
115 | }
116 |
117 |
118 | /**
119 | * Creates an empty [MutableObservableList].
120 | *
121 | * @return Empty [MutableObservableList]
122 | */
123 | fun mutableObservableListOf(observer: ListObserver)
124 | : MutableObservableList = ArrayObservableList(observer)
125 |
126 | /**
127 | * @see ListObserverDSL
128 | * @see mutableObservableListOf
129 | */
130 | fun mutableObservableListOf(observer: ListObserverDSL.() -> Unit) : MutableObservableList
131 | = mutableObservableListOf(ListObserverDSL.create(observer))
132 |
133 | /**
134 | * Creates an [MutableObservableList] with [elements].
135 | *
136 | * @return [MutableObservableList] with [elements]
137 | */
138 | fun mutableObservableListOf(
139 | observer: ListObserver,
140 | vararg elements: E): MutableObservableList
141 | = ArrayObservableList(listOf(*elements), observer)
142 |
143 | /**
144 | * @see ListObserverDSL
145 | * @see mutableObservableListOf
146 | */
147 | fun mutableObservableListOf(
148 | observer: ListObserverDSL.() -> Unit,
149 | vararg elements: E) : MutableObservableList
150 | = mutableObservableListOf(ListObserverDSL.create(observer), *elements)
151 |
152 | /**
153 | * Creates an empty [ObservableList].
154 | *
155 | * @return Empty [ObservableList]
156 | */
157 | fun observableListOf(
158 | observer: ListObserver) : ObservableList
159 | = mutableObservableListOf(observer)
160 |
161 | /**
162 | * @see ListObserverDSL
163 | * @see observableListOf
164 | */
165 | fun observableListOf(observer: ListObserverDSL.() -> Unit) : ObservableList
166 | = mutableObservableListOf(observer)
167 |
168 | /**
169 | * Creates an [ObservableList] with [elements].
170 | *
171 | * @return [ObservableList] with [elements]
172 | */
173 | fun observableListOf(observer: ListObserver, vararg elements: E) : ObservableList
174 | = mutableObservableListOf(observer, *elements)
175 |
176 | /**
177 | * @see ListObserverDSL
178 | * @see observableListOf
179 | */
180 | fun observableListOf(observer: ListObserverDSL.() -> Unit, vararg elements: E): ObservableList
181 | = mutableObservableListOf(observer, *elements)
--------------------------------------------------------------------------------
/src/main/kotlin/io/bluego/powercollections/observable/list/adapter/ObservableListAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2018 Felix Pröhl
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 io.bluego.powercollections.observable.list.adapter
26 |
27 | import io.bluego.powercollections.observable.list.ListObserver
28 | import java.util.function.Predicate
29 | import java.util.function.UnaryOperator
30 | import kotlin.properties.Delegates
31 |
32 | internal open class ObservableListAdapter, E>(private val mObserver: ListObserver,
33 | private val mList: T)
34 | {
35 | protected var isSilent = false
36 |
37 | open fun notifyDataChanged() = mObserver.notifyDataChanged()
38 |
39 | open fun notifyDataChanged(index: Int) = mObserver.notifyDataChanged(index)
40 |
41 | open fun runSilentChanges(silentChanges: T.() -> Unit) {
42 | isSilent = true
43 | silentChanges(mList)
44 | isSilent = false
45 | }
46 |
47 | open fun add(element: E, add: (E) -> Boolean): Boolean {
48 | return add(element).apply { if (!isSilent) mObserver.wasAdded(mList.lastIndex, element) }
49 | }
50 |
51 | open fun add(index: Int, element: E, add: (Int, E) -> Unit) {
52 | add(index, element).also { if (!isSilent) mObserver.wasAdded(mList.lastIndex, element) }
53 | }
54 |
55 | open fun addAll(index: Int, elements: Collection, addAll: (Int, Collection) -> Boolean)
56 | : Boolean
57 | {
58 | val startIndex = mList.size
59 | return addAll(index, elements).also {
60 | if (!isSilent && it) mObserver.wasAdded(
61 | elements.mapIndexed { index, e -> startIndex + index to e }.toMap())
62 | }
63 | }
64 |
65 | open fun addAll(elements: Collection, addAll: (Collection) -> Boolean): Boolean {
66 | val startIndex = mList.size
67 | return addAll(elements).also {
68 | if (!isSilent && it) mObserver.wasAdded(
69 | elements.mapIndexed { index, e -> startIndex + index to e }.toMap())
70 | }
71 | }
72 |
73 | open fun clear(clear: () -> Unit) {
74 | if (!isSilent) {
75 | val list = mList.mapIndexed { index, e -> Pair(index, e) }.toMap()
76 | clear()
77 | mObserver.wasRemoved(list)
78 | } else clear()
79 | }
80 |
81 | open fun remove(element: E, remove: (E) -> Boolean): Boolean {
82 | return if (!isSilent) {
83 | val index = mList.indexOf(element)
84 | return if (index != -1) {
85 | val result = remove(element)
86 | assert(result) { "Result cannot be false. There must be a bug..." }
87 | mObserver.wasRemoved(index, element)
88 | result
89 | } else false
90 | } else remove(element)
91 | }
92 |
93 | open fun removeIf(p0: Predicate, removeIf: (Predicate) -> Boolean): Boolean {
94 | throw NotImplementedError()
95 | }
96 |
97 | open fun removeAt(index: Int, removeAt: (Int) -> E): E {
98 | return removeAt(index).also { if (!isSilent) mObserver.wasRemoved(index, it) }
99 | }
100 |
101 | open fun removeAll(elements: Collection, removeAll: (Collection) -> Boolean): Boolean {
102 | return if (!isSilent) {
103 | val toBeRemoved = elements.mapNotNull {
104 | val index = mList.indexOf(it)
105 | if (index > -1) Pair(index, it)
106 | else null
107 | }.toMap()
108 | if (toBeRemoved.isNotEmpty()) {
109 | val result = removeAll(elements)
110 | mObserver.wasRemoved(toBeRemoved)
111 | assert(result) { "Result must not be false. There must be a bug..." }
112 | result
113 | } else false
114 | } else removeAll(elements)
115 | }
116 |
117 | open fun removeRange(fromIndex: Int, toIndex: Int, removeRange: (Int, Int) -> Unit) {
118 | val rng = 0 .. mList.size
119 | var removedRange by Delegates.notNull