]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - vendor/wikimedia/avro/lib/avro/gmp.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / wikimedia / avro / lib / avro / gmp.php
diff --git a/vendor/wikimedia/avro/lib/avro/gmp.php b/vendor/wikimedia/avro/lib/avro/gmp.php
new file mode 100644 (file)
index 0000000..3d41d03
--- /dev/null
@@ -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);
+  }
+
+}