Exemplo n.º 1
0
 /**
  * Randomizes the positions of the elements in an array.
  *
  * @param  array $array The array to be shuffled.
  *
  * @return void
  */
 public static function shuffle($array)
 {
     assert('is_carray($array)', vs(isset($this), get_defined_vars()));
     $array = splarray($array);
     // The Fisher-Yates algorithm.
     for ($i = $array->getSize() - 1; $i > 0; $i--) {
         $exchangeIdx = CMathi::intervalRandom(0, $i);
         $save = $array[$exchangeIdx];
         $array[$exchangeIdx] = $array[$i];
         $array[$i] = $save;
     }
 }
Exemplo n.º 2
0
 /**
  * Randomizes the positions of the characters in a string and returns the new string.
  *
  * @param  string $string The string to be shuffled.
  *
  * @return string The shuffled string.
  */
 public static function shuffle($string)
 {
     assert('is_cstring($string)', vs(isset($this), get_defined_vars()));
     // The Fisher-Yates algorithm.
     for ($i = strlen($string) - 1; $i > 0; $i--) {
         $exchangeIdx = CMathi::intervalRandom(0, $i);
         $save = $string[$exchangeIdx];
         $string[$exchangeIdx] = $string[$i];
         $string[$i] = $save;
     }
     return $string;
 }
Exemplo n.º 3
0
 protected static function shiftTimeInTimeZone(CTime $time, $timeUnit, $quantity, $timeZone)
 {
     $units;
     switch ($timeUnit) {
         case self::SECOND:
             $units = "seconds";
             break;
         case self::MINUTE:
             $units = "minutes";
             break;
         case self::HOUR:
             $units = "hours";
             break;
         case self::DAY:
             $units = "days";
             break;
         case self::WEEK:
             $units = "weeks";
             break;
         case self::MONTH:
             $units = "months";
             break;
         case self::YEAR:
             $units = "years";
             break;
         default:
             assert('false', vs(isset($this), get_defined_vars()));
             break;
     }
     $dt = new DateTime();
     $dt->setTimestamp($time->UTime());
     $dt->setTimezone(is_cstring($timeZone) ? new DateTimeZone($timeZone) : $timeZone->DTimeZone());
     $sign = $quantity < 0 ? "-" : "+";
     $absQty = CString::fromInt(CMathi::abs($quantity));
     $dt->modify("{$sign}{$absQty} {$units}");
     $UTime = $dt->getTimestamp();
     $MTime = $time->MTime();
     if ($UTime != 0 && $MTime != 0 && CMathi::sign($UTime) != CMathi::sign($MTime)) {
         if ($UTime < 0) {
             // $MTime > 0
             $UTime++;
             $MTime -= 1000;
         } else {
             // $MTime < 0
             $UTime--;
             $MTime += 1000;
         }
     }
     return new self($UTime, $MTime);
 }
