diff options
Diffstat (limited to 'vendor/wikimedia/avro/lib/avro/gmp.php')
-rw-r--r-- | vendor/wikimedia/avro/lib/avro/gmp.php | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/vendor/wikimedia/avro/lib/avro/gmp.php b/vendor/wikimedia/avro/lib/avro/gmp.php new file mode 100644 index 00000000..3d41d034 --- /dev/null +++ b/vendor/wikimedia/avro/lib/avro/gmp.php @@ -0,0 +1,222 @@ +<?php +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @package Avro + */ + +/** + * Methods for handling 64-bit operations using the GMP extension. + * + * This is a naive and hackish implementation that is intended + * to work well enough to support Avro. It has not been tested + * beyond what's needed to decode and encode long values. + * + * @package Avro + */ +class AvroGMP { + + /** + * @var resource memoized GMP resource for zero + */ + private static $gmp_0; + + /** + * @returns resource GMP resource for zero + */ + private static function gmp_0() + { + if (!isset(self::$gmp_0)) + self::$gmp_0 = gmp_init('0'); + return self::$gmp_0; + } + + /** + * @var resource memoized GMP resource for one (1) + */ + private static $gmp_1; + + /** + * @returns resource GMP resource for one (1) + */ + private static function gmp_1() + { + if (!isset(self::$gmp_1)) + self::$gmp_1 = gmp_init('1'); + return self::$gmp_1; + } + + /** + * @var resource memoized GMP resource for two (2) + */ + private static $gmp_2; + + /** + * @returns resource GMP resource for two (2) + */ + private static function gmp_2() + { + if (!isset(self::$gmp_2)) + self::$gmp_2 = gmp_init('2'); + return self::$gmp_2; + } + + /** + * @var resource memoized GMP resource for 0x7f + */ + private static $gmp_0x7f; + + /** + * @returns resource GMP resource for 0x7f + */ + private static function gmp_0x7f() + { + if (!isset(self::$gmp_0x7f)) + self::$gmp_0x7f = gmp_init('0x7f'); + return self::$gmp_0x7f; + } + + /** + * @var resource memoized GMP resource for 64-bit ~0x7f + */ + private static $gmp_n0x7f; + + /** + * @returns resource GMP resource for 64-bit ~0x7f + */ + private static function gmp_n0x7f() + { + if (!isset(self::$gmp_n0x7f)) + self::$gmp_n0x7f = gmp_init('0xffffffffffffff80'); + return self::$gmp_n0x7f; + } + + /** + * @var resource memoized GMP resource for 64-bits of 1 + */ + private static $gmp_0xfs; + + /** + * @returns resource GMP resource for 64-bits of 1 + */ + private static function gmp_0xfs() + { + if (!isset(self::$gmp_0xfs)) + self::$gmp_0xfs = gmp_init('0xffffffffffffffff'); + return self::$gmp_0xfs; + } + + /** + * @param GMP resource + * @returns GMP resource 64-bit two's complement of input. + */ + static function gmp_twos_complement($g) + { + return gmp_neg(gmp_sub(gmp_pow(self::gmp_2(), 64), $g)); + } + + /** + * @interal Only works up to shift 63 (doesn't wrap bits around). + * @param resource|int|string $g + * @param int $shift number of bits to shift left + * @returns resource $g shifted left + */ + static function shift_left($g, $shift) + { + if (0 == $shift) + return $g; + + if (0 > gmp_sign($g)) + $g = self::gmp_twos_complement($g); + + $m = gmp_mul($g, gmp_pow(self::gmp_2(), $shift)); + $m = gmp_and($m, self::gmp_0xfs()); + if (gmp_testbit($m, 63)) + $m = gmp_neg(gmp_add(gmp_and(gmp_com($m), self::gmp_0xfs()), + self::gmp_1())); + return $m; + } + + /** + * Arithmetic right shift + * @param resource|int|string $g + * @param int $shift number of bits to shift right + * @returns resource $g shifted right $shift bits + */ + static function shift_right($g, $shift) + { + if (0 == $shift) + return $g; + + if (0 <= gmp_sign($g)) + $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift)); + else // negative + { + $g = gmp_and($g, self::gmp_0xfs()); + $m = gmp_div($g, gmp_pow(self::gmp_2(), $shift)); + $m = gmp_and($m, self::gmp_0xfs()); + for ($i = 63; $i >= (63 - $shift); $i--) + gmp_setbit($m, $i); + + $m = gmp_neg(gmp_add(gmp_and(gmp_com($m), self::gmp_0xfs()), + self::gmp_1())); + } + + return $m; + } + + /** + * @param int|str $n integer (or string representation of integer) to encode + * @return string $bytes of the long $n encoded per the Avro spec + */ + static function encode_long($n) + { + $g = gmp_init($n); + $g = gmp_xor(self::shift_left($g, 1), + self::shift_right($g, 63)); + $bytes = ''; + while (0 != gmp_cmp(self::gmp_0(), gmp_and($g, self::gmp_n0x7f()))) + { + $bytes .= chr(gmp_intval(gmp_and($g, self::gmp_0x7f())) | 0x80); + $g = self::shift_right($g, 7); + } + $bytes .= chr(gmp_intval($g)); + return $bytes; + } + + /** + * @param int[] $bytes array of ascii codes of bytes to decode + * @return string represenation of decoded long. + */ + static function decode_long_from_array($bytes) + { + $b = array_shift($bytes); + $g = gmp_init($b & 0x7f); + $shift = 7; + while (0 != ($b & 0x80)) + { + $b = array_shift($bytes); + $g = gmp_or($g, self::shift_left(($b & 0x7f), $shift)); + $shift += 7; + } + $val = gmp_xor(self::shift_right($g, 1), gmp_neg(gmp_and($g, 1))); + return gmp_strval($val); + } + +} |