Hoa central
Realdom.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Realdom;
38 
39 use Hoa\Core;
40 use Hoa\Math;
41 use Hoa\Praspel;
42 use Hoa\Visitor;
43 
52 abstract class Realdom
53  implements \ArrayAccess,
54  \Countable,
56 {
62  const NAME = '(null)';
63 
69  protected $_arguments = null;
70 
76  protected $arguments = null;
77 
83  protected static $_sampler = null;
84 
90  protected $__sampler = null;
91 
97  protected $_value = null;
98 
104  protected static $_maxtry = 64;
105 
111  protected $_constraints = null;
112 
118  protected $_holder = null;
119 
125  protected $_constructed = false;
126 
132  protected static $_defaultPraspelVisitor = null;
133 
139  protected $_praspelVisitor = null;
140 
141 
142 
150  final public function __construct()
151  {
152  switch ($this->_arguments) {
153  case null:
154  $this->arguments = [];
155 
156  break;
157 
158  case …:
159  $this->arguments = func_get_args();
160  self::autoBoxing($this->arguments, $this);
161 
162  break;
163 
164  default:
165  $arguments = func_get_args();
166  $hints = [];
167  $this->arguments = [];
168  $i = 0;
169 
170  reset($this->_arguments);
171 
172  foreach ($arguments as $argument) {
173  $name = key($this->_arguments);
174  $hint = null;
175 
176  if (… === $argument) {
177  if (is_int($name)) {
178  throw new Exception\IllegalArgument(
179  'Argument %s passed to %s() does not have a ' .
180  'default value.',
181  0,
182  [$i + 1, $this->getName()]
183  );
184  }
185 
186  $argument = current($this->_arguments);
187  }
188 
189  if (is_int($name)) {
190  $name = current($this->_arguments);
191  ++$i;
192  }
193 
194  if (false !== $pos = strrpos($name, ' ')) {
195  $hint = trim(substr($name, 0, $pos));
196  $name = substr($name, $pos + 1);
197  }
198 
199  $this->arguments[$name] = $argument;
200  $hints[] = $hint;
201  next($this->_arguments);
202  }
203 
204  while (list($name, $default) = each($this->_arguments)) {
205  if (is_int($name)) {
206  $j = 0;
207  array_walk(
208  $this->_arguments,
209  function ($_, $key) use (&$j) {
210  $j += is_int($key);
211 
212  return;
213  }
214  );
215 
216  throw new Exception\MissingArgument(
217  1 < $j
218  ? '%s() expects at least %d parameters, %d given.'
219  : '%s() expects at least %d parameter, %d given.',
220  1,
221  [$this->getName(), $j, $i]
222  );
223  }
224 
225  $hint = null;
226 
227  if (false !== $pos = strrpos($name, ' ')) {
228  $hint = trim(substr($name, 0, $pos));
229  $name = substr($name, $pos + 1);
230  }
231 
232  $this->arguments[$name] = $default;
233  $hints[] = $hint;
234  }
235 
236  self::autoBoxing($this->arguments, $this);
237 
238  foreach ($this->arguments as &$argument) {
239  $hint = current($hints);
240 
241  if (null === $hint) {
242  next($hints);
243 
244  continue;
245  }
246 
247  if ($argument instanceof IRealdom\Holder) {
248  $_realdoms = $argument->getHeld();
249  } elseif ($argument instanceof IRealdom\Crate) {
250  $_realdoms = $argument->getTypes();
251  } elseif ($argument instanceof Disjunction) {
252  $_realdoms = $argument->getRealdoms();
253  } else {
254  $_realdoms = [$argument];
255  }
256 
257  $k = 0;
258 
259  $_hints = explode('|', $hint);
260 
261  foreach ($_hints as &$_hint) {
262  if ('\\' !== $_hint[0]) {
263  $_hint = __NAMESPACE__ . '\\' . $_hint;
264  }
265  }
266 
267  foreach ($_realdoms as $_realdom) {
268  $flag = false;
269 
270  foreach ($_hints as $__hint) {
271  if ($_realdom instanceof $__hint ||
272  $_realdom === $__hint) {
273  $flag = true;
274 
275  break;
276  }
277  }
278 
279  if (false === $flag) {
280  unset($_realdoms[$k]);
281  } else {
282  ++$k;
283  }
284  }
285 
286  switch (count($_realdoms)) {
287  case 0:
288  if ($argument instanceof IRealdom\Holder) {
289  throw new Exception\IllegalArgument(
290  'Argument %d passed to %s() must be of ' .
291  'type %s, variable %s does not satisfy ' .
292  'this constraint.',
293  2,
294  [
295  key($hints),
296  $this->getName(),
297  mb_strtolower($hint),
298  $argument->getName()
299  ]
300  );
301  }
302 
303  throw new Exception\IllegalArgument(
304  'Argument %d passed to %s() must be of type ' .
305  '%s, %s given.',
306  3,
307  [
308  key($hints),
309  $this->getName(),
310  mb_strtolower($hint),
311  mb_strtolower(mb_substr(
312  $_ = get_class($argument),
313  mb_strrpos($_, '\\') + 1
314  ))
315  ]
316  );
317 
318  break;
319 
320  case 1:
321  if ($argument instanceof IRealdom\Crate) {
322  break;
323  }
324 
325  $argument = $_realdoms[0];
326 
327  break;
328 
329  default:
330  throw new Exception\IllegalArgument(
331  'Variable %s, passed as argument %d of %s(), ' .
332  'has to many domains.',
333  4,
334  [
335  $argument->getName(),
336  key($hints),
337  $this->getName()
338  ]
339  );
340  }
341 
342  next($hints);
343  }
344  }
345 
346  return;
347  }
348 
354  protected function construct()
355  {
356  return;
357  }
358 
366  public static function autoBoxing(Array &$arguments, Realdom $self = null)
367  {
368  if (is_object($self) &&
369  (get_class($self) === 'Hoa\Realdom\Constarray' ||
370  get_class($self) === 'Hoa\Realdom\Constboolean' ||
371  get_class($self) === 'Hoa\Realdom\Constfloat' ||
372  get_class($self) === 'Hoa\Realdom\Constinteger' ||
373  get_class($self) === 'Hoa\Realdom\Constnull' ||
374  get_class($self) === 'Hoa\Realdom\Conststring')) {
375  return;
376  }
377 
378  foreach ($arguments as &$argument) {
379  switch (gettype($argument)) {
380  case 'array':
381  $handle = [];
382 
383  foreach ($argument as &$pair) {
384  $handle[] = &$pair[0];
385 
386  if (isset($pair[1])) {
387  $handle[] = &$pair[1];
388  }
389  }
390 
391  self::autoBoxing($handle);
392 
393  $argument = new Constarray($argument);
394 
395  break;
396 
397  case 'boolean':
398  $argument = new Constboolean($argument);
399 
400  break;
401 
402  case 'double':
403  $argument = new Constfloat($argument);
404 
405  break;
406 
407  case 'integer':
408  $argument = new Constinteger($argument);
409 
410  break;
411 
412  case 'NULL':
413  $argument = new Constnull($argument);
414 
415  break;
416 
417  case 'string':
418  $argument = new Conststring($argument);
419 
420  break;
421 
422  default:
423  if ($argument instanceof IRealdom\Holder) {
424  $argument = $argument->getHeld();
425 
426  if (null !== $self) {
427  $argument = $argument[0];
428  }
429 
430  break;
431  }
432  }
433  }
434 
435  return;
436  }
437 
444  public function offsetExists($offset)
445  {
446  return
447  isset($this->arguments[$offset]) &&
448  !($this->arguments[$offset] instanceof Constnull);
449  }
450 
457  public function offsetGet($offset)
458  {
459  return
460  true === $this->offsetExists($offset)
461  ? $this->arguments[$offset]
462  : null;
463  }
464 
472  public function offsetSet($offset, $value)
473  {
474  $old = $this->offsetGet($offset);
475  $this->arguments[$offset] = $value;
476 
477  return $old;
478  }
479 
486  public function offsetUnset($offset)
487  {
488  unset($this->arguments[$offset]);
489 
490  return;
491  }
492 
498  public function getArguments()
499  {
500  return $this->arguments;
501  }
502 
508  public function count()
509  {
510  return count($this->arguments);
511  }
512 
518  public function getName()
519  {
520  return static::NAME;
521  }
522 
529  public static function setDefaultSampler(Math\Sampler $sampler)
530  {
531  $old = static::$_sampler;
532  static::$_sampler = $sampler;
533 
534  return $old;
535  }
536 
542  public static function getDefaultSampler()
543  {
544  return static::$_sampler;
545  }
546 
553  public function setSampler(Math\Sampler $sampler)
554  {
555  $old = $this->__sampler;
556  $this->__sampler = $sampler;
557 
558  return $old;
559  }
560 
566  public function getSampler()
567  {
568  return $this->__sampler ?: static::$_sampler;
569  }
570 
577  protected function setValue($sampled)
578  {
579  $old = $this->_value;
580  $this->_value = $sampled;
581 
582  return $old;
583  }
584 
590  public function getValue()
591  {
592  return $this->_value;
593  }
594 
601  public static function setMaxTry($maxtry)
602  {
603  $old = self::$_maxtry;
604  self::$_maxtry = $maxtry;
605 
606  return $old;
607  }
608 
614  public static function getMaxTry()
615  {
616  return self::$_maxtry;
617  }
618 
624  public function reset()
625  {
626  if (false === $this->_constructed) {
627  $this->construct();
628  $this->_constructed = true;
629  }
630 
631  if ($this instanceof IRealdom\Nonconvex &&
632  isset($this->_discredited)) {
633  $this->_discredited = [];
634  }
635 
636  return;
637  }
638 
644  protected function resetArguments()
645  {
646  foreach ($this->getArguments() as $name => $argument) {
647  if ($argument instanceof self) {
648  $argument->reset();
649  }
650  }
651 
652  return;
653  }
654 
661  public function predicate($q)
662  {
663  if (false === $this->_constructed) {
664  $this->construct();
665  $this->_constructed = true;
666  }
667 
668  return $this->_predicate($q);
669  }
670 
677  abstract protected function _predicate($q);
678 
686  public function sample(Math\Sampler $sampler = null)
687  {
688  if (false === $this->_constructed) {
689  $this->construct();
690  $this->_constructed = true;
691  }
692 
693  if (null === $sampler &&
694  null === $sampler = $this->getSampler()) {
695  throw new Exception(
696  'No sampler set. Please, use the %s::setDefaultSampler() or ' .
697  '%1$s::setSampler() method.',
698  4,
699  __CLASS__
700  );
701  }
702 
703  $maxtry = $this->getMaxTry();
704 
705  do {
706  $sampled = $this->_sample($sampler);
707  $predicate = $this->predicate($sampled);
708 
709  if (false === $predicate) {
710  $this->reset();
711  }
712  } while (false === $predicate && 0 < --$maxtry);
713 
714  if (0 >= $maxtry) {
715  throw new Exception(
716  'Cannot sample a value, all tries failed (%d tries) from %s.',
717  5,
718  [$this->getMaxTry(), $this->getName()]
719  );
720  }
721 
722  $this->setValue($sampled);
723 
724  return $sampled;
725  }
726 
733  abstract protected function _sample(Math\Sampler $sampler);
734 
741  public function intersectWith(Realdom $realdom)
742  {
743  return false;
744  }
745 
753  public function setConstraints(Array &$constraints)
754  {
755  $this->_constraints = &$constraints;
756 
757  return $this;
758  }
759 
765  protected function &getConstraints()
766  {
767  return $this->_constraints;
768  }
769 
777  public function propagateConstraints($type, $index)
778  {
779  $this->_propagateConstraints($type, $index, $this->getConstraints());
780 
781  return;
782  }
783 
793  protected function _propagateConstraints(
794  $type,
795  $index,
796  Array &$constraints
797  ) {
798  return;
799  }
800 
807  public function is($qualifier)
808  {
809  if (!isset($this->_constraints['is'])) {
810  return false;
811  }
812 
813  return in_array($qualifier, $this->_constraints['is']);
814  }
815 
822  public function setHolder(IRealdom\Holder $holder)
823  {
824  $old = $holder;
825  $this->_holder = $holder;
826 
827  return $old;
828  }
829 
835  public function getHolder()
836  {
837  return $this->_holder;
838  }
839 
846  public static function setDefaultPraspelVisitor(Visitor\Visit $visitor)
847  {
848  $old = static::$_defaultPraspelVisitor;
849  static::$_defaultPraspelVisitor = $visitor;
850 
851  return $old;
852  }
853 
861  public static function getDefaultPraspelVisitor()
862  {
863  if (null === static::$_defaultPraspelVisitor) {
864  static::$_defaultPraspelVisitor = new Praspel\Visitor\Praspel();
865  }
866 
867  return static::$_defaultPraspelVisitor;
868  }
869 
876  public function setPraspelVisitor(Visitor\Visit $visitor)
877  {
878  $old = $this->_praspelVisitor;
879  $this->_praspelVisitor = $visitor;
880 
881  return $old;
882  }
883 
889  public function getPraspelVisitor()
890  {
891  return $this->_praspelVisitor ?: static::getDefaultPraspelVisitor();
892  }
893 
902  public function accept(
903  Visitor\Visit $visitor,
904  &$handle = null,
905  $eldnah = null
906  ) {
907  return $visitor->visit($this, $handle, $eldnah);
908  }
909 }
910 
914 Core\Consistency::flexEntity('Hoa\Realdom\Realdom');
accept(Visitor\Visit $visitor, &$handle=null, $eldnah=null)
Definition: Realdom.php:902
static getMaxTry()
Definition: Realdom.php:614
static setMaxTry($maxtry)
Definition: Realdom.php:601
offsetGet($offset)
Definition: Realdom.php:457
static autoBoxing(Array &$arguments, Realdom $self=null)
Definition: Realdom.php:366
offsetSet($offset, $value)
Definition: Realdom.php:472
_sample(Math\Sampler $sampler)
static getDefaultPraspelVisitor()
Definition: Realdom.php:861
_propagateConstraints($type, $index, Array &$constraints)
Definition: Realdom.php:793
is($qualifier)
Definition: Realdom.php:807
sample(Math\Sampler $sampler=null)
Definition: Realdom.php:686
setConstraints(Array &$constraints)
Definition: Realdom.php:753
static setDefaultSampler(Math\Sampler $sampler)
Definition: Realdom.php:529
setValue($sampled)
Definition: Realdom.php:577
setPraspelVisitor(Visitor\Visit $visitor)
Definition: Realdom.php:876
offsetUnset($offset)
Definition: Realdom.php:486
static getDefaultSampler()
Definition: Realdom.php:542
propagateConstraints($type, $index)
Definition: Realdom.php:777
intersectWith(Realdom $realdom)
Definition: Realdom.php:741
static $_defaultPraspelVisitor
Definition: Realdom.php:132
static setDefaultPraspelVisitor(Visitor\Visit $visitor)
Definition: Realdom.php:846
setHolder(IRealdom\Holder $holder)
Definition: Realdom.php:822
offsetExists($offset)
Definition: Realdom.php:444
setSampler(Math\Sampler $sampler)
Definition: Realdom.php:553