Exemplo n.º 4
0
 /**
  * Wraps the text in a string to a specified width and returns the new string.
  *
  * @param  string $string The string with the text to be wrapped.
  * @param  int $width The wrapping width, in characters.
  * @param  bitfield $wrappingFlags **OPTIONAL. Default is** `WRAPPING_DEFAULT`. The wrapping option(s). The
  * available options are `WRAPPING_BREAK_SPACELESS_LINES`, `WRAPPING_ALLOW_TRAILING_SPACES`,
  * `WRAPPING_DISALLOW_LEADING_SPACES`, and `WRAPPING_DONT_BREAK_SPACELESS_CJK_ENDING_LINES`
  * (see [Summary](#summary)).
  * @param  string $newline **OPTIONAL. Default is** LF (U+000A). The newline character(s) to be used for making
  * new lines in the process of wrapping.
  *
  * @return string The wrapped text.
  */
 public static function wordWrap($string, $width, $wrappingFlags = self::WRAPPING_DEFAULT, $newline = self::NEWLINE)
 {
     assert('is_cstring($string) && is_int($width) && is_bitfield($wrappingFlags) && is_cstring($newline)', vs(isset($this), get_defined_vars()));
     assert('$width > 0', vs(isset($this), get_defined_vars()));
     // Constant. Newline character that is used by the input string (after newline normalization).
     $normNl = self::NEWLINE;
     // Constant. Determines what characters should be considered spaces.
     // A character in the "Zs" Unicode category, an HT, or a Zero Width Space, except No-break Space and Narrow
     // No-break Space.
     $spaceSubjectRe = "(\\p{Zs}|\\x{0009}|\\x{200B})(?<!\\x{00A0}|\\x{202F})";
     // Break enabling characters.
     // Soft Hyphen or Tibetan Mark Intersyllabic Tsheg.
     $breakAllowCharSubjectRe = "\\x{00AD}|\\x{0F0B}";
     // Retrieve the wrapping options.
     $breakSpacelessLines = CBitField::isBitSet($wrappingFlags, self::WRAPPING_BREAK_SPACELESS_LINES);
     $allowTrailingSpaces = CBitField::isBitSet($wrappingFlags, self::WRAPPING_ALLOW_TRAILING_SPACES);
     $disallowLeadingSpaces = CBitField::isBitSet($wrappingFlags, self::WRAPPING_DISALLOW_LEADING_SPACES);
     $dontBreakSpacelessCjkEndingLines = CBitField::isBitSet($wrappingFlags, self::WRAPPING_DONT_BREAK_SPACELESS_CJK_ENDING_LINES);
     // Normalize newlines in the input string.
     $string = self::normNewlines($string, $normNl);
     $normNlLength = self::length($normNl);
     $newString = "";
     $pos = 0;
     $bytePos = 0;
     $sLength = self::length($string);
     while (true) {
         $numCharsLeft = $sLength - $pos;
         // A portion begins at the very start or right after a newline, either it is native or added. The length of
         // a portion is the wrapping width or less.
         $portionLength = CMathi::min($width, $numCharsLeft);
         $portion = self::substr($string, $pos, $portionLength);
         $portionByteLength = CString::length($portion);
         if ($portionLength == $numCharsLeft) {
             // All done.
             $newString .= $portion;
             break;
         }
         // The starting position of the next portion.
         $nextPos = $pos + $portionLength;
         $nextBytePos = $bytePos + $portionByteLength;
         // Look for the first occurrence of a newline in the portion.
         $nlPos = self::indexOf($portion, $normNl);
         if ($nlPos != -1) {
             // This portion contains a newline, so the next portion is going to start right after this first found
             // newline.
             $subPLength = $nlPos + $normNlLength;
             $subP = self::substr($portion, 0, $subPLength);
             $newString .= $subP;
             $pos += $subPLength;
             $bytePos += CString::length($subP);
             continue;
         }
         // There are no newlines in this portion. Before the next step, make sure that the next portion is not
         // going to start with a newline.
         if ($numCharsLeft - $portionLength >= $normNlLength) {
             $nextPortionBeginning = self::substr($string, $nextPos, $normNlLength);
             if (self::indexOf($nextPortionBeginning, $normNl) == 0) {
                 // The next portion is going to start with a newline, so no need to break this one, regardless of
                 // whether or not it contains any spaces.
                 $newString .= $portion;
                 $pos = $nextPos;
                 $bytePos = $nextBytePos;
                 continue;
             }
         }
         // The next portion is not going to start with a newline. Look for the last occurrence of a space or
         // break-allow character in this portion.
         $lastSubjectBytePos = CRegex::lastIndexOf($portion, "/({$spaceSubjectRe})|({$breakAllowCharSubjectRe})/u", 0, $foundString);
         if ($lastSubjectBytePos != -1) {
             // Add a newline right after this last occurring space or break-allow character.
             $subP = CString::substring($portion, 0, $lastSubjectBytePos + CString::length($foundString));
             $newString .= $subP;
             $newString .= $newline;
             $pos += self::length($subP);
             $bytePos += CString::length($subP);
             continue;
         }
         // There are no spaces or break-allow characters in this portion. Consider adding a newline right after the
         // portion.
         if ($breakSpacelessLines || !$dontBreakSpacelessCjkEndingLines && self::hasCjkChar(self::charAt($portion, $portionLength - 1))) {
             $newString .= $portion;
             $newString .= $newline;
             $pos = $nextPos;
             $bytePos = $nextBytePos;
             continue;
         }
         // There are no spaces or break-allow characters in this portion and it should go adjacent to the upcoming
         // text. Look for the first newline, space, or break-allow character in the upcoming text.
         $nextSubjectBytePos = CRegex::indexOf($string, "/{$normNl}|(({$spaceSubjectRe})|({$breakAllowCharSubjectRe}))(?!{$normNl})/u", $nextBytePos, $foundString);
         if ($nextSubjectBytePos != -1) {
             // Found a newline, space, or a break-allow character, so the next portion is going to start right
             // after it.
             $afterP = CString::substring($string, $nextBytePos, $nextSubjectBytePos + CString::length($foundString));
             $newString .= $portion;
             $newString .= $afterP;
             if (!CString::equals($foundString, $normNl)) {
                 // It is a space or break-allow character that was found, so add a newline after it.
                 $newString .= $newline;
             }
             $pos += $portionLength + self::length($afterP);
             $bytePos += $portionByteLength + CString::length($afterP);
             continue;
         }
         // There are no spaces, newlines, or break-allow characters in the upcoming text. Finalize according to the
         // breaking options.
         if (!$breakSpacelessLines) {
             $newString .= $portion;
             $newString .= self::substr($string, $nextPos);
         } else {
             $newString .= $portion;
             $newString .= $newline;
             $pos = $nextPos;
             while (true) {
                 $numCharsLeft = $sLength - $pos;
                 $portionLength = CMathi::min($width, $numCharsLeft);
                 $newString .= self::substr($string, $pos, $portionLength);
                 if ($portionLength == $numCharsLeft) {
                     break;
                 }
                 $newString .= $newline;
                 $pos += $portionLength;
             }
         }
         break;
     }
     if (!$allowTrailingSpaces) {
         // Remove trailing spaces.
         $newString = CRegex::remove($newString, "/({$spaceSubjectRe})+(?={$normNl}|\\z)/u");
     }
     if ($disallowLeadingSpaces) {
         // Remove leading spaces.
         $newString = CRegex::remove($newString, "/(?<={$normNl}|^)({$spaceSubjectRe})+/u");
     }
     return $newString;
 }
