summaryrefslogtreecommitdiff
path: root/vendor/wikimedia/avro/lib/avro/gmp.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/wikimedia/avro/lib/avro/gmp.php')
-rw-r--r--vendor/wikimedia/avro/lib/avro/gmp.php222
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);
+ }
+
+}