Blame mpz/ior.c

Packit 5c3484
/* mpz_ior -- Logical inclusive or.
Packit 5c3484
Packit 5c3484
Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013 Free
Packit 5c3484
Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
Packit 5c3484
{
Packit 5c3484
  mp_srcptr op1_ptr, op2_ptr;
Packit 5c3484
  mp_size_t op1_size, op2_size;
Packit 5c3484
  mp_ptr res_ptr;
Packit 5c3484
  mp_size_t res_size;
Packit 5c3484
  mp_size_t i;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
  op1_size = SIZ(op1);
Packit 5c3484
  op2_size = SIZ(op2);
Packit 5c3484
Packit 5c3484
  op1_ptr = PTR(op1);
Packit 5c3484
  op2_ptr = PTR(op2);
Packit 5c3484
  res_ptr = PTR(res);
Packit 5c3484
Packit 5c3484
  if (op1_size >= 0)
Packit 5c3484
    {
Packit 5c3484
      if (op2_size >= 0)
Packit 5c3484
	{
Packit 5c3484
	  if (op1_size >= op2_size)
Packit 5c3484
	    {
Packit 5c3484
	      if (ALLOC(res) < op1_size)
Packit 5c3484
		{
Packit 5c3484
		  res_ptr = MPZ_REALLOC (res, op1_size);
Packit 5c3484
		  /* No overlapping possible: op1_ptr = PTR(op1); */
Packit 5c3484
		  op2_ptr = PTR(op2);
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      if (res_ptr != op1_ptr)
Packit 5c3484
		MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
Packit 5c3484
			  op1_size - op2_size);
Packit 5c3484
	      if (LIKELY (op2_size != 0))
Packit 5c3484
		mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op2_size);
Packit 5c3484
	      res_size = op1_size;
Packit 5c3484
	    }
Packit 5c3484
	  else
Packit 5c3484
	    {
Packit 5c3484
	      if (ALLOC(res) < op2_size)
Packit 5c3484
		{
Packit 5c3484
		  res_ptr = MPZ_REALLOC (res, op2_size);
Packit 5c3484
		  op1_ptr = PTR(op1);
Packit 5c3484
		  /* No overlapping possible: op2_ptr = PTR(op2); */
Packit 5c3484
		}
Packit 5c3484
Packit 5c3484
	      if (res_ptr != op2_ptr)
Packit 5c3484
		MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
Packit 5c3484
			  op2_size - op1_size);
Packit 5c3484
	      if (LIKELY (op1_size != 0))
Packit 5c3484
		mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
Packit 5c3484
	      res_size = op2_size;
Packit 5c3484
	    }
Packit 5c3484
Packit 5c3484
	  SIZ(res) = res_size;
Packit 5c3484
	  return;
Packit 5c3484
	}
Packit 5c3484
      else /* op2_size < 0 */
