-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from DandyLyons/docs-bijective
Add Docs
- Loading branch information
Showing
5 changed files
with
227 additions
and
0 deletions.
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
Sources/BijectiveDictionary/Documentation.docc/Assets/Bijection.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions
69
Sources/BijectiveDictionary/Documentation.docc/Creating a BijectiveDictionary.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Creating a BijectiveDictionary | ||
|
||
Learn the many different ways to initialize a `BijectiveDictionary`. | ||
|
||
## Creating an Empty `BijectiveDictionary` | ||
An empty dictionary can be created using ``BijectiveDictionary/init()`` | ||
Because `BijectiveDictionary` is generic, you will also need to somewhere declare your `Left` and `Right` value types. | ||
|
||
```swift | ||
let bDict = BijectiveDictionary<String, Int>() | ||
``` | ||
|
||
Or an empty `BijectiveDictionary` can also be created with a literal. However, this will require that you explicitly declare the type (unless it can be inferred elsewhere). | ||
|
||
```swift | ||
let bDict: BijectiveDictionary<String, Int> = [:] | ||
``` | ||
|
||
### Reserving Capacity | ||
An empty dictionary can also be created with a minimum capacity using ``BijectiveDictionary/init(minimumCapacity:)``. Remember that, (just like a standard `Dictionary`) when a `BijectiveDictionary` exceeds it's capacity, it must reallocate its storage buffer under the hood. This reallocation is automatic and you do not need to remember to do it, but it is not free. It is good to avoid this work, if you know in advance that you will have a large number of items. | ||
|
||
```swift | ||
let bDict = BijectiveDictionary<String, Int>(minimumCapacity: 10_000) | ||
``` | ||
|
||
## Initialize with Values | ||
### Create a `BijectiveDictionary` from a Literal | ||
See: ``BijectiveDictionary/init(dictionaryLiteral:)`` | ||
|
||
``BijectiveDictionary`` conforms to `ExpressibleByDictionaryLiteral` and therefore can be initialized with common `Dictionary` syntax. (Note, this creates a `BijectiveDictionary` directly, and does not create any `Dictionary`.) In practice, this is one of the easiest ways to create a `BijectiveDictionary`. | ||
|
||
># Warning | ||
>The dictionary literal used here must not contain any duplicates in the left or right values or else this initializer will fatal error. | ||
```swift | ||
let bDict: BijectiveDictionary<String, Int> = ["A": 1, "B": 2, "C": 3] | ||
``` | ||
|
||
|
||
### Initialize with a Sequence of Tuples | ||
See ``BijectiveDictionary/init(uniqueLeftRightPairs:)`` | ||
```swift | ||
let values = [ | ||
("A", 1), | ||
("B", 2), | ||
("C", 3), | ||
] | ||
let bDict = BijectiveDictionary(uniqueLeftRightPairs: values) | ||
``` | ||
|
||
## Conversion | ||
### Convert a `Dictionary` to a `BijectiveDictionary` | ||
See ``BijectiveDictionary/init(_:)`` | ||
|
||
```swift | ||
let dict = ["A": 1, "B": 2, "C": 3] | ||
guard let bDict = BijectiveDictionary(dict) else { | ||
print("Right values are non-unique.") | ||
} | ||
print("bDict is now unwrapped.") | ||
``` | ||
|
||
### Convert a `BijectiveDictionary` to a `Dictionary` | ||
```swift | ||
let bDict: BijectiveDictionary = ["A": 1, "B": 2, "C": 3] | ||
let dict = Dictionary(bDict) | ||
``` | ||
|
||
### Codable | ||
`BijectiveDictionary` also conforms to `Codable` and therefore can be easily converted back and forth from `JSON`, `Data`, `XML` and any other serialization scheme that supports `Codable`. The `Codable` implementation for `BijectiveDictionary` is designed to perfectly mimic `Dictionary`'s `Codable` implementation. In other words, you should expect that and encoded representation of a `Dictionary` should produce an equivalent `BijectiveDictionary` and vice versa. |
72 changes: 72 additions & 0 deletions
72
Sources/BijectiveDictionary/Documentation.docc/Using a BijectiveDictionary.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Using a BijectiveDictionary | ||
Learn how to mutate and maintain a BijectiveDictionary. | ||
|
||
## Reserving Capacity | ||
Just like a `Dictionary`, if a ``BijectiveDictionary`` overflows its capacity, then it must internally allocate for more memory. While this process is automatic, it is not free. If we know the required capacity ahead of time, then we can allocate it in advance, thus eliminating unnecessary work. This can be done during initialization. | ||
|
||
```swift | ||
let bDict = BijectiveDictionary<String, Int>(minimumCapacity: 10_000) | ||
``` | ||
|
||
Or it can also be done during the lifetime of the dictionary. | ||
|
||
```swift | ||
print(bDict.capacity) // 10_000 | ||
bDict.reserveCapacity(200_000) | ||
print(bDict.capacity) // 200_000 | ||
``` | ||
## Reading a Value | ||
```swift | ||
let bDict: BijectiveDictionary = ["A": 1, "B": 2, "C": 3] | ||
bDict[left: "B"] // 2 | ||
bDict[right: 3] // "C" | ||
``` | ||
|
||
## Order | ||
># `BijectiveDictionary` does not preserve or guarantee ordering. | ||
>Do not forget that just like `Dictionary`, a `BijectiveDictionary` is unordered. The order of key-value pairs is stable between mutations but is otherwise unpredictable. For more info, see the docs for [Dictionary](https://github.com/swiftlang/swift/blob/28c6cc105da2e917416002df3e0accfc2ad2d23f/stdlib/public/core/Dictionary.swift#L316). | ||
For the purposes of these docs, we will preserve the order, just to make it easier to reason about. But in practice, in actual code, the order of elements in a `BijectiveDictionary` will not be predictable. | ||
|
||
## Mutation | ||
Insertion and updates are done through the subscripts. The syntax is just like mutating a `Dictionary`. However, unlike a `Dictionary` both the "key" and the "value" can be used as a key. This is the reason why we instead use the words "left" and "right". We must also add these words to our subscript when we call them. In other words we must use `bDict[left: "B"]` rather than `bDict["B"]`. | ||
|
||
### Insertion | ||
Just like a `Dictionary`, if the given "key" is not found, then the new key-value pair will be inserted. | ||
|
||
```swift | ||
var bDict: BijectiveDictionary = ["A": 1, "B": 2, "C": 3] | ||
bDict[left: "D"] = 4 | ||
bDict[right: 5] = "E" | ||
print(bDict) // ["A": 1, "B": 2, "C": 3, "D": 4, "E": 5] | ||
``` | ||
|
||
Swift will also check for types. | ||
```swift | ||
var bDict: BijectiveDictionary = ["A": 1, "B": 2, "C": 3] | ||
bDict[left: 4] = "D" // this is a compiler error | ||
``` | ||
|
||
### Updates | ||
Also just like a `Dictionary`, if the given "key" already exists, then the subscript will keep the "key" as-is, and will mutate the corresponding "value". | ||
|
||
```swift | ||
var bDict: BijectiveDictionary = ["A": 1, "B": 2, "C": 3] | ||
bDict[left: "A"] = 12 | ||
bDict[right: 2] = "Z" | ||
print(bDict) // ["A": 12, "Z": 2, "C": 3] | ||
``` | ||
|
||
|
||
### Removal | ||
Removal can be performed by using ``BijectiveDictionary/remove(byLeft:)`` and ``BijectiveDictionary/remove(byRight:)`` respectively. | ||
|
||
```swift | ||
var bDict = ["A": 1, "B": 2, "C": 3, "D": 4, "E": 5] | ||
bDict.remove(byLeft: "D") | ||
print(bDict) // ["A": 1, "B": 2, "C": 3, "E": 5] | ||
bDict.remove(byRight: 5) | ||
print(bDict) // ["A": 1, "B": 2, "C": 3] | ||
``` | ||
|
||
|
17 changes: 17 additions & 0 deletions
17
Sources/BijectiveDictionary/Documentation.docc/What Are Duplicates?.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# What Are Duplicates? | ||
Learn what `BijectiveDictionary` means when referring to duplicates. | ||
|
||
## Duplicates | ||
Throughout the documentation we will use the term `duplicate`. This term has a slightly different meaning in `BijectiveDictionary` than it means in other collections such as `Dictionary`. | ||
|
||
### Duplicates in `Dictionary` | ||
A `Dictionary` cannot have duplicate keys, but it can have duplicate values. Therefore when you create a `Dictionary` using the initializer `Dictionary.init(uniqueKeysWithValues:)`, you must provide unique keys. In other words the keys can have no duplicates. But it is okay for the values to have duplicates. Providing duplicate keys will result in a runtime error. | ||
|
||
For this reason, `Dictionary` also comes with another initializer (`Dictionary.init(_:uniquingKeysWith:)`). This initializer will not result in a runtime error. In order to achieve this, you must provide it a closure which will be called any time that duplicate keys are encountered. This will instruct the initializer how to resolve the duplicate. | ||
|
||
### Duplicates in `BijectiveDictionary` | ||
`BijectiveDictionary` aims to mimic `Dictionary`'s API as closely as possible, only making changes when necessary. Unlike `Dictionary`, a `BijectiveDictionary` requires both the left and the right values to be unique. But let's be a little more specific on what that means. | ||
|
||
1. Within the left values, there can be no duplicates. | ||
2. Within the right values, there can be no duplicates. | ||
3. However, it is okay if the same value exists on both the right and left side. This is not considered a duplicate. |
18 changes: 18 additions & 0 deletions
18
Sources/BijectiveDictionary/Documentation.docc/What is Bijective.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# What does 'Bijective' mean? | ||
|
||
Learn how bijection affects the behavior of `BijectiveDictionary`. | ||
|
||
## Overview | ||
[Bijection](https://en.wikipedia.org/wiki/Bijection) is the property of having one-to-one correspondence between two sets. | ||
|
||
 | ||
|
||
From this definition we can see that ``BijectiveDictionary`` has these important characteristics: | ||
1. Every left value is **unique** (just like a `Dictionary` key). | ||
2. Every right value is **also unique** (unlike a `Dictionary` value). | ||
3. Every left value has **one and only one** corresponding right value. | ||
4. Every right value has **one and only one** corresponding left value. | ||
|
||
Just like a `Set`, all key-value pairs in a `BijectiveDictionary` are unique and unordered. | ||
|
||
If you do not want these properties for your particular use case, then `BijectiveDictionary` is not the right tool for the job. |