{"id":16915888,"url":"https://github.com/tysonandre/pecl-teds","last_synced_at":"2025-03-17T07:31:11.107Z","repository":{"id":43349327,"uuid":"377687951","full_name":"TysonAndre/pecl-teds","owner":"TysonAndre","description":"Tentative Extra Data Structures for php","archived":false,"fork":false,"pushed_at":"2023-09-16T13:03:30.000Z","size":1309,"stargazers_count":31,"open_issues_count":47,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-27T19:57:21.087Z","etag":null,"topics":["data-structures","pecl","php"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TysonAndre.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-17T02:58:40.000Z","updated_at":"2024-12-25T15:07:35.000Z","dependencies_parsed_at":"2024-10-27T12:15:33.596Z","dependency_job_id":"dd7c1170-3946-494e-b812-a500923cc105","html_url":"https://github.com/TysonAndre/pecl-teds","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fpecl-teds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fpecl-teds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fpecl-teds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TysonAndre%2Fpecl-teds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TysonAndre","download_url":"https://codeload.github.com/TysonAndre/pecl-teds/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243852386,"owners_count":20358266,"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":["data-structures","pecl","php"],"created_at":"2024-10-13T19:23:20.603Z","updated_at":"2025-03-17T07:31:10.696Z","avatar_url":"https://github.com/TysonAndre.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Teds\n\n## Introduction\n\n[![Build Status](https://github.com/TysonAndre/pecl-teds/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/TysonAndre/pecl-teds/actions/workflows/main.yml?query=branch%3Amain)\n[![Build Status (Windows)](https://ci.appveyor.com/api/projects/status/j5s46tetcg4101g8?svg=true)](https://ci.appveyor.com/project/TysonAndre/pecl-teds)\n\nTeds is a another collection of data structures.\n(Tentative Extra Data Structures)\n\n## Installation\n\nThis extension requires php 8.0 or newer.\n\n```\nphpize\n./configure\nmake install\n```\n\nOn Windows, see https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 instead\n\n## Overview\n`Teds` contains the following types of `Teds\\Collection` instances as well as various [iterable functionality](#iterable-functions):\n\n### Teds\\Sequence - A Collection of values with keys 0..n-1\n\n`Teds\\Sequence` is an interface representing a Collection of values with keys `0..n-1` and no gaps. (also known as a list in other languages)\nIt is implemented by the following classes.\n\n- `Teds\\Vector` - a memory-efficient representation of a list of values that can easily grow/shrink.\n- `Teds\\Deque` - a memory-efficient representation of a list of values with amortized constant time push/pop/pushFront/popFront.\n\n`Teds` also includes several specializations of `Teds\\Sequence` for memory-efficiency:\n\n- `Teds\\IntVector` - a memory-efficient specialization of lists of integers, typically with faster serialization requiring less memory.\n- `Teds\\LowMemoryVector` - exposes the same API as `Teds\\Vector` but uses less memory for specializations (exclusively bool/null, exclusively integers, exclusively floats)\n- `Teds\\BitVector` - exposes the same API as `Teds\\Vector` but uses significantly less memory for booleans. Provides ways to read/write raw bytes/words.\n\nAnd immutable versions:\n\n- `Teds\\ImmutableSequence` - represents an immutable sequence.\n- `Teds\\EmptySequence::INSTANCE` (PHP 8.1+, uses enum) - represents an immutable empty sequence.\n\n### Teds\\Set - a Collection of unique values\n\nThe `Teds\\Set` interface is implemented by the following classes:\n\n- `Teds\\StrictHashSet` - a hash table based set of unique values providing efficient average-time lookup/insertion/removal. Uses `Teds\\strict_hash`.\n- `Teds\\StrictTreeSet` - a binary tree-based set of **sorted** unique values providing good worst-case time. Uses `Teds\\stable_compare` for stable ordering.\n- `Teds\\StrictSortedVectorSet` - provides a similar API to `Teds\\StrictTreeSet` but is represented internally as a Vector. This has reduced memory usage and faster construction time, and can be useful in cases where modification is infrequent (e.g. more common to unserialize without modifying)\n\n#### Low-memory Sets\n\nSome specializations are provided for reduced memory usage:\n\n- `Teds\\SortedIntVectorSet` - a mutable sorted set of integers, represented internally as a Vector. This has reduced memory usage and can be useful in cases where modification is infrequent (e.g. more common to unserialize without modifying)\n\n`Teds` also provides immutable specializations of common data types offering faster serialization/unserialization:\n\n- `Teds\\ImmutableSortedStringSet` - a sorted set of strings sorted by strcmp. Note that internally, this is backed by a single string with the data that would be used for `__unserialize`/`__serialize`.\n\n  As a result, this is faster to unserialize and uses less memory than an array  ([see benchmark](https://github.com/TysonAndre/pecl-teds/blob/main/benchmarks/benchmark_string_set.php)), but when iterating over the string, temporary copies of the strings that are members of the set are returned.\n- `Teds\\ImmutableSortedIntSet` - a sorted set of integers.\n- `Teds\\EmptySet::INSTANCE` (PHP 8.1+, uses enum) - represents an immutable empty set.\n\n### Teds\\Map - a Collection mapping unique keys to values\n\nThe `Teds\\Map` interface is implemented by the following classes:\n\n- `Teds\\StrictHashMap` - a hash table based map of unique keys to values providing efficient average-time lookup/insertion/removal. Uses `Teds\\strict_hash`.\n- `Teds\\StrictTreeMap` - a binary tree-based map of **sorted** unique keys to values providing slower average-case time but good worst-case time. Uses `Teds\\stable_compare` for stable ordering.\n- `Teds\\StrictSortedVectorMap` - provides a similar API to `Teds\\StrictTreeMap` but is represented internally like a Vector. This has reduced memory usage and faster construction time and can be useful in cases where modification is infrequent (e.g. more common to unserialize without modifying)\n\n`Teds` also provides the following map types:\n\n- `Teds\\EmptyMap::INSTANCE` (PHP 8.1+, uses enum) - represents an immutable empty map.\n\n### Teds\\Collections - others\n\n- `Teds\\StrictMinHeap` and `Teds\\StrictMaxHeap` are heaps where elements can be added (allowing duplicates) and are removed in order (or reverse order) of `Teds\\stable_compare`.\n- `Teds\\CachedIterable` is a `Collection` that lazily evaluates iterables such as Generators and stores the exact keys and values to allow future retrieval and iteration.\n- `Teds\\ImmutableIterable` is a `Collection` that eagerly evaluates iterables such as Generators and stores the exact keys and values to allow future retrieval and iteration.\n- `Teds\\MutableIterable` is a `Collection` that allows construction and modification of iterables, setting keys and values and allowing duplicate keys in any order.\n\n## Functionality\n\n### Teds\\ImmutableIterable\n\n[`Teds\\ImmutableIterable` API](./teds_immutableiterable.stub.php)\n\nCurrently, PHP does not provide a built-in way to store the state of an arbitrary iterable for reuse later (when the iterable has arbitrary keys, or when keys might be repeated). There are use cases for this, such as:\n\n1. Creating a rewindable copy of a non-rewindable `Traversable` (e.g. a `Generator`) before passing that copy to a function that consumes an `iterable`/`Traversable`. (new ImmutableIterable(my_generator()))\n2. Generating an `IteratorAggregate` from a class still implementing `Iterator` (e.g. `SplObjectStorage`) so that code can independently iterate over the key-value sequences. (e.g. `foreach ($immutableImmutableIterable as $k1 =\u003e $v1) { foreach ($immutableImmutableIterable as $k2 =\u003e $v2) { /* process pairs */ } }`)\n3. Providing helpers such as `iterable_flip(iterable $iterable)`, `iterable_take(iterable $iterable, int $limit)`, `iterable_chunk(iterable $iterable, int $chunk_size)` that act on iterables with arbitrary key/value sequences and have return values including iterables with arbitrary key/value sequences\n4. Providing constant time access to both keys and values of arbitrary key-value sequences at any offset (for binary searching on keys and/or values, etc.)\n\nHaving this implemented as a native class allows it to be much more efficient than a userland solution (in terms of time to create, time to iterate over the result, and total memory usage, depending on the representation).\n\nObjects within this data structure or references in arrays in this data structure can still be mutated.\n\nTraversables are eagerly iterated over in the constructor.\n\n### Teds\\CachedIterable\n\n[`Teds\\CachedIterable` API](./teds_cachediterable.stub.php)\n\nThis is similar to `Teds\\ImmutableIterable` but lazily evaluates Traversables instead of eagerly evaluating Traversables.\n(E.g. Generators will only run until the last offset used from a CachedIterable. See [tests/CachedIterable/lazy.phpt](./tests/CachedIterable/lazy.phpt) and [tests/CachedIterable/selfReferential.phpt](./tests/CachedIterable/selfReferential.phpt) for examples.)\n\nThis can be used to cache results of generators without fetching more elements than needed (e.g. Generators that repeatedly call databases or services to paginate).\n\n### Teds\\ImmutableSequence\n\n[`Teds\\ImmutableSequence` API](./teds_immutablesequence.stub.php)\n\nSimilar to SplFixedArray or Ds\\Sequence, but immutable.\nThis stores a sequence of values with the keys 0, 1, 2....\n\n### Teds\\LowMemoryVector\n\n[`Teds\\LowMemoryVector` API](./teds_lowmemoryvector.stub.php)\n\nThis exposes the same API as a Vector, but with a more memory-efficient representation if the LowMemoryVector has only ever included a type that it could optimize.\n\nBenefits:\n\n- For collections of exclusively int, exclusively floats, or exclusively null/true/false, this uses less memory when serialized compared to vectors/arrays.\n- For collections of exclusively int, exclusively floats, or exclusively null/true/false, this uses less memory when serialized compared to vectors/arrays.\n\n  Note that adding other types will make this use as much memory as a Vector, e.g. adding any non-float (including int) to a collection of floats.\n- Has faster checks for contains/indexOf (if values can have an optimized representation)\n- Has faster garbage collection (if values can have an optimized representation due to int/float/bool/null not needing reference counting).\n- Interchangeable with `Vector` or other collections without configuration - this will silently fall back to the default `mixed` representation if a more efficient representation is not supported.\n\nDrawbacks:\n- Slightly more overhead when types aren't specialized.\n- Adding a different type to the collection will permanently make it used the less efficient `mixed` representation.\n\nIn 64-bit builds, the following types are supported, with the following amounts of memory (plus constant overhead to represent the LowMemoryVector itself, and extra capacity for growing the LowMemoryVector):\n\n1. null/bool : 1 byte per value.\n\n   (In serialize(), this is even less, adding 1 to 2 bits per value (2 bits if null is included)).\n2. signed 8-bit int (-128..127): 1 byte per value. Adding a larger int to any of these n-bit types will convert them to the collection of that larger int type.\n3. signed 16-bit int: 2 bytes per value.\n4. signed 32-bit int: 4 bytes per value.\n5. signed 64-bit int: 8 bytes per value. (64-bit php builds only)\n6. signed PHP `float`:  8 bytes per value. (C `double`)\n7. `mixed` or combinations of the above: 16 bytes per value. (Same as `Vector`)\n\nIn comparison, in 64-bit builds of PHP, PHP's arrays take at least 16 bytes per value in php 8.2, and at least 32 bytes per value before php 8.1, at the time of writing.\n\nExample benchmarks: [benchmarks/benchmark_vector_bool.php](benchmarks/benchmark_vector_bool.php) and [benchmarks/benchmark_vector_unserialize.phpt](benchmarks/benchmark_vector_unserialize.phpt).\n\n### Teds\\IntVector\n\n[`Teds\\IntVector` API](./teds_intvector.stub.php)\n\nSimilar to `Teds\\LowMemoryVector` but throws a TypeError on attempts to add non-integers.\n\n### Teds\\BitVector\n\n[`Teds\\BitVector` API](./teds_bitset.stub.php)\n\nSimilar to `Teds\\LowMemoryVector`/`Teds\\IntVector` but throws a TypeError on attempts to add non-booleans.\nThis can be used as a memory-efficient vector of booleans.\n\nThis uses only a single bit per value for large bit sets in memory and when serializing (around 128 times less memory than arrays, for large arrays of booleans)\n\n### Teds\\Vector\n\n[`Teds\\Vector` API](./teds_vector.stub.php)\n\nSimilar to SplFixedArray or Ds\\Vector.\nThis stores a mutable sequence of values with the keys 0, 1, 2...\nIt can be appended to with `push()`, and elements can be removed from the end with `pop()`\n\nThis is implemented based on SplFixedArray/ImmutableSequence.\nThere are plans to add more methods.\n\n### Teds\\MutableIterable\n\n[`Teds\\MutableIterable` API](./teds_mutableiterable.stub.php)\n\nSimilar to `Teds\\Vector` and `Teds\\ImmutableIterable`.\nThis stores a mutable vector of keys and values with the keys 0, 1, 2...\nIt can be resized with `setSize()`.\n\n### Teds\\Deque\n\n[`Teds\\Deque` API](./teds_deque.stub.php)\n\nSimilar to SplDoublyLinkedList but backed by an array instead of a linked list.\nMuch more efficient in memory usage and random access than SplDoublyLinkedList.\n\n(Also similar to `Ds\\Deque`)\n\n### Teds\\StrictTreeMap and Teds\\StrictTreeSet\n\n[`Teds\\StrictTreeMap` API](./teds_stricthashmap.stub.php)\n\nThis is a map where entries for keys of any type can be inserted if `Teds\\stable_compare !== 0`.\n\nThis currently uses a balanced [red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) to ensure logarithmic time is needed for insertions/removals/lookups.\n\nRemoving a `Teds\\StrictTreeMap`/`Teds\\StrictTreeSet` entry will move iterators pointing to that entries to the entry before the removed entry (as of 1.2.1).\n\nThis uses [`Teds\\stable_compare`](#stable-comparison) internally.\n\nThe [`Teds\\StrictTreeSet` API](./teds_stricttreeset.stub.php) implementation is similar, but does not associate values with keys. Also, `StrictTreeSet` does not implement ArrayAccess and uses different method names.\n\n### Teds\\StrictHashMap and Teds\\StrictHashSet\n\n[`Teds\\StrictHashMap` API](./teds_stricthashmap.stub.php)\n\nThis is a map where entries for keys of any type can be inserted if they are `!==` to other keys.\nThis uses [`Teds\\strict_hash`](#strict-hashing) internally.\n\nThe [`Teds\\StrictHashSet` API](./teds_stricthashset.stub.php) implementation is similar, but does not associate values with keys and does not implement ArrayAccess and uses different method names.\n\nNOTE: The floats `0.0` and [`-0.0` (negative zero)](https://en.wikipedia.org/wiki/Signed_zero) have the same hashes and are treated as the same entries, because `0.0 === -0.0` in php.\nNOTE: The float `NAN` (Not a Number) is deliberately treated as equivalent to itself by `Teds\\strict_hash` and  `StrictHashSet`/`StrictHashMap`, despite having `NAN !== $x` in php for any $x, including `NAN`. This is done to avoid duplicate or unremovable entries.\n\nRemoving an entry from a hash map/set will move iterators pointing to that entry to the entry prior to the removed entry.\n\n### Teds\\StrictMinHeap and Teds\\StrictMaxHeap\n\n[`Teds\\Strict*Heap` API](./teds_strictheap.stub.php)\n\nThis uses `Teds\\stable_compare` instead of PHP's unstable default comparisons.\nSorting logic can be customized by inserting `[$priority, $value]` instead of `$value`.\n(Or by subclassing `SplMinHeap`/`SplMaxHeap` and overriding `compare` manually).\n\n```php\nphp \u003e $x = new SplMinHeap();\nphp \u003e foreach (['19', '9', '2b', '2'] as $v) { $x-\u003einsert($v); }\nphp \u003e foreach ($x as $value) { echo json_encode($value).\",\"; } echo \"\\n\"; // unpredictable order\n\"2\",\"19\",\"2b\",\"9\",\n\nphp \u003e $x = new Teds\\StrictMinHeap();\nphp \u003e foreach (['19', '9', '2b', '2'] as $v) { $x-\u003eadd($v); }\nphp \u003e foreach ($x as $value) { echo json_encode($value).\",\"; } echo \"\\n\"; // lexicographically sorted\n\"19\",\"2\",\"2b\",\"9\",\n```\n\n### Teds\\EmptySequence and Teds\\EmptySet and Teds\\EmptyMap\n\nThis provides empty immutable collections for php 8.1+ based on single-case enums.\n\n[Empty Immutable Collection API](./teds_emptycollection.stub.php)\n\n### Common interfaces\n\n[teds_interfaces.stub.php](./teds_interfaces.stub.php)\n\n**NOTE: This is currently being revised, and new methods may be added to these interfaces in 0.x releases or new major releases.** More methods are currently being added.\n\nThese provide common interfaces for accessing the lists, sorted/hash sets, sorted/hash maps, sequences, and key value sequences that are provided by `Teds\\`.\n\n```php\n\u003c?php\nnamespace Teds;\n\n/**\n * Collection is a common interface for an object with values that can be iterated over and counted,\n * but not addressed with ArrayAccess (e.g. Sets, Heaps, objects that yield values in an order in their iterators, etc.)\n */\ninterface Collection extends \\Traversable, \\Countable {\n    /** @return list\u003cvalues\u003e the list of values in the collection */\n    public function values(): array {}\n\n    /**\n     * Returns a list or associative array,\n     * typically attempting to cast keys to array key types (int/string) to insert elements of the collection into the array, or throwing.\n     *\n     * When this is impossible for the class in general,\n     * the behavior depends on the class implementation (e.g. throws \\Teds\\UnsupportedOperationException, returns an array with representations of key/value entries of the Collection)\n     */\n    public function toArray(): array {}\n\n    /** Returns true if count() would be 0 */\n    public function isEmpty(): bool {}\n\n    /** Returns true if this contains a value identical to $value. */\n    public function contains(mixed $value): bool {}\n}\n\n/**\n * This represents a Collection that can be used like a list without gaps.\n * E.g. get()/set() will work for is_int($offset) \u0026\u0026 0 \u003c= $offset and $offset \u003c $list-\u003ecount().\n */\ninterface Sequence extends Collection, \\ArrayAccess {\n    public function get(int $offset): mixed {}\n    public function set(int $offset, mixed $value): void {}\n\n    public function push(mixed ...$values): void {}\n    public function pop(): mixed {}\n}\n\n/**\n * A Map is a type of Collection mapping unique keys to values.\n *\n * Implementations should either coerce unsupported key types or throw TypeError when using keys.\n *\n * Implementations include\n *\n * 1. Teds\\StrictHashMap, a hash table with amortized constant time operations\n * 2. Teds\\StrictTreeMap, a sorted binary tree\n */\ninterface Map extends Collection, \\ArrayAccess {\n    /**\n     * Returns true if there exists a key identical to $key according to the semantics of the implementing collection.\n     * Typically, this is close to the definition of `===`, but may be stricter or weaker in some implementations, e.g. for NAN, negative zero, etc.\n     *\n     * containsKey differs from offsetExists, where implementations of offsetExists usually return false if the key was found but the corresponding value was null.\n     * (This is analogous to the difference between array_key_exists($key, $array) and isset($array[$key]))\n     */\n    public function containsKey(mixed $value): bool {}\n}\n\n/**\n * A Set is a type of Collection representing a set of unique values.\n * Implementations include Teds\\StrictHashSet and Teds\\StrictTreeSet.\n *\n * 1. Teds\\StrictHashSet, a hash table with amortized constant time operations\n * 2. Teds\\StrictTreeSet, a sorted binary tree\n */\ninterface Set extends Collection {\n    /**\n     * Returns true if $value was added to this Set and was not previously in this Set.\n     */\n    public function add(mixed $value): bool {}\n\n    /**\n     * Returns true if $value was found in this Set before being removed from this Set.\n     */\n    public function remove(mixed $value): bool {}\n}\n```\n\n### iterable functions\n\nThis PECL contains a library of native implementations of various functions acting on iterables.\nSee [`teds.stub.php`](./teds.stub.php) for function signatures.\n\n**The behavior is equivalent to the following polyfill**\n(similarly to array_filter, the native implementation is likely faster than the polyfill with no callback, and slower with a callback)\n\n```php\nnamespace Teds;\n\n/**\n * Determines whether any element of the iterable satisfies the predicate.\n *\n * If the value returned by the callback is truthy\n * (e.g. true, non-zero number, non-empty array, truthy object, etc.),\n * this is treated as satisfying the predicate.\n *\n * @param iterable $iterable\n * @param null|callable(mixed):mixed $callback\n */\nfunction any(iterable $iterable, ?callable $callback = null): bool {\n    foreach ($iterable as $v) {\n        if ($callback !== null ? $callback($v) : $v) {\n            return true;\n        }\n    }\n    return false;\n}\n/**\n * Determines whether all elements of the iterable satisfy the predicate.\n *\n * If the value returned by the callback is truthy\n * (e.g. true, non-zero number, non-empty array, truthy object, etc.),\n * this is treated as satisfying the predicate.\n *\n * @param iterable $iterable\n * @param null|callable(mixed):mixed $callback\n */\nfunction all(iterable $iterable, ?callable $callback = null): bool {\n    foreach ($iterable as $v) {\n        if (!($callback !== null ? $callback($v) : $v)) {\n            return false;\n        }\n    }\n    return true;\n}\n\n/**\n * Determines whether no element of the iterable satisfies the predicate.\n *\n * If the value returned by the callback is truthy\n * (e.g. true, non-zero number, non-empty array, truthy object, etc.),\n * this is treated as satisfying the predicate.\n *\n * @param iterable $iterable\n * @param null|callable(mixed):mixed $callback\n */\nfunction none(iterable $iterable, ?callable $callback = null): bool {\n\treturn !any($iterable, $callback);\n}\n\n// Analogous to array_reduce but with mandatory default\nfunction fold(iterable $iterable, callable $callback, mixed $default): bool {\n\tforeach ($iterable as $value) {\n\t\t$default = $callback($default, $value);\n\t}\n\treturn $default;\n}\n\n/**\n * Returns the first value for which $callback($value) is truthy.\n */\nfunction find(iterable $iterable, callable $callback, mixed $default = null): bool {\n\tforeach ($iterable as $value) {\n\t\tif ($callback($value)) {\n\t\t\treturn $value;\n\t\t}\n\t}\n\treturn $default;\n}\n\n/**\n * Similar to in_array($value, $array, true) but also works on Traversables.\n */\nfunction includes_value(iterable $iterable, mixed $value): bool {\n\tforeach ($iterable as $other) {\n\t\tif ($other === $value) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/**\n * Returns a list of unique values in order of occurrence,\n * using a hash table with `Teds\\strict_hash` to deduplicate values.\n */\nfunction unique_values(iterable $iterable): array {\n\t// Without Teds installed, this takes quadratic time instead of linear time.\n\t$result = [];\n\tforeach ($iterable as $value) {\n\t\tif (!in_array($value, $result, true)) {\n\t\t\t$result[] = $value;\n\t\t}\n\t}\n\treturn $result;\n}\n```\n\n## Stable comparison\n\n`Teds\\stable_compare` is a function that can be used to compare arbitrary values in a stable order.\n\nThis exists because php's `\u003c` operator is not stable. `'10' \u003c '0a' \u003c '1b' \u003c '9' \u003c '10'`.\n`Teds\\stable_compare` fixes that by strictly ordering:\n\n- `null \u003c false \u003c true \u003c int,float \u003c string \u003c array \u003c object \u003c resource`.\n- objects are compared by class name with strcmp, then by spl_object_id.\n- resources are compared by id.\n- arrays are compared recursively. Smaller arrays are less than larger arrays.\n- int/float are compared numerically. If an int is equal to a float, then the int is first.\n- strings are compared with strcmp.\n\n## Strict hashing\n\n`Teds\\strict_hash` provides a hash based on value identity.\nBefore a final step to improve accidental hash collisions:\n\n- Objects are hashed based only on `spl_object id`.\n  Different objects will have different hashes for the lifetime of the hash.\n- Resources are hashed based on `get_resource_id`.\n- Strings are hashed\n- References are dereferenced and hashed the same way as the value.\n- Integers are used directly.\n- Floats are hashed in a possibly platform-specific way.\n- Arrays are hashed recursively. If $a1 === $a2 then they will have the same hash.\n\nThis may vary based on php release, OS, CPU architecture, or Teds release\nand should not be saved/loaded outside of a given php process.\n(and `spl_object_id`/`get_resource_id` are unpredictable)\n\n## Binary search\n\n`Teds\\binary_search(array $values, mixed $target, callable $comparer = null, bool $useKey=false)`\ncan be used to [binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm) on arrays that are sorted by key (ksort, uksort) or value (sort, usort, uasort).\n(even if keys were unset).\n\nThis will have unpredictable results if the array is out of order. See [`Teds\\stable_sort`](#stable-comparison) for ways to sort even arbitrary values in a stable order.\n\nThis is faster for very large sorted arrays. See [benchmarks](benchmarks/).\n\nThis returns the key and value of the first entry `\u003c=` $needle according to the comparer, and whether an entry comparing equal was found.\nBy default, php's default comparison behavior (`\u003c=\u003e`) is used.\n\n```php\nphp \u003e $values = [1 =\u003e 100, 3 =\u003e 200, 4 =\u003e 1000];\nphp \u003e echo json_encode(Teds\\binary_search($values, 1));\n{\"found\":false,\"key\":null,\"value\":null}\nphp \u003e echo json_encode(Teds\\binary_search($values, 100));\n{\"found\":true,\"key\":1,\"value\":100}\nphp \u003e echo json_encode(Teds\\binary_search($values, 201));\n{\"found\":false,\"key\":3,\"value\":200}\nphp \u003e echo json_encode(Teds\\binary_search($values, 99));\n{\"found\":false,\"key\":null,\"value\":null}\nphp \u003e echo json_encode(Teds\\binary_search($values, 1, useKey: true));\n{\"found\":true,\"key\":1,\"value\":100}\n```\n\n## Array functionality\n\n[teds.stub.php](./teds.stub.php)\n\n- `Teds\\is_same_array_handle(array $array1, array $array2)` - check if two arrays have the same handle, for [infinite recursion detection](tests/array/is_same_array_handle.phpt).\n- `Teds\\array_value_first(array $array)`, `Teds\\array_value_last(array $array)` - Return the first/last value of an array without creating references or moving the internal array pointer. Similar to `$array[array_key_first($array)] ?? null`.\n\n## Motivation\n\nThis contains functionality and data structures that may be proposed for inclusion into PHP itself (under a different namespace) at a future date, reimplemented using [SPL's source code](https://github.com/php/php-src/tree/master/ext/spl) as a starting point.\n\nProviding this as a PECL first makes this functionality easier to validate for correctness, and make it more practical to change APIs before proposing including them in PHP if needed.\n\n## License\n\nSee [COPYING](./COPYING)\n\n## Changelog\n\nSee [package.xml](./package.xml)\n\n## Related Projects\n\n- https://www.php.net/spl is built into php\n- https://www.php.net/manual/en/book.ds.php\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftysonandre%2Fpecl-teds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftysonandre%2Fpecl-teds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftysonandre%2Fpecl-teds/lists"}