github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpz/xor.c (about)

     1  /* mpz_xor -- Logical xor.
     2  
     3  Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012 Free Software
     4  Foundation, Inc.
     5  
     6  This file is part of the GNU MP Library.
     7  
     8  The GNU MP Library is free software; you can redistribute it and/or modify
     9  it under the terms of either:
    10  
    11    * the GNU Lesser General Public License as published by the Free
    12      Software Foundation; either version 3 of the License, or (at your
    13      option) any later version.
    14  
    15  or
    16  
    17    * the GNU General Public License as published by the Free Software
    18      Foundation; either version 2 of the License, or (at your option) any
    19      later version.
    20  
    21  or both in parallel, as here.
    22  
    23  The GNU MP Library is distributed in the hope that it will be useful, but
    24  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    25  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    26  for more details.
    27  
    28  You should have received copies of the GNU General Public License and the
    29  GNU Lesser General Public License along with the GNU MP Library.  If not,
    30  see https://www.gnu.org/licenses/.  */
    31  
    32  #include "gmp.h"
    33  #include "gmp-impl.h"
    34  
    35  void
    36  mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
    37  {
    38    mp_srcptr op1_ptr, op2_ptr;
    39    mp_size_t op1_size, op2_size;
    40    mp_ptr res_ptr;
    41    mp_size_t res_size, res_alloc;
    42    TMP_DECL;
    43  
    44    TMP_MARK;
    45    op1_size = SIZ(op1);
    46    op2_size = SIZ(op2);
    47  
    48    op1_ptr = PTR(op1);
    49    op2_ptr = PTR(op2);
    50    res_ptr = PTR(res);
    51  
    52    if (op1_size >= 0)
    53      {
    54        if (op2_size >= 0)
    55  	{
    56  	  if (op1_size >= op2_size)
    57  	    {
    58  	      if (ALLOC(res) < op1_size)
    59  		{
    60  		  _mpz_realloc (res, op1_size);
    61  		  /* No overlapping possible: op1_ptr = PTR(op1); */
    62  		  op2_ptr = PTR(op2);
    63  		  res_ptr = PTR(res);
    64  		}
    65  
    66  	      if (res_ptr != op1_ptr)
    67  		MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
    68  			  op1_size - op2_size);
    69  	      if (LIKELY (op2_size != 0))
    70  		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
    71  	      res_size = op1_size;
    72  	    }
    73  	  else
    74  	    {
    75  	      if (ALLOC(res) < op2_size)
    76  		{
    77  		  _mpz_realloc (res, op2_size);
    78  		  op1_ptr = PTR(op1);
    79  		  /* No overlapping possible: op2_ptr = PTR(op2); */
    80  		  res_ptr = PTR(res);
    81  		}
    82  
    83  	      if (res_ptr != op2_ptr)
    84  		MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
    85  			  op2_size - op1_size);
    86  	      if (LIKELY (op1_size != 0))
    87  		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
    88  	      res_size = op2_size;
    89  	    }
    90  
    91  	  MPN_NORMALIZE (res_ptr, res_size);
    92  	  SIZ(res) = res_size;
    93  	  return;
    94  	}
    95        else /* op2_size < 0 */
    96  	{
    97  	  /* Fall through to the code at the end of the function.  */
    98  	}
    99      }
   100    else
   101      {
   102        if (op2_size < 0)
   103  	{
   104  	  mp_ptr opx, opy;
   105  
   106  	  /* Both operands are negative, the result will be positive.
   107  	      (-OP1) ^ (-OP2) =
   108  	     = ~(OP1 - 1) ^ ~(OP2 - 1) =
   109  	     = (OP1 - 1) ^ (OP2 - 1)  */
   110  
   111  	  op1_size = -op1_size;
   112  	  op2_size = -op2_size;
   113  
   114  	  /* Possible optimization: Decrease mpn_sub precision,
   115  	     as we won't use the entire res of both.  */
   116  	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
   117  	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
   118  	  op1_ptr = opx;
   119  
   120  	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
   121  	  op2_ptr = opy;
   122  
   123  	  if (op1_size > op2_size)
   124  	    MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
   125  
   126  	  res_alloc = op2_size;
   127  	  res_ptr = MPZ_REALLOC (res, res_alloc);
   128  
   129  	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
   130  		    op2_size - op1_size);
   131  	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
   132  	  res_size = op2_size;
   133  
   134  	  MPN_NORMALIZE (res_ptr, res_size);
   135  	  SIZ(res) = res_size;
   136  	  TMP_FREE;
   137  	  return;
   138  	}
   139        else
   140  	{
   141  	  /* We should compute -OP1 ^ OP2.  Swap OP1 and OP2 and fall
   142  	     through to the code that handles OP1 ^ -OP2.  */
   143  	  MPZ_SRCPTR_SWAP (op1, op2);
   144  	  MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
   145  	}
   146      }
   147  
   148    {
   149      mp_ptr opx;
   150      mp_limb_t cy;
   151  
   152      /* Operand 2 negative, so will be the result.
   153         -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
   154         = ~(OP1 ^ ~(OP2 - 1)) + 1 =
   155         = (OP1 ^ (OP2 - 1)) + 1      */
   156  
   157      op2_size = -op2_size;
   158  
   159      opx = TMP_ALLOC_LIMBS (op2_size);
   160      mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
   161      op2_ptr = opx;
   162  
   163      res_alloc = MAX (op1_size, op2_size) + 1;
   164      if (ALLOC(res) < res_alloc)
   165        {
   166  	_mpz_realloc (res, res_alloc);
   167  	op1_ptr = PTR(op1);
   168  	/* op2_ptr points to temporary space.  */
   169  	res_ptr = PTR(res);
   170        }
   171  
   172      if (op1_size > op2_size)
   173        {
   174  	MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
   175  	mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
   176  	res_size = op1_size;
   177        }
   178      else
   179        {
   180  	MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
   181  	if (LIKELY (op1_size != 0))
   182  	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
   183  	res_size = op2_size;
   184        }
   185  
   186      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
   187      res_ptr[res_size] = cy;
   188      res_size += (cy != 0);
   189  
   190      MPN_NORMALIZE (res_ptr, res_size);
   191      SIZ(res) = -res_size;
   192      TMP_FREE;
   193    }
   194  }