{"id":16854852,"url":"https://github.com/tommyettinger/jdkgdxds","last_synced_at":"2025-03-22T06:31:06.614Z","repository":{"id":37275364,"uuid":"293246546","full_name":"tommyettinger/jdkgdxds","owner":"tommyettinger","description":"Java data structures for primitive and/or Object items","archived":false,"fork":false,"pushed_at":"2024-04-16T06:33:01.000Z","size":19910,"stargazers_count":23,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-17T05:16:26.613Z","etag":null,"topics":["case-insensitive","data-structures","deque","hashmap","hashset","insertion-order","java-8","list","primitive-types"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tommyettinger.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null}},"created_at":"2020-09-06T09:47:23.000Z","updated_at":"2024-04-19T05:22:57.393Z","dependencies_parsed_at":"2023-10-25T22:32:28.909Z","dependency_job_id":"37b6083d-46a8-40b9-9253-588ff032da1b","html_url":"https://github.com/tommyettinger/jdkgdxds","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tommyettinger%2Fjdkgdxds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tommyettinger%2Fjdkgdxds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tommyettinger%2Fjdkgdxds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tommyettinger%2Fjdkgdxds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tommyettinger","download_url":"https://codeload.github.com/tommyettinger/jdkgdxds/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244918500,"owners_count":20531682,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["case-insensitive","data-structures","deque","hashmap","hashset","insertion-order","java-8","list","primitive-types"],"created_at":"2024-10-13T13:57:23.449Z","updated_at":"2025-03-22T06:31:06.604Z","avatar_url":"https://github.com/tommyettinger.png","language":"Java","funding_links":[],"categories":["数据结构"],"sub_categories":["文件同步"],"readme":"# jdkgdxds\nMaking libGDX's data structures implement JDK interfaces\n\n## What is this?\n\nSome background, first... libGDX has its own data structures, and they're mostly nice to work with. They have fast iteration by\nreusing iterators, they are designed to use low memory (both in the way the hashed maps and sets are designed and by allowing\nprimitive data types for many data structures), and they have some nice features that aren't present in all standard libraries,\nlike optional insertion-ordering. The problem with libGDX's data structures is that they are extremely limited in what interfaces\nthey implement, typically implementing no more than `java.io.Serializable` and `java.lang.Iterable`. They also are limited to Java\n6 or 7 features, despite Java 8 features being available on Android and GWT for some time now, and even reaching iOS soon, if not\nalready. So what is this? It is a redo of libGDX's data structures so that they implement common JDK interfaces like\n`java.util.Map`, `java.util.List`, and `java.util.Set`, plus their parts that can't implement generic interfaces use interfaces\ndefined here, such as `PrimitiveCollection`, `Ordered`, `FloatIterator`, `LongComparator`, and so on. It also sharply increases\nthe number of primitive-backed maps; they don't implement `java.util.Map`, but often implement other interfaces here. As an\nexample, `com.github.tommyettinger.ds.IntLongOrderedMap` implements `com.github.tommyettinger.ds.Ordered.OfInt`, which specifies\nthat the order of items (keys here) is represented by a `com.github.tommyettinger.ds.IntList` containing those keys.\n\n## OK, how do I use it?\n\nYou use jdkgdxds much like the standard JDK collections, just extended for primitive types. The types of data structure offered\nhere are lists (array-backed, like `ArrayList`), deques (double-ended queues, like `ArrayDeque` but also allowing access inside\nthe deque), sets (allowing only unique items, and coming in unordered and insertion-ordered varieties), maps (allowing unique keys\nassociated with values, and also coming in unordered and insertion-ordered varieties), bags (unordered lists, with fast removal\nbut unpredictable iteration order) and some extra types. The Object-based classes are generic, centered around\n`com.github.tommyettinger.ds.ObjectList`, `com.github.tommyettinger.ds.ObjectDeque`,`com.github.tommyettinger.ds.ObjectSet`, and\n`com.github.tommyettinger.ds.ObjectObjectMap`; `ObjectOrderedSet` and `ObjectObjectOrderedMap` are also here and extend the other\nSet and Map. These are effectively replacements for `com.badlogic.gdx.utils.Array`, `com.badlogic.gdx.utils.Queue`,\n`com.badlogic.gdx.utils.ObjectSet`, `com.badlogic.gdx.utils.ObjectMap`, `com.badlogic.gdx.utils.OrderedSet`, and\n`com.badlogic.gdx.utils.OrderedMap`. As nice as it would be to just call these by the same names (except Array and Queue, those\nare just confusing), we have other kinds of Object-keyed Maps, and other kinds of insertion-ordered Maps, so `ObjectMap` is now\n`ObjectObjectMap` because it has Object keys and Object values, while `OrderedMap` is now `ObjectObjectOrderedMap`, because of the\nsame reason.\n\nPrimitive-backed collections support `int` and `long` keys, and `int`, `long`, or `float` values; all primitive types are\navailable for lists, deques, and bags. So, there's `IntSet` and `LongSet`, with ordered variants `IntOrderedSet` and\n`LongOrderedSet`, while their map counterparts are more numerous. Most of the primitive lists are very similar, only changing the\nnumeric type, but there are some small changes for `CharList` (which doesn't define math operations on its items) and\n`BooleanList` (which defines logical operations but not math ones). The deques don't currently implement math operations on their\nitems. Each of the bag classes extends a list class, and  changes its behavior on certain operations (like `remove()`, which takes\n`O(1)` time instead of `O(n)`, but rearranges the items), while keeping the other operations mostly the same. A minor point to\nnote is that libGDX also supplies primitive arrays for all types, *except* that it doesn't have `DoubleArray`, where this library\ndoes provide `DoubleList` (as well as `DoubleBag` and `DoubleQueue`). As for the maps...\n\nThere's `IntFloatMap`, `IntFloatOrderedMap`, `IntIntMap`, `IntIntOrderedMap`, `IntLongMap`, `IntLongOrderedMap`,\n`IntObjectMap`, `IntObjectOrderedMap`, `LongFloatMap`, `LongFloatOrderedMap`, `LongIntMap`, `LongIntOrderedMap`,\n`LongLongMap`, `LongLongOrderedMap`, `LongObjectMap`, and `LongObjectOrderedMap`, so I hope that's enough. Then again, there's\nstill `ObjectFloatMap`, `ObjectFloatOrderedMap`, `ObjectIntMap`, `ObjectIntOrderedMap`, `ObjectLongMap`, and\n`ObjectLongOrderedMap` for the primitive-valued maps with Object keys. There's `IdentityObjectMap` and `IdentityObjectOrderedMap`,\nwhich compare keys by reference identity (not by `equals()`) and hash their keys using their identity hash code. There's the\nunusual `HolderSet` and `HolderOrderedSet`, which take an \"extractor\" function when constructed and use it to hash items by an\nextracted value; this lets you, for example, make a HolderSet of \"Employee\" objects and look up a full Employee given only their\nUUID. In that case, an Employee's value could change, and the result of hashCode() on an Employee would change, but as long as the\nUUID of the Employee stays the same, the same Employee will be found by methods like `get()` and `contains()`. `NumberedSet` wraps\nan `ObjectIntOrderedMap` and makes it so that Object keys can be looked up by index (using the standard ordered set methods like\n`getAt()`), but also so that their `indexOf()` method runs in constant time instead of linear time. This is at the expense of\nslower removal from the middle of the NumberedSet; that class doesn't implement insertion in the middle of the NumberedSet either.\nThere's also a close relative of libGDX's `BinaryHeap` class, but the one here implements the JDK's `Queue`.\n\nThere are some useful varieties of Map and Set here that don't show up very often in libraries. There's a `CaseInsensitiveMap`\nand a `CaseInsensitiveOrderedMap` that require `CharSequence` keys (such as String or StringBuilder), but treat them as\ncase-insensitive, and allows a generic Object type for its values. A more generic solution to the same sort of problem lies in\n`FilteredStringSet`, `FilteredStringOrderedSet`, `FilteredStringMap`, and `FilteredStringOrderedMap`. These filtered-String data\nstructures contain a filter (a predicate that determines if a char in a String should be read or skipped for hashing and equality\ncomparison purposes) and an editor (a function that can change what char is actually used in a hash or equality comparison). These\ndata structures can be used to implement the CaseInsensitive maps and sets (except one needs a key to be a String and where the\nother uses a CharSequence) if the editor is `Character::toUpperCase`. In addition, they can do something like filter the Strings\nso only the letter characters are considered (whitespace, punctuation, and numbers could all be skipped) using\n`Character::isLetter` as the filter (or RegExodus' `Category.L::contains` for GWT compatibility). This goes on, to even more\nfiltered data structures: `FilteredIterableSet`, `FilteredIterableOrderedSet`, `FilteredIterableMap`, and\n`FilteredIterableOrderedMap`, which act like the filtered-String data structures but work on keys or items that are each an\nIterable (type `I`) of sub-items/sub-keys (type `T` or `K`). The Iterable must not be modified while it is a key, or at least not\nmodified in a way that changes what is considered by the filter and editor.\n\nNew in version 1.5.2 are nearly-drop-in replacements for `java.util.EnumSet` and `java.util.EnumMap`, named, ah, `EnumSet` and\n`EnumMap`. The main difference with these versions is that they can be constructed with a zero-argument constructor (and that is\nvital for serialization done without using `java.io.Serializable`). Other than that, they are very similar to the `java.util`\nclasses, except that where the `java.util` types need a `Class` of an enum type when they are constructed, the types here can\ntake the result of calling `values()` on an enum type when constructed, or can figure out those values when an enum constant is\nadded to the Set or Map. Both the `EnumSet` here and in the standard library are very memory-efficient; the one here uses a bitset\nmade from a simple `int[]` (for better GWT performance). `EnumMap` is also rather efficient; the one here only needs to store the\nkey universe (another name for the result of `values()` mentioned above) and exactly as many value slots as there are items in the\nkey universe. `EnumMap` does also store a default value, which is usually `null`, and some other data.\n\nThe library includes expanded interfaces for these to implement, like the aforementioned `Ordered` interface,\n`PrimitiveCollection` is akin to Java 8's `PrimitiveIterator`, some `float`-based versions of primitive specializations where\nthe JDK only offers `int`, `long`, and `double`, and primitive `Comparator`s (which are usable as Java 8\n`FunctionalInterface`s, but don't implement that type for RoboVM compatibility). There is also `EnhancedCollection`,\nwhich is used to add default methods to various classes here.\n\nYou can extend essentially all classes in jdkgdxds, and it's meant to be friendlier to inherit from than the libGDX collections.\nThe Object-keyed maps and sets have protected `place()` and `equate()` methods to allow changing the behavior of hashing (with\n`place()`) and equality (with `equate()`). If you, for instance, wanted to use `char[]` as a key type in a map, the normal\nbehavior of an array in a hashed collection like a map or set is basically unusable. Arrays are compared by reference rather than\nby value, so you would need the exact `char[]` you had put in to get a value out. They're also hashed by identity, which means\nmore than just the equality comparison needs to change. Thankfully, in jdkgdxds you can override `place()` to\n`return Arrays.hashCode((char[])item) \u0026 mask;` and `equate()` to `return Objects.deepEquals(left, right);`; this uses standard JDK\nmethods to hash and compare arrays, and will work as long as you don't edit any array keys while they are in the map. There are\nother potential uses for this extensibility, like the case-insensitive CharSequence comparison that `CaseInsensitiveMap` and\nrelated classes use, or some form of fuzzy equality for float or double keys.\n\nMost of the ordered data structures now allow `addAll()` or `putAll()` to specify a range with a starting index and count of how\nmany items to copy from the data structure passed as a parameter (often some kind of `Ordered`). This also optionally takes a\nstarting index to add the range at in the order. When constructing one of these ordered data structures with a copy constructor,\nyou usually have the option to copy only a range of the data structure you are copying. Similarly, there's often a `removeRange()`\nmethod, also present on all ordered types except deques (and it takes a start and end index, rather than a start index and count,\nwhich imitates the method by that name in the JDK, not the similar one in libGDX's Array class). All of these are intended to be\nuseful for imitating disjoint sets, and other ways of isolating part of a data structure. You might shuffle an `ObjectList`, then\nmake two more distinct `ObjectList`s by copying different ranges from the shuffled \"deck,\" for example.\n\nAn oddity in libGDX's Array classes (such as IntArray, FloatArray, and of course Array) is that their removeAll() method doesn't\nact like removeAll() in the JDK List interface. In `List.removeAll(Collection)`, when the Collection `c` contains an item even\nonce, every occurrence of that item is removed from the `List`. In libGDX, if an item appears once in the parameter, it is removed\nonce from the Array; similarly, if it appears twice, it is removed twice. Here, we have the List behavior for removeAll(), but\nalso keep the Array behavior in the newly-added `removeEach()`.\n\nHere, we rely on some shared common functionality in two other libraries (by the same author).\n[Digital](https://github.com/tommyettinger/digital) has core math code, including the BitConversion and Base classes that were\nhere earlier. [Funderby](https://github.com/tommyettinger/funderby) provides functional interfaces for primitive types, with a\nrather large amount of total combinations. [Juniper](https://github.com/tommyettinger/juniper) has the random number generators\nthat also used to be here. Having these as external libraries allows someone's LibraryA that really only needs the core math from\ndigital to only use that, but for projects that need both jdkgdxds and LibraryA, the shared dependency won't be duplicated.\n\nVersions of jdkgdxds before 1.0.2 used \"Fibonacci hashing\" to mix `hashCode()` results. This involved multiplying the hash by a\nspecific constant (2 to the 64, divided by the golden ratio) and shifting the resulting bits so only an upper portion was used\n(its size depended on the size of the backing table or tables). This works well in most situations, but a few were found where it\nhad catastrophically bad performance. The easiest case to reproduce was much like [this bug in Rust's standard library](https://accidentallyquadratic.tumblr.com/post/153545455987/rust-hash-iteration-reinsertion),\nrelating to reinserting already-partially-colliding keys in a large map or set. Starting in 1.0.2, we take a different route to\nmixing `hashCode()` results -- instead of multiplying by a specific constant every time, we change the constant every time we need\nto resize the backing tables. Everything else is the same. This simple change allows one test, inserting 2 million\nspecifically-chosen Strings, to complete in under 2 seconds, when without the change, it wouldn't complete given 77 minutes (a\nspeedup of over 3 orders of magnitude). In 1.1.1, the strategy for picking a constant changed, and now the constant is picked from\na table of 512 known-good multipliers, appropriately called `Utilities.GOOD_MULTIPLIERS`. You can change the behavior of a map or\nset when it chooses its `hashMultiplier` by overriding `resize(int)`.\n\nStarting in jdkgdxds 1.5.4, there is substantially more code to support converting data structures to String, either for legibly\nprinting them or for serialization (such as with JSON). The `appendTo()` method is at the core of this; one overload takes many\nparameters, but more commonly-used overloads of that and `toString()` take few or no parameters. You can give `appendTo()`\nfunctions, method references, and/or lambdas that take a `StringBuilder` and an item to append to that `StringBuilder`, and return\nthat same `StringBuilder`. An example is the method reference `Base::appendReadable`, which can take a type for which Java has a\nliteral representation available, and appends that representation, such as `3.14f` for a `float` or `999999999999L` for a `long`.\nThis can be useful if you want some special representation for data, such as to print some particular number (or more likely, a\nnumber in some range that defies find-and-replace) you're looking for with exclamation points around it, like `!!!42!!!`, using a\nlambda that was made to check for `42`. Passing in user-definable functions hasn't been done much in jdkgdxds, but it may see much\nmore use in the future.\n\nStarting in jdkgdxds 1.6.4, there's more support for receiving iterator types in any of the various data structures,\nand there are wrappers around iterators provided to change what these iterators can provide to a constructor or\n`addAll()` call, for instance. Each of these wrappers has variants for all primitive types:\n\n- FilteringIterator skips items unless they match a predicate.\n- StridingIterator skips a fixed number of items at a time, repeatedly.\n- EditingIterator runs a function on each item and returns what that function does.\n  - There's also AlteringIterator, which has two type parameters since it receives one from the iterator and returns another.\n- LimitingIterator only returns at most a set amount of items, and terminates early if that amount has been reached. \n- More iterator wrappers will probably be added in the future.\n\n## How do I get it?\n\nYou have two options: Maven Central for stable releases, or JitPack to select a commit of your choice to build.\n\nMaven Central uses the Gradle dependency:\n```\napi \"com.github.tommyettinger:jdkgdxds:1.8.0\"\n```\nYou can use `implementation` instead of `api` if you don't use the `java-library` plugin.\nIt does not need any additional repository to be specified in most cases; if it can't be found, you may need the repository\n`mavenCentral()` or to remove the `mavenLocal()` repo. Jdkgdxds has dependencies on [digital](https://github.com/tommyettinger/digital)\n(which provides common math code meant for use by multiple projects), [funderby](https://github.com/tommyettinger/funderby)\n(Java 8 functional interfaces for primitive types), and for annotations only, [checker-qual](https://github.com/typetools/checker-framework). The\nversion for the `digital` dependency is 0.6.0 (you can specify it manually with the core dependency\n`api \"com.github.tommyettinger:digital:0.6.0\"`). Funderby has only changed a bit since its initial release, and is on version\n0.1.2 (you can specify it manually with `implementation \"com.github.tommyettinger:funderby:0.1.2\"`). The version for\n`checker-qual` is 3.42.0 , and  is expected to go up often because checker-qual rather-frequently updates to handle JDK changes.\nEarlier versions of jdkgdxds used `jsr305` instead of `checker-qual`, which had some potential problems on Java 9 and up (not to\nmention that JSR305 is currently unmaintained). You can manually specify a `checker-qual` version with\n`api \"org.checkerframework:checker-qual:3.42.0\"`.\n\nIf you have an HTML module, add:\n```\nimplementation \"com.github.tommyettinger:funderby:0.1.2:sources\"\nimplementation \"com.github.tommyettinger:digital:0.6.0:sources\"\nimplementation \"com.github.tommyettinger:jdkgdxds:1.8.0:sources\"\n```\nto its\ndependencies, and in its `GdxDefinition.gwt.xml` (in the HTML module), add\n```\n\u003cinherits name=\"com.github.tommyettinger.funderby\" /\u003e\n\u003cinherits name=\"com.github.tommyettinger.digital\" /\u003e\n\u003cinherits name=\"com.github.tommyettinger.jdkgdxds\" /\u003e\n```\nin with the other `inherits` lines. You shouldn't need to specify checker-qual in GWT dependencies.\nUsing jdkgdxds 1.6.2 or later (or preferably, the current version) is strongly encouraged for GWT applications for\nperformance reasons.\n\nIf you have an Android module, you may need to ensure that multi-dex and desugaring are enabled. Projects generated with\ngdx-liftoff that target Java 8 or higher have this already, but projects made with gdx-setup or manually do not.\nIf these aren't already enabled, add:\n```\nandroid.defaultConfig.multiDexEnabled true\nandroid.compileOptions.coreLibraryDesugaringEnabled true\n\n// These can be higher versions, but typically no greater than JDK 11\nandroid.compileOptions.sourceCompatibility JavaVersion.VERSION_1_8\nandroid.compileOptions.targetCompatibility JavaVersion.VERSION_1_8\n\ndependencies {\n\tcoreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'\n}\n```\nto whatever module uses an `android` or `com.android.application` plugin. The `desugar_jdk_libs` version should only be updated if\nyou have checked for compatibility with your Android Gradle Plugin version; see [Android docs](https://developer.android.com/studio/write/java8-support#library-desugaring-versions).\nIn short, if you use Android Gradle Plugin 7.4.0 or later (the default for gdx-liftoff projects is 8.5.2), you should use\n`'com.android.tools:desugar_jdk_libs:2.0.4'`. If you use Android Gradle Plugin 7.3.0, you should use\n`'com.android.tools:desugar_jdk_libs:1.2.3'`. You may need to set the `minSdkVersion`\nto a higher value, depending on where it is already; 19 is known to work, and 16 probably works.\n\nThe dependency (and `inherits` line) on digital is not necessary for jdkgdxds 0.2.8, but is necessary starting in 1.0.3 and later.\nThe dependency and `inherits` line for funderby is new in 1.0.4 . Versions 1.0.1 and 1.0.2 also depended on\n[juniper](https://github.com/tommyettinger/juniper) 0.1.0 ; if you intend to use the\nrandomized algorithms here (like shuffles), then depending on Juniper (0.6.3) might be a good idea, though it is still optional.\nAnother option for random number generation, if you use libGDX, is [cringe](https://github.com/tommyettinger/cringe), which is more closely-integrated with libGDX.\nThe versions are expected to increase somewhat for digital as bugs are found and fixed, but a low version number isn't a bad thing\nfor that library -- both digital and juniper were both mostly drawn from code in this library, and were tested significantly here.\nThe version for funderby is expected to stay at or around 0.1.2, since it is a relatively small library and is probably complete.\n\nYou can build specific, typically brand-new commits on JitPack.\n[JitPack has instructions for any recent commit you want here](https://jitpack.io/#tommyettinger/jdkgdxds/5740b3e4f1).\nTo reiterate, you add `maven { url 'https://jitpack.io' }` to your project's `repositories` section, just **not** the one inside\n`buildscript` (that just applies to the Gradle script itself, not your project). Then you can add\n`implementation 'com.github.tommyettinger:jdkgdxds:5740b3e4f1'` or `api 'com.github.tommyettinger:jdkgdxds:5740b3e4f1'`, depending\non what your other dependencies use, to your project or its core module (if there are multiple modules, as in a typical libGDX\nproject). If you have an HTML module, add:\n```\nimplementation \"com.github.tommyettinger:funderby:0.1.2:sources\"\nimplementation \"com.github.tommyettinger:digital:0.6.0:sources\"\nimplementation \"com.github.tommyettinger:jdkgdxds:5740b3e4f1:sources\"\n```\nto its\ndependencies, and in its `GdxDefinition.gwt.xml` (in the HTML module), add\n```\n\u003cinherits name=\"com.github.tommyettinger.funderby\" /\u003e\n\u003cinherits name=\"com.github.tommyettinger.digital\" /\u003e\n\u003cinherits name=\"com.github.tommyettinger.jdkgdxds\" /\u003e\n```\nin with the other `inherits` lines. `5740b3e4f1` is an example of a recent commit, and can be\nreplaced with other commits shown on JitPack.\n\nThere is an optional dependency, [jdkgdxds-interop](https://github.com/tommyettinger/jdkgdxds_interop), that provides code to\ntransfer libGDX data structures to and from jdkgdxds data structures, and more importantly, to store any`*` jdkgdxds classes using\nlibGDX's `Json` class. The asterisk is because `IdentityMap` and `IdentityOrderedMap` don't make sense to serialize, while\n`HolderSet` and `HolderOrderedSet` can't be serialized easily because their behavior depends on a `Function`. For historical\nreasons, jdkgdxds-interop also can serialize classes from digital and juniper. Dependency information is provided in the\njdkgdxds-interop README.md .\n\nAnother optional dependency, [kryo-more](https://github.com/tommyettinger/kryo-more), allows serializing jdkgdxds data structures\nefficiently on non-GWT platforms (using [Kryo](https://github.com/EsotericSoftware/kryo) 5.x for binary serialization).\nDependency information is provided in the kryo-more README.md .\n\nYou can also use [Apache Fury](https://fury.apache.org) to serialize these data structures by using\n[tantrum](https://github.com/tommyettinger/tantrum). The tantrum README.md has dependency information. Fury can be\nfaster than Kryo, and despite being \"Incubating\" at the Apache Foundation, I have so-far encountered no bugs with it in\npractice. I have found a mystery bug in Kryo 5.0 and up, with a specific type that overwrites the start of the\nserialized data file, making it invalid. Actually, I've found it twice, for two unrelated types. That is what caused me\nto seek out alternatives to Kryo, and Fury works well. \n\n## Updating to 1.0.1\n\nThe 1.0.1 release is a more significant set of breaking changes, but thankfully, most of the changes have been very easy to adjust\nto in practice. First, the core math utilities in `BitConversion` and `Base` were moved into the\n[digital](https://github.com/tommyettinger/digital) library. Then, the random number generators that were here were moved to the\n[juniper](https://github.com/tommyettinger/juniper) library. Because of changes in juniper, jdkgdxds can now just use its\ngenerators as `java.util.Random` subclasses, so juniper is simply an optional, but recommended, dependency starting in jdkgdxds\n1.0.3 . There are various new additions to both of these small libraries to make them more useful as shared libraries for other\nlibraries to depend on. While `digital` has common math and trigonometry methods now, the random number generators in `juniper`\ncan serialize themselves to Strings without needing external code, and deserialize any of the serialized forms back to the\nappropriate generator using `Deserializer`.\n\nTo update to 1.0.1, most of the changes are package-related, and often only need changing import statements. Code that previously\nimported:\n\n  - `com.github.tommyettinger.ds.support.BitConversion` changes to `com.github.tommyettinger.digital.BitConversion`\n  - `com.github.tommyettinger.ds.support.Base` changes to `com.github.tommyettinger.digital.Base`\n  - `com.github.tommyettinger.ds.support.ChopRandom` changes to `com.github.tommyettinger.random.ChopRandom`\n  - `com.github.tommyettinger.ds.support.DistinctRandom` changes to `com.github.tommyettinger.random.DistinctRandom`\n  - `com.github.tommyettinger.ds.support.FourWheelRandom` changes to `com.github.tommyettinger.random.FourWheelRandom`\n  - `com.github.tommyettinger.ds.support.LaserRandom` changes to `com.github.tommyettinger.random.LaserRandom`\n  - `com.github.tommyettinger.ds.support.MizuchiRandom` changes to `com.github.tommyettinger.random.MizuchiRandom`\n  - `com.github.tommyettinger.ds.support.RomuTrioRandom` changes to `com.github.tommyettinger.random.RomuTrioRandom`\n  - `com.github.tommyettinger.ds.support.StrangerRandom` changes to `com.github.tommyettinger.random.StrangerRandom`\n  - `com.github.tommyettinger.ds.support.TricycleRandom` changes to `com.github.tommyettinger.random.TricycleRandom`\n  - `com.github.tommyettinger.ds.support.TrimRandom` changes to `com.github.tommyettinger.random.TrimRandom`\n  - `com.github.tommyettinger.ds.support.Xoshiro256StarStarRandom` changes to `com.github.tommyettinger.random.Xoshiro256StarStarRandom`\n  - `com.github.tommyettinger.ds.support.EnhancedRandom` is slightly more complicated, but it changes to `com.github.tommyettinger.random.EnhancedRandom`\n\n`EnhancedRandom` is now an abstract class, instead of a default-method-heavy interface, which makes it a little less flexible, but\nallows it to work smoothly on Java 17 and much earlier Java versions. Extending the new `EnhancedRandom` only needs the new\n`getTag()` method implemented, and maybe changes to `copy()`, `equals()` or `toString()` could be used as well.\n\nIf you are migrating other code to `digital`'s new math functions, you may need to rename some called methods -- the `sin_()`,\n`cos_()`, and similar trigonometric methods that worked with turns instead of radians now explicitly are called `sinTurns()` and\n`cosTurns()`.\n\nThere was a 1.0.0 release, but it mistakenly shadowed the `digital` code, without super-sourcing `BitConversion` for GWT support.\nSo, the first 1.x release is 1.0.1.\n\n## Updating to 1.0.4\n\nLikely less significant than the 1.0.1 update, 1.0.4 still \"removed\" some classes, though they were only moved to the funderby\nlibrary. The `com.github.tommyettinger.ds.support.function` package is now `com.github.tommyettinger.function`, and has many more\nfunctional interfaces, but if they were being provided as lambdas, no difference will be noticeable. There are quite a lot more\ninterfaces in funderby than there ever were in jdkgdxds, which may help in uncommon situations that use primitives in lambdas\n(so as if you need a `ByteLongPredicate`, you'll be ready). Some classes may have had their names changed; you can consult\n[funderby's README.md](https://github.com/tommyettinger/funderby#what-is-it) for the naming conventions. \n\n## Updating to 1.1.2\n\nVersion 1.1.2 has no breaking Java API changes, but if you use GWT, it does change the `inherits` tags you need in your .gwt.xml\nfile. This was needed because versions of most \"tommyettinger libraries\" before about January 9, 2023 placed their .gwt.xml files\nin the resources root folder, which turns out to cause unexpected compilation failures on GWT. This wasn't caught because,\nstrangely enough, these libraries were typically tested with projects that used the package `com.github.tommyettinger`, which is\nshared with the sources in the GWT-affected libraries, and this caused the compilation to mysteriously succeed. After testing on\nother packages on GWT, Dmitrii Tikhomirov and Colin Alworth tracked down the odd behavior to this folder situation, and so all the\nfolders needed to change. They did so in digital 0.1.7, funderby 0.0.2, juniper 0.1.8, and jdkgdxds 1.1.2 , among others.\n\n## Updating to 1.3.0\n\nVersion 1.3.0 removes a lot of Java 8 APIs, including all interfaces that require Java 8 code. Language level 8 is still used,\nsince it's been safe to use on all platforms for a while now, but RoboVM (for iOS support) still doesn't support Java 8 APIs (just\nthe language level). To update, change any usage of `PrimitiveIterator.OfInt`, `PrimitiveIterator.OfLong`, and\n`PrimitiveIterator.OfDouble` to `com.github.tommyettinger.ds.support.util.IntIterator`,\n`com.github.tommyettinger.ds.support.util.LongIterator`, and `com.github.tommyettinger.ds.support.util.DoubleIterator`,\nrespectively. You may also need to change some functional interfaces to use the ones in Funderby, which are named differently:\n\n - `Function` becomes `ObjToObjFunction`, `BiFunction` becomes `ObjObjToObjBiFunction`, `Consumer` becomes `ObjConsumer`,\n   `BiConsumer` becomes `ObjObjBiConsumer`, `Supplier` becomes `ObjSupplier`, and `Predicate` becomes `ObjPredicate`.\n - The pattern of specifying types in order continues for primitive types, and most combinations are supported.\n   - `IntLongToLongBiFunction` and `IntIntToLongBiFunction` exist because using one or two primitive types is always supported.\n   - If you were to try `IntLongToFloatBiFunction`, it isn't defined because it uses three primitive types.\n     - There is an exception for predicates, which return `boolean`; `IntLongPredicate` is defined.\n\nIf you get errors about a Java 8 functional interface not being assignable to something in jdkgdxds, it probably should be swapped\nout for something defined by funderby -- jdkgdxds won't use functional interfaces defined anywhere but there or here.\n\n## Updating to 1.4.1\n\nVersion 1.4.1 only has very small changes to jdkgdxds, but does update its dependency on `digital`, and digital 0.4.0 has a form\nof breaking change for users who depended on getting the same results from `Hasher` for a given input and seed. None of the\nmethods in digital that are affected by the change are used in jdkgdxds, but they could affect transitive usage. There is no\nmitigation or anything you have to do, other than to be aware that `Hasher.hash()` and `Hasher.hash64()` results may be different.\n\n## Updating to 1.4.6\n\nVersion 1.4.5 introduced `FilteredString(Ordered)?(Set|Map)` classes, which each took a CharPredicate filter and a\nCharToCharFunction editor. This turned out to work rather poorly when serializing to JSON, and so version 1.4.6 uses a\ndifferent, somewhat-incompatible approach. Now instead of specifying a filter and editor as individual arguments, they are\nalways grouped into a `CharFilter` object, which has a name that can be looked up with `CharFilter.contains()` or\n`CharFilter.get()`. To obtain a CharFilter, you still need a CharPredicate filter and a CharToCharFunction editor, but you\nuse `CharFilter.getOrCreate()` to get an existing CharFilter if one can be reused, or create one if the name isn't registered.\nThis is only breaking if you updated to 1.4.5 between December 5 and December 7, 2023, since 1.4.6 was released on December 7,\n2023... Plus you would have to be using the new FilteredString types... So, this is unlikely to be a problem.\n\n## Updating to 1.7.0\n\nVersion 1.7.0 mostly has a small breaking change that is not very likely to affect users, but this can cascade if you\nsubclass set or map classes. Most sets and maps had their `hashMultiplier` field removed, since it wasn't used anymore.\nSome re-added `hashMultiplier` to themselves, such as the Filtered sets and maps, or the CaseInsensitive ones, because\nthey did still use that field. This needed some extra work because of how calls to a `super()` constructor can't see\ninitialization done in a subclass; subclasses that previously relied on a superconstructor that took a collection or\narray now have to use a superconstructor that doesn't, then set hashMultiplier, then add that collection or array. This\nwill only affect user code that extends classes such as ObjectSet, ObjectObjectMap, IntSet, IntFloatMap, LongSet,\nLongIntMap, and so on, and even then only if the subclass needs to access `hashMultiplier`. The getters and setters for\n`hashMultiplier` are still there, and can still be overridden to do something even if a class doesn't use a\n`hashMultiplier` at all.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftommyettinger%2Fjdkgdxds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftommyettinger%2Fjdkgdxds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftommyettinger%2Fjdkgdxds/lists"}