Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 1x 51x 51x 179x 179x 179x 179x 365x 365x 363x 363x 363x 363x 363x 365x 365x 691x 691x 97x 691x 332x 146x 146x | import type {NonEmptyArray2} from '#Array'
import {Array, Equivalence, Predicate, pipe} from 'effect'
/**
* Check that a path list is valid:
*
* 1. Every leaf, I.e.: a node that appears last in its path, is mentioned in
* only one path.
* 2. All paths share the same root
* 3. For any pair of appearances of any node the parent node is equal.
* @category codec
* @function
*/
export const isValidPathList =
<A>(
equals: Equivalence.Equivalence<A>,
): Predicate.Predicate<NonEmptyArray2<A>> =>
paths => {
const parents = new Map<A, A>(),
leaves = new Set<A>(),
root = paths[0][0]
for (const path of paths) {
const [head, leaf] = [Array.headNonEmpty(path), Array.lastNonEmpty(path)]
if (!equals(head, root) || leaves.has(leaf)) return false
leaves.add(leaf)
const zipped = pipe(
Array.tailNonEmpty(path),
Array.zip(Array.initNonEmpty(path)),
)
if (Array.isEmptyArray(zipped)) return paths.length === 1
for (const [child, parent] of zipped) {
const maybeParent = parents.get(child)
if (maybeParent === undefined) parents.set(child, parent)
else if (!equals(maybeParent, parent)) return false
}
}
return true
}
|