Coverage Report

Created: 2025-03-09 06:52

/src/gmp-6.2.1/mpz/ior.c
Line
Count
Source (jump to first uncovered line)
1
/* mpz_ior -- Logical inclusive or.
2
3
Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013,
4
2015-2018 Free Software 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-impl.h"
33
34
void
35
mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
36
125
{
37
125
  mp_srcptr op1_ptr, op2_ptr;
38
125
  mp_size_t op1_size, op2_size;
39
125
  mp_ptr res_ptr;
40
125
  mp_size_t res_size;
41
125
  mp_size_t i;
42
43
125
  op1_size = SIZ(op1);
44
125
  op2_size = SIZ(op2);
45
46
125
  if (op1_size < op2_size)
47
75
    {
48
75
      MPZ_SRCPTR_SWAP (op1, op2);
49
75
      MP_SIZE_T_SWAP (op1_size, op2_size);
50
75
    }
51
52
125
  op1_ptr = PTR(op1);
53
125
  res_ptr = PTR(res);
54
55
125
  if (op2_size >= 0)
56
41
    {
57
41
      if (res_ptr != op1_ptr)
58
33
  {
59
33
    res_ptr = MPZ_REALLOC (res, op1_size);
60
    /* No overlapping possible: op1_ptr = PTR(op1); */
61
33
    MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
62
33
        op1_size - op2_size);
63
33
  }
64
41
      if (LIKELY (op2_size != 0))
65
26
  mpn_ior_n (res_ptr, op1_ptr, PTR(op2), op2_size);
66
67
41
      SIZ(res) = op1_size;
68
41
    }
69
84
  else
70
84
    {
71
84
      mp_ptr opx;
72
84
      TMP_DECL;
73
74
84
      TMP_MARK;
75
84
      if (op1_size < 0)
76
44
  {
77
44
    mp_ptr opy;
78
79
    /* Both operands are negative, so will be the result.
80
       -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
81
       = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
82
       = ((OP1 - 1) & (OP2 - 1)) + 1      */
83
84
44
    res_size = -op1_size;
85
86
    /* Possible optimization: Decrease mpn_sub precision,
87
       as we won't use the entire res of both.  */
88
44
    TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
89
44
    mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
90
44
    op1_ptr = opx;
91
92
44
    mpn_sub_1 (opy, PTR(op2), res_size, (mp_limb_t) 1);
93
44
    op2_ptr = opy;
94
95
    /* First loop finds the size of the result.  */
96
147
    for (i = res_size; --i >= 0;)
97
145
      if ((op1_ptr[i] & op2_ptr[i]) != 0)
98
42
        break;
99
44
    res_size = i + 1;
100
101
44
    res_ptr = MPZ_NEWALLOC (res, res_size + 1);
102
103
44
    if (res_size != 0)
104
42
      {
105
        /* Second loop computes the real result.  */
106
42
        mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
107
108
42
        res_ptr[res_size] = 0;
109
42
        MPN_INCR_U (res_ptr, res_size + 1, 1);
110
42
        res_size += res_ptr[res_size];
111
42
      }
112
2
    else
113
2
      {
114
2
        res_ptr[0] = 1;
115
2
        res_size = 1;
116
2
      }
117
118
44
    SIZ(res) = -res_size;
119
44
  }
120
40
      else
121
40
  {
122
40
    mp_limb_t cy;
123
40
    mp_size_t count;
124
125
    /* Operand 2 negative, so will be the result.
126
       -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
127
       = ~(OP1 | ~(OP2 - 1)) + 1 =
128
       = (~OP1 & (OP2 - 1)) + 1      */
129
130
40
    op2_size = -op2_size;
131
132
40
    res_ptr = MPZ_REALLOC (res, op2_size);
133
40
    op1_ptr = PTR(op1);
134
135
40
    opx = TMP_ALLOC_LIMBS (op2_size);
136
40
    mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
137
40
    op2_ptr = opx;
138
40
    op2_size -= op2_ptr[op2_size - 1] == 0;
139
140
40
    if (op1_size >= op2_size)
141
10
      {
142
        /* We can just ignore the part of OP1 that stretches above OP2,
143
     because the result limbs are zero there.  */
144
145
        /* First loop finds the size of the result.  */
146
39
        for (i = op2_size; --i >= 0;)
147
39
    if ((~op1_ptr[i] & op2_ptr[i]) != 0)
148
10
      break;
149
10
        res_size = i + 1;
150
10
        count = res_size;
151
10
      }
152
30
    else
153
30
      {
154
30
        res_size = op2_size;
155
156
        /* Copy the part of OP2 that stretches above OP1, to RES.  */
157
30
        MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
158
30
        count = op1_size;
159
30
      }
160
161
40
    if (res_size != 0)
162
40
      {
163
        /* Second loop computes the real result.  */
164
40
        if (LIKELY (count != 0))
165
18
    mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
166
167
40
        cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
168
40
        if (cy)
169
0
    {
170
0
      res_ptr[res_size] = cy;
171
0
      ++res_size;
172
0
    }
173
40
      }
174
0
    else
175
0
      {
176
0
        res_ptr[0] = 1;
177
0
        res_size = 1;
178
0
      }
179
180
40
    SIZ(res) = -res_size;
181
40
  }
182
84
      TMP_FREE;
183
84
    }
184
125
}