diff --git a/src/php/iter.php b/src/php/iter.php
deleted file mode 100644
index 0a67146..0000000
--- a/src/php/iter.php
+++ /dev/null
@@ -1,168 +0,0 @@
-close();
- return true;
- } elseif ($it instanceof Generator) {
- try {
- $it->throw(new StopException());
- return true;
- } catch (StopException $e) {
- }
- }
- return false;
- }
-
- /**
- * retourner la première valeur du tableau, de l'itérateur ou de l'instance
- * de Traversable, ou $default si aucun élément n'est trouvé.
- */
- static final function first($values, $default=null) {
- if ($values instanceof IteratorAggregate) $values = $values->getIterator();
- if ($values instanceof Iterator) {
- try {
- $values->rewind();
- $value = $values->valid()? $values->current(): $default;
- } finally {
- self::close($values);
- }
- } elseif (is_array($values) || $values instanceof Traversable) {
- $value = $default;
- foreach ($values as $value) {
- break;
- }
- } else {
- throw self::unexpected_type($values);
- }
- return $value;
- }
-
- /**
- * retourner la première clé du tableau, de l'itérateur ou de l'instance
- * de Traversable, ou $default si aucun élément n'est trouvé.
- */
- static final function first_key($values, $default=null) {
- if ($values instanceof IteratorAggregate) $values = $values->getIterator();
- if ($values instanceof Iterator) {
- try {
- $values->rewind();
- $key = $values->valid()? $values->key(): $default;
- } finally {
- self::close($values);
- }
- } elseif (is_array($values) || $values instanceof Traversable) {
- $key = $default;
- foreach ($values as $key => $ignored) {
- break;
- }
- } else {
- throw self::unexpected_type($values);
- }
- return $key;
- }
-
- #############################################################################
- # outils pour gérer de façon générique des instances de {@link Iterator} ou
- # des arrays
-
- /**
- * @param $it ?iterable|array
- * @return bool true si l'itérateur ou le tableau ont pu être réinitialisés
- */
- static function rewind(&$it, ?Exception &$exception=null): bool {
- if ($it instanceof Iterator) {
- try {
- $exception = null;
- $it->rewind();
- return true;
- } catch (Exception $e) {
- $exception = $e;
- }
- } elseif ($it !== null) {
- reset($it);
- return true;
- }
- return false;
- }
-
- /**
- * @param $it ?iterable|array
- */
- static function valid($it): bool {
- if ($it instanceof Iterator) {
- return $it->valid();
- } elseif ($it !== null) {
- return key($it) !== null;
- } else {
- return false;
- }
- }
-
- /**
- * @param $it ?iterable|array
- */
- static function current($it, &$key=null) {
- if ($it instanceof Iterator) {
- $key = $it->key();
- return $it->current();
- } elseif ($it !== null) {
- $key = key($it);
- return current($it);
- } else {
- $key = null;
- return null;
- }
- }
-
- /**
- * @param $it ?iterable|array
- */
- static function next(&$it, ?Exception &$exception=null): void {
- if ($it instanceof Iterator) {
- try {
- $exception = null;
- $it->next();
- } catch (Exception $e) {
- $exception = $e;
- }
- } elseif ($it !== null) {
- next($it);
- }
- }
-
- /**
- * obtenir la valeur de retour si $it est un générateur terminé, ou null sinon
- */
- static function get_return($it) {
- if ($it instanceof Generator) {
- try {
- return $it->getReturn();
- } catch (Exception $e) {
- }
- }
- return null;
- }
-}
diff --git a/src/php/iter/Cursor.php b/src/php/iter/Cursor.php
deleted file mode 100644
index 1579c1f..0000000
--- a/src/php/iter/Cursor.php
+++ /dev/null
@@ -1,310 +0,0 @@
- ["?iterable"],
- "rows_func" => ["?callable"],
- "filter" => ["?array"],
- "filter_func" => ["?callable"],
- "map" => ["?array"],
- "map_func" => ["?callable"],
- "cols" => ["?array"],
- "cols_func" => ["?callable"],
- ];
-
- function __construct(?iterable $rows=null, ?array $params=null) {
- if ($rows !== null) $params["rows"] = $rows;
-
- $rows = $params["rows"] ?? null;
- $rowsGenerator = null;
- $rowsFunc = $params["rows_func"] ?? null;
- if ($rowsFunc !== null) {
- if ($rowsFunc instanceof Traversable) {
- $rowsGenerator = $rowsFunc;
- $rowsFunc = null;
- } else {
- $rowsFunc = func::with($rowsFunc, [$rows, $this]);
- }
- } elseif ($rows instanceof Traversable) {
- $rowsGenerator = $rows;
- } else {
- $rowsFunc = func::with(function() use ($rows) {
- return $rows;
- });
- }
- $this->rowsGenerator = $rowsGenerator;
- $this->rowsFunc = $rowsFunc;
-
- $filter = $params["filter"] ?? null;
- $filterFunc = $params["filter_func"] ?? null;
- if ($filterFunc !== null) $this->setFilterFunc($filterFunc);
- elseif ($filter !== null) $this->setFilter($filter);
-
- $map = $params["map"] ?? null;
- $mapFunc = $params["map_func"] ?? null;
- if ($mapFunc !== null) $this->setMapFunc($mapFunc);
- elseif ($map !== null) $this->setMap($map);
-
- $this->cols = $params["cols"] ?? null;
- $this->setColsFunc($params["cols_func"] ?? null);
- }
-
- /** un générateur de lignes */
- private ?Traversable $rowsGenerator;
-
- /**
- * une fonction de signature function(mixed $rows, Cursor): ?iterable
- */
- private ?func $rowsFunc;
-
- /**
- * une fonction de signature function(?array $row, Cursor): bool
- */
- private ?func $filterFunc = null;
-
- function setFilter(array $filter): self {
- $this->filterFunc = func::with(function(?array $row) use ($filter) {
- return cl::filter($row, $filter);
- });
- return $this;
- }
-
- function setFilterFunc(?callable $func): self {
- if ($func === null) $this->filterFunc = null;
- else $this->filterFunc = func::with($func)->bind($this);
- return $this;
- }
-
- /**
- * une fonction de signature function(?array $row, Cursor): ?array
- */
- private ?func $mapFunc = null;
-
- function setMap(array $map): self {
- $this->mapFunc = func::with(function(?array $row) use ($map) {
- return cl::map($row, $map);
- });
- return $this;
- }
-
- function setMapFunc(?callable $func): self {
- if ($func === null) $this->mapFunc = null;
- else $this->mapFunc = func::with($func)->bind($this);
- return $this;
- }
-
- /**
- * une fonction de signature function(?array $row, Cursor): ?array
- */
- private ?func $colsFunc = null;
-
- function setColsFunc(?callable $func): self {
- $this->cols = null;
- if ($func === null) $this->colsFunc = null;
- else $this->colsFunc = func::with($func)->bind($this);
- return $this;
- }
-
- /** @var iterable|null source des éléments */
- protected ?iterable $rows;
-
- /** @var array|null listes des colonnes de chaque enregistrement */
- public ?array $cols;
-
- /**
- * @var int index de l'enregistrement (en ne comptant pas les éléments filtrés)
- */
- public int $index;
-
- /**
- * @var int index original de l'enregistrement (en tenant compte des éléments
- * filtrés)
- */
- public int $origIndex;
-
- /** @var string|int clé de l'enregistrement */
- public $key;
-
- /** @var mixed élément original récupéré depuis la source */
- public $raw;
-
- /**
- * @var array|null enregistrement après conversion en tableau et application
- * du mapping
- */
- public ?array $row;
-
- function __get($name) {
- if ($name === "value") return $this->row;
- elseif ($name == "rows") return $this->rows;
- trigger_error("Undefined property $name");
- return null;
- }
-
- function offsetExists($offset): bool {
- return cl::has($this->row, $offset);
- }
-
- function offsetGet($offset) {
- return cl::get($this->row, $offset);
- }
-
- function offsetSet($offset, $value): void {
- cl::set($this->row, $offset, $value);
- }
-
- function offsetUnset($offset): void {
- cl::del($this->row, $offset);
- }
-
- /**
- * données de session: cela permet de maintenir certaines informations pendant
- * le parcours des données
- */
- protected ?array $data;
-
- /** @param string|int $key */
- function has($key): bool {
- return cl::has($this->data, $key);
- }
-
- /** @param string|int $key */
- function get($key) {
- return cl::get($this->data, $key);
- }
-
- /** @param string|int $key */
- function set($key, $value): void {
- $this->data[$key] = $value;
- }
-
- /** @param string|int $key */
- function del($key) {
- $orig = cl::get($this->data, $key);
- unset($this->data[$key]);
- return $orig;
- }
-
- protected function convertToRow($raw): ?array {
- return cl::withn($raw);
- }
-
- protected function filterFunc(?array $row): bool {
- return false;
- }
-
- protected function mapFunc(?array $row): ?array {
- return $this->row;
- }
-
- protected function colsFunc(?array $row): ?array {
- return $this->row !== null? array_keys($this->row): null;
- }
-
- #############################################################################
- # Iterator
-
- function rewind() {
- $this->cols = null;
- $this->index = 0;
- $this->origIndex = 0;
- $this->key = null;
- $this->raw = null;
- $this->row = null;
- $this->data = null;
- if ($this->rowsGenerator !== null) {
- $rows = $this->rowsGenerator;
- if ($rows instanceof IteratorAggregate) $rows = $rows->getIterator();
- $rows->rewind();
- $this->rows = $rows;
- } else {
- $this->rows = $this->rowsFunc->invoke();
- }
- }
-
- function valid(): bool {
- $colsFunc = $this->colsFunc;
- $filterFunc = $this->filterFunc;
- $mapFunc = $this->mapFunc;
- while ($valid = iter::valid($this->rows)) {
- $this->raw = iter::current($this->rows, $this->key);
- # conversion en enregistrement
- $this->key ??= $this->origIndex;
- $this->row = $this->convertToRow($this->raw);
- # filtrage
- if ($filterFunc === null) $filtered = $this->filterFunc($this->row);
- else $filtered = $filterFunc->invoke([$this->row, $this]);
- if ($filtered) {
- iter::next($this->rows);
- $this->origIndex++;
- } else {
- # l'enregistrement n'as pas été filtré: faire le mapping
- if ($mapFunc === null) $this->row = $this->mapFunc($this->row);
- else $this->row = $mapFunc->invoke([$this->row, $this]);
- # calculer la liste des colonnes le cas échéant
- if ($this->cols === null) {
- if ($colsFunc === null) $this->cols = $this->colsFunc($this->row);
- else $this->cols = $colsFunc->invoke([$this->row, $this]);
- }
- break;
- }
- }
- if (!$valid) {
- iter::close($this->rows);
- $this->rows = null;
- $this->cols = null;
- $this->index = -1;
- $this->origIndex = -1;
- $this->key = null;
- $this->raw = null;
- $this->row = null;
- # ne pas toucher à data, l'utilisateur peut vouloir continuer à consulter
- # les valeurs
- }
- return $valid;
- }
-
- function current(): ?array {
- return $this->row;
- }
-
- function key() {
- return $this->key;
- }
-
- function next() {
- iter::next($this->rows);
- $this->index++;
- $this->origIndex++;
- }
-
- #############################################################################
-
- function each(callable $func): void {
- $func = func::with($func);
- $this->rewind();
- while ($this->valid()) {
- $func->invoke([$this]);
- $this->next();
- }
- }
-}
diff --git a/tests/php/coll/CursorTest.php b/tests/php/coll/CursorTest.php
deleted file mode 100644
index b572c4c..0000000
--- a/tests/php/coll/CursorTest.php
+++ /dev/null
@@ -1,152 +0,0 @@
- 1, "b" => 2, "c" => 3, "x" => 99];
- $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null];
- self::assertSame([
- "a" => $row["a"],
- "b" => $row["x"],
- "c" => "y",
- "d" => null
- ], $cursor->mapRow($row, $map));
- }
-
- function test_filter_row() {
- $cursor = new class extends Cursor {
- function filterRow(array $row, $filter): bool {
- return cl::filter($row, $filter);
- }
- };
- $row = ["a" => 1, "b" => 2, "c" => 3, "x" => 99];
- self::assertTrue($cursor->filterRow($row, "a"));
- self::assertTrue($cursor->filterRow($row, ["a"]));
- self::assertTrue($cursor->filterRow($row, ["a" => true]));
- self::assertFalse($cursor->filterRow($row, ["a" => false]));
- self::assertTrue($cursor->filterRow($row, ["a" => 1]));
- self::assertFalse($cursor->filterRow($row, ["a" => 2]));
-
- self::assertFalse($cursor->filterRow($row, "z"));
- self::assertFalse($cursor->filterRow($row, ["z"]));
- self::assertFalse($cursor->filterRow($row, ["z" => true]));
- self::assertTrue($cursor->filterRow($row, ["z" => false]));
- self::assertFalse($cursor->filterRow($row, ["z" => 1]));
- }
-
- const SCALARS = [0, 1, 2, 3, 4];
-
- function generator() {
- yield from self::SCALARS;
- }
-
- function testVanilla() {
- $c = new Cursor(self::SCALARS);
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
-
- $c = new Cursor($this->generator());
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertException(Exception::class, function() use ($c) {
- // pas possible de rewind un générateur
- return cl::all($c);
- });
-
- $c = new Cursor(null, [
- "rows" => function() {
- return self::SCALARS;
- },
- ]);
- self::assertError(TypeError::class, function() use ($c) {
- // rows doit être un iterable, pas une fonction
- return cl::all($c);
- });
-
- $c = new Cursor(null, [
- "rows" => $this->generator(),
- ]);
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertException(Exception::class, function() use ($c) {
- // pas possible de rewind un générateur
- return cl::all($c);
- });
-
- $c = new Cursor(null, [
- "rows_func" => function() {
- return self::SCALARS;
- },
- ]);
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
-
- $c = new Cursor(null, [
- "rows_func" => $this->generator(),
- ]);
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertException(Exception::class, function() use ($c) {
- // pas possible de rewind un générateur
- return cl::all($c);
- });
-
- $c = new Cursor(null, [
- "rows_func" => function() {
- yield from self::SCALARS;
- },
- ]);
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- self::assertSame([[0], [1], [2], [3], [4]], cl::all($c));
- }
-
- function testMap() {
- $c = new Cursor(self::SCALARS, [
- "map_func" => function(Cursor $c) {
- return [$c->raw + 1];
- },
- ]);
- self::assertSame([[1], [2], [3], [4], [5]], cl::all($c));
- }
-
- function testFilter() {
- $c = new Cursor(self::SCALARS, [
- "filter_func" => function(Cursor $c) {
- return $c->raw % 2 == 0;
- },
- ]);
- self::assertSame([[1], [3]], cl::all($c));
- }
-
- function testEach() {
- $c = new Cursor(self::SCALARS, [
- "filter_func" => function(Cursor $c) {
- return $c->raw % 2 == 0;
- },
- "map_func" => function(Cursor $c) {
- return [$c->raw + 1];
- },
- ]);
- $xs = [];
- $xitems = [];
- $oxs = [];
- $kitems = [];
- $c->each(function(Cursor $c) use (&$xs, &$xitems, &$oxs, &$kitems) {
- $xs[] = $c->index;
- $oxs[] = $c->origIndex;
- $xitems[$c->index] = $c->row[0];
- $kitems[$c->key] = $c->row[0];
- });
- self::assertSame([0, 1], $xs);
- self::assertSame([2, 4], $xitems);
- self::assertSame([1, 3], $oxs);
- self::assertSame([1 => 2, 3 => 4], $kitems);
- }
-}