@ 2014-03-02T22:52:43Z <?php
class LinkedList
{
/** @var LinkedListBucket */
public $first;
/** @var LinkedListBucket */
public $last;
public $length = 0;
public $min = PHP_INT_MAX;
public function append(LinkedListBucket $bucket)
{
$this->last->next = $bucket;
$this->last = $bucket;
$this->length++;
if ($bucket->codePoint < $this->min) {
$this->min = $bucket->codePoint;
}
}
public function insert(LinkedListBucket $after, LinkedListBucket $new)
{
$new->next = $after->next;
$after->next = $new;
if ($after === $this->last) {
$this->last = $new;
}
$this->length++;
if ($new->codePoint < $this->min) {
$this->min = $new->codePoint;
}
}
}
class LinkedListBucket
{
public $pos;
public $codePoint;
public $raw;
public $rawLen;
/** @var LinkedListBucket */
public $next;
public function __construct($pos, $codePoint, $raw = null, $rawLen = 0)
{
$this->pos = $pos;
$this->codePoint = $codePoint;
$this->raw = $raw;
$this->rawLen = $rawLen;
}
}
class Punycode
{
const BASE = 36;
const T_MIN = 1;
const T_MAX = 26;
const SKEW = 38;
const DAMP = 700;
const INITIAL_BIAS = 72;
const INITIAL_N = 128;
private function decodeUtf8Character($input, $i, &$codePoint = null)
{
$input = array_values(unpack('C*', substr($input, $i, 4)));
$count = count($input);
switch (true) {
case $count >= 2 && ($input[0] & 0xE0) === 0xC0 && ($input[1] & 0xC0) === 0x80:
$codePoint = (($input[0] & 0x1F) << 6) | ($input[1] & 0x3F);
return 2;
case $count >= 3 && ($input[0] & 0xF0) === 0xE0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & 0xC0) === 0xC0:
$codePoint = (($input[0] & 0x0F) << 12) | (($input[1] & 0x3F) << 6) | ($input[2] & 0x3F);
return 3;
case $count >= 4 && ($input[0] & 0xF8) === 0xF0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & ($input[3] ^ 0x40) & 0xC0) === 0xC0:
$codePoint = (($input[0] & 0x07) << 18) | (($input[1] & 0x3F) << 12) | (($input[2] & 0x3F) << 6) | ($input[3] & 0x3F);
return 4;
}
return 0;
}
private function encodeUtf8CodePoint($codePoint)
{
switch (true) {
case $codePoint < 0x80:
return pack('C*', $codePoint & 0x7F);
case $codePoint < 0x0800:
return pack('C*', (($codePoint & 0x07C0) >> 6) | 0xC0, ($codePoint & 0x3F) | 0x80);
case $codePoint < 0x010000:
return pack('C*', (($codePoint & 0xF000) >> 12) | 0xE0, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80);
case $codePoint < 0x110000:
return pack('C*', (($codePoint & 0x1C0000) >> 18) | 0xF0, (($codePoint & 0x03F000) >> 12) | 0x80, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80);
}
return false;
}
private function isDnsLabelChar($charCode)
{
return ($charCode >= 0x61 && $charCode <= 0x7A) // lower-case letter
|| ($charCode >= 0x30 && $charCode <= 0x39) // digit
|| $charCode === 0x2D // -
|| ($charCode >= 0x41 && $charCode <= 0x5A); // upper-case letter;
}
private function isPrintableLatin1Char($charCode)
{
return $charCode >= 0xA0;
}
private function adaptBias($delta, $numPoints, $first)
{
$delta = $first ? $delta / self::DAMP : $delta / 2;
$delta += $delta / $numPoints;
$div = self::BASE - self::T_MIN;
$end = ($div * self::T_MAX) / 2;
for ($k = 0; $delta > $end; $k += self::BASE) {
$delta = (int)($delta / $div);
}
return $k + (($div + 1) * $delta) / ($delta + self::SKEW);
}
private function decodeDigit($digits, $index)
{
if (isset($digits[$index])) {
$codePoint = ord($digits[$index]);
if ($codePoint >= 0x61 && $codePoint <= 0x7A) {
return $codePoint - 97;
} else if ($codePoint >= 0x30 && $codePoint <= 0x39) {
return $codePoint - 22;
}
}
return false;
}
private function encodeDigit($digit)
{
if ($digit <= 25) {
return $digit + 97;
} else if ($digit <= 35) {
return $digit + 22;
}
return false;
}
private function decodeLabel($input)
{
if (substr($input, 0, 4) !== 'xn--') {
return $input;
}
$input = substr($input, 4);
if (false !== $nonBasicCharsStart = strrpos($input, '-')) {
$output = str_split(substr($input, 0, $nonBasicCharsStart), 1);
$nonBasicChars = substr($input, $nonBasicCharsStart + 1);
} else {
$output = [];
$nonBasicChars = $input;
}
$n = self::INITIAL_N;
$bias = self::INITIAL_BIAS;
$c = count($output) + 1;
for ($i = $j = 0, $l = strlen($nonBasicChars); $j < $l; $i++) {
$oldi = $i;
$w = 1;
for ($k = self::BASE;; $k+= self::BASE) {
if (false === $digit = $this->decodeDigit($nonBasicChars, $j++)) {
return false;
}
$i += $digit * $w;
if ($k <= $bias) {
$t = self::T_MIN;
} else if ($k >= $bias + self::T_MAX) {
$t = self::T_MAX;
} else {
$t = $k - $bias;
}
if ($digit < $t) {
break;
}
$w *= (int) (self::BASE - $t);
}
$bias = $this->adaptBias($i - $oldi, $c, $oldi === 0);
$n += (int)($i / $c);
$i %= $c++;
array_splice($output, $i, 0, [$this->encodeUtf8CodePoint($n)]);
}
return implode('', $output);
}
public function decode($input)
{
$output = [];
foreach (explode('.', strtolower($input)) as $label) {
if (false === $label = $this->decodeLabel($label)) {
return false;
}
$output[] = $label;
}
return implode('.', $output);
}
private function getEncodingParts($input, &$output = null, &$nonBasicChars = null)
{
$isUtf8 = true;
$output = [];
$nonBasicChars = new LinkedList;
for ($i = $p = 0, $l = strlen($input); $i < $l; $p++) {
$charCode = ord($input[$i]);
if ($charCode & 0x80) {
if ($isUtf8) {
if ($len = $this->decodeUtf8Character($input, $i, $codePoint)) {
// undecoded data is stored for UTF-8 chars to facilitate conversion to latin1 if necessary
$nonBasicChars->append(new LinkedListBucket($p, $codePoint, substr($input, $i, $len), $len));
$i += $len;
} else {
// not a valid UTF-8 code point, convert $nonBasicChars to latin1 representation
if (!$this->isPrintableLatin1Char($charCode)) {
return false;
}
$isUtf8 = false;
if ($nonBasicChars->length > 0) {
$offset = 0;
$current = $nonBasicChars->first;
do {
$base = $current->pos;
$current->pos += $offset;
$current->codePoint = ord($current->raw[0]);
for ($k = 1; $k < $current->rawLen; $k++) {
$nonBasicChars->insert($current, new LinkedListBucket($base + ++$offset, ord($current->raw[$k])));
}
} while($current = $current->next);
}
$nonBasicChars->append(new LinkedListBucket($i++, $charCode));
}
} else if ($this->isPrintableLatin1Char($charCode)) {
$nonBasicChars->append(new LinkedListBucket($i++, $charCode));
} else {
return false;
}
} else if ($this->isDnsLabelChar($charCode)) {
$output[] = $input[$i++];
} else {
return false;
}
}
return true;
}
private function encodeLabel($input)
{
/** @var LinkedList $nonBasicChars */
if (!$this->getEncodingParts($input, $output, $nonBasicChars)) {
return false;
}
if ($nonBasicChars->length === 0) {
return $input;
}
$n = self::INITIAL_N;
$delta = 0;
$bias = self::INITIAL_BIAS;
$h = $b = count($output);
if ($b > 0) {
$output[] = '-';
}
$current = $nonBasicChars->first;
for ($l = $h + $nonBasicChars->length; $h < $l;) {
$m = $nonBasicChars->min;
$delta += ($m - $n) * ($h + 1);
$n = $m;
$i = 0;
while ($i < $l && $current) {
$c = $i === $current->pos ? $current->codePoint : ord($output[$i++]);
if ($c < $n) {
$delta++;
}
if ($c === $n) {
$q = $delta;
for ($k = self::BASE;; $k+= self::BASE) {
if ($k <= $bias) {
$t = self::T_MIN;
} else if ($k >= $bias + self::T_MAX) {
$t = self::T_MAX;
} else {
$t = $k - $bias;
}
if ($q < $t) {
break;
}
$output[] = chr($this->encodeDigit($t + (($q - $t) % self::BASE - $t)));
$q = ($q - $t) / (self::BASE - $t);
}
$output[] = chr($this->encodeDigit($q));
$bias = $this->adaptBias($delta, $h + 1, $h === $b);
$delta = 0;
$h++;
}
}
$delta++;
$n++;
}
return 'xn--' . implode('-', $output);
}
public function encode($input)
{
$output = [];
foreach (explode('.', strtolower($input)) as $label) {
if (false === $label = $this->encodeLabel($label)) {
return false;
}
$output[] = $label;
}
return implode('.', $output);
}
}
$punycode = new Punycode;
$input = "www.xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n.com";
$decoded = $punycode->decode($input);
$encoded = $punycode->encode($decoded);
echo "Input: ", $input, "\n",
"Decoded: ", $decoded, "\n",
"Encoded: ", $encoded, "\n";
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).
Version System time (s) User time (s) Memory (MiB) 8.3.6 0.014 0.007 18.68 8.3.5 0.014 0.007 22.11 8.3.4 0.004 0.011 18.84 8.3.3 0.009 0.006 19.22 8.3.2 0.008 0.000 20.29 8.3.1 0.008 0.000 21.96 8.3.0 0.008 0.000 22.45 8.2.18 0.004 0.012 16.50 8.2.17 0.006 0.012 22.96 8.2.16 0.010 0.010 19.33 8.2.15 0.004 0.004 24.18 8.2.14 0.004 0.004 24.66 8.2.13 0.007 0.011 26.16 8.2.12 0.005 0.003 19.66 8.2.11 0.003 0.006 22.02 8.2.10 0.004 0.012 18.34 8.2.9 0.008 0.000 19.39 8.2.8 0.000 0.008 18.29 8.2.7 0.003 0.006 17.84 8.2.6 0.003 0.005 18.18 8.2.5 0.000 0.009 18.07 8.2.4 0.003 0.006 18.46 8.2.3 0.008 0.000 18.21 8.2.2 0.008 0.000 17.80 8.2.1 0.003 0.005 17.86 8.2.0 0.009 0.003 17.91 8.1.28 0.012 0.006 25.92 8.1.27 0.003 0.006 18.70 8.1.26 0.005 0.003 26.35 8.1.25 0.008 0.000 28.09 8.1.24 0.003 0.006 23.96 8.1.23 0.011 0.000 19.24 8.1.22 0.003 0.005 17.91 8.1.21 0.004 0.004 18.77 8.1.20 0.006 0.006 17.48 8.1.19 0.004 0.004 17.65 8.1.18 0.004 0.004 20.66 8.1.17 0.008 0.000 18.59 8.1.16 0.004 0.004 22.30 8.1.15 0.005 0.003 18.84 8.1.14 0.009 0.000 17.56 8.1.13 0.000 0.008 17.89 8.1.12 0.007 0.000 17.68 8.1.11 0.003 0.005 17.49 8.1.10 0.004 0.004 17.66 8.1.9 0.005 0.005 17.63 8.1.8 0.003 0.005 17.66 8.1.7 0.000 0.007 17.50 8.1.6 0.004 0.004 17.79 8.1.5 0.004 0.004 17.68 8.1.4 0.004 0.004 17.59 8.1.3 0.003 0.005 17.73 8.1.2 0.003 0.006 17.80 8.1.1 0.004 0.004 17.75 8.1.0 0.003 0.007 17.73 8.0.30 0.003 0.005 18.77 8.0.29 0.004 0.004 17.30 8.0.28 0.004 0.004 18.58 8.0.27 0.004 0.004 17.40 8.0.26 0.004 0.004 16.95 8.0.25 0.004 0.004 17.23 8.0.24 0.004 0.004 17.11 8.0.23 0.000 0.007 17.14 8.0.22 0.004 0.004 17.01 8.0.21 0.003 0.003 17.07 8.0.20 0.000 0.008 17.04 8.0.19 0.005 0.003 17.18 8.0.18 0.000 0.008 17.02 8.0.17 0.000 0.008 17.16 8.0.16 0.004 0.004 17.09 8.0.15 0.004 0.004 17.05 8.0.14 0.000 0.008 17.08 8.0.13 0.003 0.003 13.57 8.0.12 0.000 0.008 17.08 8.0.11 0.003 0.006 17.11 8.0.10 0.006 0.003 16.90 8.0.9 0.008 0.000 16.93 8.0.8 0.000 0.015 17.03 8.0.7 0.000 0.008 17.17 8.0.6 0.000 0.008 17.05 8.0.5 0.004 0.004 17.21 8.0.3 0.011 0.008 17.21 8.0.2 0.012 0.010 17.40 8.0.1 0.009 0.000 17.19 8.0.0 0.011 0.012 16.93 7.4.33 0.000 2.011 15.10 7.4.32 0.003 2.001 16.53 7.4.30 0.000 2.003 16.53 7.4.29 0.003 1.999 16.67 7.4.28 0.007 1.995 16.57 7.4.27 0.003 1.997 16.68 7.4.26 0.000 2.003 16.41 7.4.25 0.000 2.003 16.64 7.4.24 0.002 2.001 16.60 7.4.23 0.003 1.998 16.63 7.4.22 0.010 1.989 16.56 7.4.21 0.016 1.985 16.63 7.4.20 0.003 2.001 16.74 7.4.19 0.007 1.996 16.43 7.4.16 0.027 1.984 16.51 7.4.15 0.010 1.987 17.40 7.4.14 0.033 1.971 17.86 7.4.13 0.013 1.988 16.61 7.4.12 0.033 1.963 16.58 7.4.11 0.010 2.444 16.82 7.4.10 0.013 2.450 16.46 7.4.9 0.026 2.422 16.71 7.4.8 0.010 2.448 19.39 7.4.7 0.016 2.444 16.60 7.4.6 0.018 1.519 16.69 7.4.5 0.007 2.492 16.70 7.4.4 0.010 2.485 22.77 7.4.3 0.061 2.235 16.60 7.3.33 0.003 1.997 13.60 7.3.32 0.000 2.003 13.57 7.3.31 0.000 2.004 16.45 7.3.30 0.007 1.997 16.43 7.3.29 0.016 1.990 16.42 7.3.28 0.010 1.991 16.41 7.3.27 0.010 1.989 17.40 7.3.26 0.042 1.927 16.41 7.3.25 0.023 1.977 16.43 7.3.24 0.016 1.959 16.50 7.3.23 0.016 2.446 16.67 7.3.21 0.017 2.458 16.37 7.3.20 0.013 2.456 19.39 7.3.19 0.023 2.440 16.51 7.3.18 0.007 2.450 16.55 7.3.17 0.013 2.441 16.45 7.3.16 0.010 2.455 16.42 7.2.33 0.013 2.448 16.50 7.2.32 0.048 2.323 16.65 7.2.31 0.010 2.435 16.69 7.2.30 0.007 2.465 16.45 7.2.29 0.016 2.438 16.88 5.4.25 0.030 2.403 19.20 5.4.24 0.013 2.407 19.15 5.4.23 0.023 2.410 19.18 5.4.22 0.013 2.457 19.30 5.4.21 0.017 2.370 18.99 5.4.20 0.027 2.403 19.11 5.4.19 0.023 2.393 19.03 5.4.18 0.023 2.430 19.13 5.4.17 0.020 2.413 18.96 5.4.16 0.013 2.450 19.09 5.4.15 0.030 2.383 19.11 5.4.14 0.027 2.383 16.43 5.4.13 0.013 2.440 16.50 5.4.12 0.030 2.383 16.45 5.4.11 0.043 2.383 16.64 5.4.10 0.017 2.360 16.38 5.4.9 0.030 1.920 16.34 5.4.8 0.023 1.917 16.40 5.4.7 0.007 1.973 16.51 5.4.6 0.047 1.923 16.54 5.4.5 0.053 2.023 16.54 5.4.4 0.017 2.180 16.40 5.4.3 0.077 2.327 16.55 5.4.2 0.017 2.347 16.57 5.4.1 0.033 2.347 16.57 5.4.0 0.017 2.407 15.90 5.3.28 0.187 0.040 14.56 5.3.27 0.200 0.047 14.91 5.3.26 0.193 0.040 14.81 5.3.25 0.207 0.040 14.63 5.3.24 0.203 0.043 14.74 5.3.23 0.207 0.047 14.65 5.3.22 0.203 0.043 14.55 5.3.21 0.193 0.043 14.62 5.3.20 0.200 0.047 14.61 5.3.19 0.197 0.033 14.62 5.3.18 0.210 0.033 14.62 5.3.17 0.183 0.037 14.70 5.3.16 0.190 0.033 14.63 5.3.15 0.197 0.033 14.70 5.3.14 0.213 0.043 14.59 5.3.13 0.063 0.040 14.57 5.3.12 0.003 0.040 14.59 5.3.11 0.003 0.037 14.58 5.3.10 0.007 0.057 14.25 5.3.9 0.187 0.037 14.17 5.3.8 0.217 0.040 14.22 5.3.7 0.230 0.043 14.23 5.3.6 0.223 0.047 13.98 5.3.5 0.003 0.040 14.01 5.3.4 0.007 0.063 13.94 5.3.3 0.090 0.033 13.95 5.3.2 0.223 0.037 14.00 5.3.1 0.207 0.030 13.69 5.3.0 0.203 0.030 13.81
preferences:dark mode live preview
29.99 ms | 401 KiB | 5 Q