Exemplo n.º 5
0
 /**
  * @ignore
  */
 public static function onThirdPartyUpdateByPackageManager()
 {
     if (!self::isInCliMode()) {
         // This method can be run in CLI mode only.
         assert('false', vs(isset($this), get_defined_vars()));
     }
     $timeoutPause = new CTimeoutPause();
     CShell::speak("Processing third-party components ...");
     $tpDps = CFile::listDirectories(CFilePath::absolute($GLOBALS["PHRED_PATH_TO_THIRD_PARTY"]));
     $ignorePackages = CConfiguration::option("upd.thirdPartyOopWrappingIgnorePackages");
     $ignorePackagesL2 = CArray::filter($ignorePackages, function ($package) {
         return CString::find($package, "/");
     });
     $newTpDps = CArray::make();
     $len = CArray::length($tpDps);
     for ($i = 0; $i < $len; $i++) {
         $tpDp = $tpDps[$i];
         $dirName = CFilePath::name($tpDp);
         if (!CArray::find($ignorePackages, $dirName)) {
             $dpHasL2DirsToIgnore = CArray::find($ignorePackagesL2, $dirName, function ($packageL2, $dirName) {
                 return CString::equals(CFilePath::directory($packageL2), $dirName);
             });
             if (!$dpHasL2DirsToIgnore) {
                 CArray::push($newTpDps, $tpDp);
             } else {
                 $tpSubDps = CFile::listDirectories($tpDp);
                 $tpSubDps = CArray::filter($tpSubDps, function ($subDp) use($ignorePackagesL2) {
                     return !CArray::find($ignorePackagesL2, $subDp, function ($packageL2, $subDp) {
                         return CString::endsWith($subDp, $packageL2);
                     });
                 });
                 CArray::pushArray($newTpDps, $tpSubDps);
             }
         }
     }
     $tpDps = $newTpDps;
     $wrapProtectedMethods = CConfiguration::option("upd.thirdPartyOopWrappingInProtectedMethods");
     $wrapPrivateMethods = CConfiguration::option("upd.thirdPartyOopWrappingInPrivateMethods");
     static $s_stdPhpTag = "<?php";
     static $s_progressResolution = 0.05;
     $prevProgressDivR = 0;
     $tpDpsLen = CArray::length($tpDps);
     for ($i0 = 0; $i0 < $tpDpsLen; $i0++) {
         $tpFps = CFile::reFindFilesRecursive($tpDps[$i0], "/\\.php\\d?\\z/");
         $tpFpsLen = CArray::length($tpFps);
         for ($i1 = 0; $i1 < $tpFpsLen; $i1++) {
             $fileCode = CFile::read($tpFps[$i1]);
             if (!CString::find($fileCode, self::$ms_thirdPartyAlreadyOopWrappedMark)) {
                 $parser = new PhpParser\Parser(new PhpParser\Lexer());
                 try {
                     // Parse the code.
                     $statements = $parser->parse($fileCode);
                     // Wrap the code into OOP.
                     $traverser = new PhpParser\NodeTraverser();
                     $mainVisitor = new CMainVisitor($wrapProtectedMethods, $wrapPrivateMethods);
                     $traverser->addVisitor($mainVisitor);
                     $statements = $traverser->traverse($statements);
                     $wrappedCode = (new PhpParser\PrettyPrinter\Standard())->prettyPrint($statements);
                     $phpTagPos = CString::indexOf($wrappedCode, $s_stdPhpTag);
                     if ($phpTagPos == -1) {
                         $wrappedCode = "{$s_stdPhpTag}\n\n{$wrappedCode}";
                         $phpTagPos = 0;
                     }
                     $wrappedCode = CString::insert($wrappedCode, $phpTagPos + CString::length($s_stdPhpTag), "\n\n" . self::$ms_thirdPartyAlreadyOopWrappedMark);
                     // Save.
                     CFile::write($tpFps[$i1], $wrappedCode);
                 } catch (PhpParser\Error $parserError) {
                     CShell::say("\nPhpParser: " . $tpFps[$i1] . ", at line " . $parserError->getRawLine() . ": " . $parserError->getRawMessage());
                 }
             }
             $progress = (double) ($i0 / $tpDpsLen + 1 / $tpDpsLen * $i1 / $tpFpsLen);
             $progressDivR = CMathi::floor($progress / $s_progressResolution);
             if ($progressDivR != $prevProgressDivR) {
                 $perc = CMathi::round($progressDivR * $s_progressResolution * 100);
                 CShell::speak("{$perc}%");
             }
             $prevProgressDivR = $progressDivR;
         }
     }
     CShell::speak("100%");
     CShell::say("Done.");
     $timeoutPause->end();
 }