Packit 5c3484
	{
Packit 5c3484
	  /* Fall through to the code at the end of the function.  */
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      if (op2_size < 0)
Packit 5c3484
	{
Packit 5c3484
	  mp_ptr opx, opy;
Packit 5c3484
Packit 5c3484
	  /* Both operands are negative, so will be the result.
Packit 5c3484
	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
Packit 5c3484
	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
Packit 5c3484
	     = ((OP1 - 1) & (OP2 - 1)) + 1      */
Packit 5c3484
Packit 5c3484
	  op1_size = -op1_size;
Packit 5c3484
	  op2_size = -op2_size;
Packit 5c3484
Packit 5c3484
	  res_size = MIN (op1_size, op2_size);
Packit 5c3484
Packit 5c3484
	  /* Possible optimization: Decrease mpn_sub precision,
Packit 5c3484
	     as we won't use the entire res of both.  */
Packit 5c3484
	  TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
Packit 5c3484
	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
Packit 5c3484
	  op1_ptr = opx;
Packit 5c3484
Packit 5c3484
	  mpn_sub_1 (opy, op2_ptr, res_size, (mp_limb_t) 1);
Packit 5c3484
	  op2_ptr = opy;
Packit 5c3484
Packit 5c3484
	  /* First loop finds the size of the result.  */
Packit 5c3484
	  for (i = res_size - 1; i >= 0; i--)
Packit 5c3484
	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
Packit 5c3484
	      break;
Packit 5c3484
	  res_size = i + 1;
Packit 5c3484
Packit 5c3484
	  if (res_size != 0)
Packit 5c3484
	    {
Packit 5c3484
	      res_ptr = MPZ_NEWALLOC (res, res_size + 1);
Packit 5c3484
Packit 5c3484
	      /* Second loop computes the real result.  */
Packit 5c3484
	      mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
Packit 5c3484
Packit 5c3484
	      res_ptr[res_size] = 0;
Packit 5c3484
	      MPN_INCR_U (res_ptr, res_size + 1, 1);
Packit 5c3484
	      res_size += res_ptr[res_size];
Packit 5c3484
	    }
Packit 5c3484
	  else
Packit 5c3484
	    {
Packit 5c3484
	      res_ptr[0] = 1;
Packit 5c3484
	      res_size = 1;
Packit 5c3484
	    }
Packit 5c3484
Packit 5c3484
	  SIZ(res) = -res_size;
Packit 5c3484
	  TMP_FREE;
Packit 5c3484
	  return;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  /* We should compute -OP1 | OP2.  Swap OP1 and OP2 and fall
Packit 5c3484
	     through to the code that handles OP1 | -OP2.  */
Packit 5c3484
	  MPZ_SRCPTR_SWAP (op1, op2);
Packit 5c3484
	  MPN_SRCPTR_SWAP (op1_ptr,op1_size, op2_ptr,op2_size);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  {
Packit 5c3484
    mp_ptr opx;
Packit 5c3484
    mp_limb_t cy;
Packit 5c3484
    mp_size_t res_alloc;
Packit 5c3484
    mp_size_t count;
Packit 5c3484
Packit 5c3484
    /* Operand 2 negative, so will be the result.
Packit 5c3484
       -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
Packit 5c3484
       = ~(OP1 | ~(OP2 - 1)) + 1 =
Packit 5c3484
       = (~OP1 & (OP2 - 1)) + 1      */
Packit 5c3484
Packit 5c3484
    op2_size = -op2_size;
Packit 5c3484
Packit 5c3484
    res_alloc = op2_size;
Packit 5c3484
Packit 5c3484
    opx = TMP_ALLOC_LIMBS (op2_size);
Packit 5c3484
    mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
Packit 5c3484
    op2_ptr = opx;
Packit 5c3484
    op2_size -= op2_ptr[op2_size - 1] == 0;
Packit 5c3484
Packit 5c3484
    if (ALLOC(res) < res_alloc)
Packit 5c3484
      {
Packit 5c3484
	_mpz_realloc (res, res_alloc);
Packit 5c3484
	op1_ptr = PTR(op1);
Packit 5c3484
	/* op2_ptr points to temporary space.  */
Packit 5c3484
	res_ptr = PTR(res);
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    if (op1_size >= op2_size)
Packit 5c3484
      {
Packit 5c3484
	/* We can just ignore the part of OP1 that stretches above OP2,
Packit 5c3484
	   because the result limbs are zero there.  */
Packit 5c3484
Packit 5c3484
	/* First loop finds the size of the result.  */
Packit 5c3484
	for (i = op2_size - 1; i >= 0; i--)
Packit 5c3484
	  if ((~op1_ptr[i] & op2_ptr[i]) != 0)
Packit 5c3484
	    break;
Packit 5c3484
	res_size = i + 1;
Packit 5c3484
	count = res_size;
Packit 5c3484
      }
Packit 5c3484
    else
Packit 5c3484
      {
Packit 5c3484
	res_size = op2_size;
Packit 5c3484
Packit 5c3484
	/* Copy the part of OP2 that stretches above OP1, to RES.  */
Packit 5c3484
	MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
Packit 5c3484
	count = op1_size;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    if (res_size != 0)
Packit 5c3484
      {
Packit 5c3484
	/* Second loop computes the real result.  */
Packit 5c3484
	if (LIKELY (count != 0))
Packit 5c3484
	  mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
Packit 5c3484
Packit 5c3484
	cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
Packit 5c3484
	if (cy)
Packit 5c3484
	  {
Packit 5c3484
	    res_ptr[res_size] = cy;
Packit 5c3484
	    res_size++;
Packit 5c3484
	  }
Packit 5c3484
      }
Packit 5c3484
    else
Packit 5c3484
      {
Packit 5c3484
	res_ptr[0] = 1;
Packit 5c3484
	res_size = 1;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    SIZ(res) = -res_size;
Packit 5c3484
  }
Packit 5c3484
  TMP_FREE;
Packit 5c3484
}