169 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php # -*- coding: utf-8 mode: php -*- vim:sw=2:sts=2:et:ai:si:sta:fenc=utf-8
 | 
						|
namespace nulib\php;
 | 
						|
 | 
						|
use Exception;
 | 
						|
use Generator;
 | 
						|
use Iterator;
 | 
						|
use IteratorAggregate;
 | 
						|
use nulib\StopException;
 | 
						|
use nulib\ValueException;
 | 
						|
use Traversable;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class iter: gestion des itérateurs
 | 
						|
 */
 | 
						|
class iter {
 | 
						|
  private static function unexpected_type($object): ValueException {
 | 
						|
    return ValueException::invalid_type($object, "iterable");
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * fermer "proprement" un itérateur ou un générateur. retourner true en cas de
 | 
						|
   * succès, ou false si c'est un générateur et qu'il ne supporte pas l'arrêt
 | 
						|
   * avec StopException (la valeur de retour n'est alors pas disponible)
 | 
						|
   */
 | 
						|
  static function close($it): bool {
 | 
						|
    if ($it instanceof ICloseable) {
 | 
						|
      $it->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;
 | 
						|
  }
 | 
						|
}
 |