Exemplo n.º 6
0
 public function testFilter()
 {
     $array = a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     $array = $array->filter(function ($element) {
         return CMathi::isEven($element);
     });
     $this->assertTrue($array->equals(a(2, 4, 6, 8, 10)));
 }
Exemplo n.º 7
0
 public function testFilter()
 {
     $array = CArray::fromElements(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
     $array = CArray::filter($array, function ($element) {
         return CMathi::isEven($element);
     });
     $this->assertTrue(CArray::equals($array, CArray::fromElements(2, 4, 6, 8, 10)));
 }
Exemplo n.º 8
0
 /**
  * Determines the order in which two maps should appear in a place where it matters.
  *
  * You can use your own comparator for the comparison of the values in the maps, but the default comparator has got
  * you covered when comparing scalar values, such as `string`, `int`, `float`, and `bool` in the ascending order or
  * in the descending order if you use `CComparator::ORDER_DESC`. And the default comparator is smart enough to know
  * how to compare objects of those classes that conform to the IEqualityAndOrder interface (static or not),
  * including CArray and CMap. See the [CComparator](CComparator.html) class for more on this.
  *
  * @param  map $map The first map for comparison.
  * @param  map $toMap The second map for comparison.
  * @param  callable $comparator **OPTIONAL. Default is** `CComparator::ORDER_ASC`. The function or method to be
  * used for the comparison of any two values. If this parameter is provided, the comparator should take two
  * parameters, with the first parameter being a value from the first map and the second parameter being a value
  * from the second map, and return `-1` if the value from the first map would need to go before the value from the
  * second map if the two were being ordered in separate, `1` if the other way around, and `0` if the two values are
  * equal.
  *
  * @return int A negative value (typically `-1`) if the first map should go before the second map, a positive value
  * (typically `1`) if the other way around, and `0` if the two maps are equal.
  *
  * @link   CComparator.html CComparator
  */
 public static function compare($map, $toMap, $comparator = CComparator::ORDER_ASC)
 {
     assert('is_cmap($map) && is_cmap($toMap)', vs(isset($this), get_defined_vars()));
     $map = parray($map);
     $toMap = parray($toMap);
     // Compare the keys.
     $keys = array_keys($map);
     $toKeys = array_keys($toMap);
     if (count($keys) != count($toKeys)) {
         return CMathi::sign(count($keys) - count($toKeys));
     }
     for ($i = 0; $i < count($keys); $i++) {
         if ($keys[$i] !== $toKeys[$i]) {
             return $keys[$i] < $toKeys[$i] ? -1 : 1;
         }
     }
     // Compare the values. The quantities should match at this point.
     $values = array_values($map);
     $toValues = array_values($toMap);
     for ($i = 0; $i < count($values); $i++) {
         $compRes = call_user_func($comparator, $values[$i], $toValues[$i]);
         if ($compRes != 0) {
             return $compRes;
         }
     }
     return 0;
 }
Exemplo n.º 9
0
 public function testFilter()
 {
     $map = m(["one" => 1, "two" => 2, "three" => 3, "four" => 4, "five" => 5, "six" => 6, "seven" => 7, "eight" => 8, "nine" => 9, "ten" => 10]);
     $map = $map->filter(function ($value) {
         return CMathi::isEven($value);
     });
     $this->assertTrue($map->equals(m(["two" => 2, "four" => 4, "six" => 6, "eight" => 8, "ten" => 10])));
 }
Exemplo n.º 10
0
 /**
  * Converts an integer quantity of mass from one unit into another and returns the result.
  *
  * @param  int $quantity The quantity to be converted.
  * @param  enum $fromUnit The source unit.
  * @param  enum $toUnit The destination unit.
  *
  * @return int The converted quantity, after rounding to the nearest integer.
  */
 public static function convertMassi($quantity, $fromUnit, $toUnit)
 {
     assert('is_int($quantity) && is_enum($fromUnit) && is_enum($toUnit)', vs(isset($this), get_defined_vars()));
     assert('$quantity >= 0', vs(isset($this), get_defined_vars()));
     if ($fromUnit == $toUnit) {
         return $quantity;
     }
     $floatQuantity = (double) $quantity;
     $milligramQty;
     switch ($fromUnit) {
         case self::MILLIGRAM:
             $milligramQty = $floatQuantity;
             break;
         case self::GRAM:
             $milligramQty = $floatQuantity * 1000;
             break;
         case self::KILOGRAM:
             $milligramQty = $floatQuantity * 1000000;
             break;
         case self::TON:
             $milligramQty = $floatQuantity * 1000000000;
             break;
         case self::OUNCE:
             $milligramQty = $floatQuantity * 28349.5231;
             break;
         case self::POUND:
             $milligramQty = $floatQuantity * 453592.37;
             break;
         case self::STONE:
             $milligramQty = $floatQuantity * 6350293.18;
             break;
         case self::SHORT_TON:
             $milligramQty = $floatQuantity * 907184740;
             break;
         case self::LONG_TON:
             $milligramQty = $floatQuantity * 1016046908.8;
             break;
         default:
             assert('false', vs(isset($this), get_defined_vars()));
             break;
     }
     $outputQty;
     switch ($toUnit) {
         case self::MILLIGRAM:
             $outputQty = CMathi::round($milligramQty);
             break;
         case self::GRAM:
             $outputQty = CMathi::round($milligramQty / 1000);
             break;
         case self::KILOGRAM:
             $outputQty = CMathi::round($milligramQty / 1000000);
             break;
         case self::TON:
             $outputQty = CMathi::round($milligramQty / 1000000000);
             break;
         case self::OUNCE:
             $outputQty = CMathi::round($milligramQty / 28349.5231);
             break;
         case self::POUND:
             $outputQty = CMathi::round($milligramQty / 453592.37);
             break;
         case self::STONE:
             $outputQty = CMathi::round($milligramQty / 6350293.18);
             break;
         case self::SHORT_TON:
             $outputQty = CMathi::round($milligramQty / 907184740);
             break;
         case self::LONG_TON:
             $outputQty = CMathi::round($milligramQty / 1016046908.8);
             break;
         default:
             assert('false', vs(isset($this), get_defined_vars()));
             break;
     }
     return $outputQty;
 }
Exemplo n.º 11
0
 /**
  * Returns the offset of a time zone from UTC, without adjusting it for daylight saving time.
  *
  * The offset is negative for the time zones located west of UTC (Greenwich, UK) and positive for the eastern ones.
  *
  * @return int The time zone's standard offset from UTC, in seconds.
  */
 public function standardOffsetSeconds()
 {
     $itz = $this->ITimeZone();
     $offset;
     $dstOffset;
     $itz->getOffset(time() * 1000, false, $offset, $dstOffset);
     return CMathi::round((double) $offset / 1000);
 }
Exemplo n.º 12
0
 public function testRoundToPow2Up()
 {
     $this->assertTrue(CMathi::roundToPow2Up(3) === 4);
     $this->assertTrue(CMathi::roundToPow2Up(5) === 8);
     $this->assertTrue(CMathi::roundToPow2Up(8) === 8);
     $this->assertTrue(CMathi::roundToPow2Up(600) === 1024);
     $this->assertTrue(CMathi::roundToPow2Up(3.01) === 4);
     $this->assertTrue(CMathi::roundToPow2Up(5.01) === 8);
     $this->assertTrue(CMathi::roundToPow2Up(8.01) === 8);
     $this->assertTrue(CMathi::roundToPow2Up(600.01) === 1024);
 }