* Bug 16522 fixed: bitget(x,pos) and bitset(..) with pos as encoded integer
[scilab.git] / scilab / modules / elementary_functions / macros / bitset.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2019 - Samuel GOUGEON
3 //
4 // This file is hereby licensed under the terms of the GNU GPL v2.0,
5 // pursuant to article 5.3.4 of the CeCILL v.2.1.
6 // This file was originally licensed under the terms of the CeCILL v2.1,
7 // and continues to be available under such terms.
8 // For more information, see the COPYING file which you should have received
9 // along with this program.
10
11 function y = bitset(x, pos, v)
12     fname = "bitset"
13     rhs = argn(2)
14
15     // CHECKING AND FORMATTING INPUT ARGUMENTS
16     // =======================================
17     if rhs < 2 | rhs > 3 then
18         msg = _("%s: Wrong number of input arguments: %d or %d expected.\n")
19         error(msprintf(msg, fname, 2, 3))
20     end
21
22     // Check x
23     // -------
24     if x==[]
25         y = []
26         return
27     end
28     if  and(type(x)<>[1 8]) | (type(x)==1 & (~isreal(x)|or((x-floor(x))<>0))) | or(x<0)
29         msg = gettext("%s: Argument #%d: Non-negative real integers expected.\n")
30         error(msprintf(msg, fname, 1))
31     end
32
33     // Check pos
34     // ---------
35     if ~isdef("pos","l") | pos==[] then     // do nothing, keep it as is
36         y = x
37         return
38     end
39     if  (type(pos)<>1  & type(pos)<>8) |  ..
40         (type(pos)==1  & (or((pos-floor(pos))<>0) | ~isreal(pos))) | or(pos<1)
41         msg = gettext("%s: Argument #%d: integers > 0 expected.\n")
42         error(msprintf(msg, fname, 2))
43     else
44         // max value
45         icode = inttype(x)
46         select modulo(icode,10)
47         case 0  then posmax = 1024  // log2(number_properties("huge"))
48         case 1 then posmax = 8
49         case 2 then posmax = 16
50         case 4 then posmax = 32
51         case 8 then posmax = 64
52         end
53         if icode>0 & icode<10      // Signed integers
54             posmax = posmax-1      // => sign bit reserved
55         end
56         if or(pos > posmax)
57             msg = gettext("%s: Argument #%d: Integers <= %d expected.\n")
58             error(msprintf(msg, fname, 2, posmax))
59         end
60     end
61     pos = double(pos)
62
63    // Check consistency between x and pos sizes
64     sx = size(x)
65     ndx = ndims(x)
66     sp = size(pos)
67     ndp = ndims(pos)
68     sameBits = ndp<ndx | ~and(sx(1:ndx)==sp(1:ndx)) // Same bits for all x components
69     if sameBits then
70         if ~isscalar(pos) & ~isvector(pos)
71             msg = gettext("%s: Arguments #%d and #%d: Incompatible sizes.\n")
72             error(msprintf(msg, fname, 1, 2))
73         end
74         if ~isdef("v","l") | size(v,"*")==1
75             pos = unique(pos)
76             // we can't do that if an array v is provided, because then
77             // its length must match the pos one.
78         else
79             if length(pos)>posmax
80                 msg = gettext("%s: Argument #%d is longer than %d. Please check against duplicate values.\n")
81                 error(msprintf(msg, fname, 2, posmax))
82             end
83         end
84     else // ndp>=ndx & and(sx(1:ndx)==sp(1:ndx))
85         pos = matrix(pos,[sx -1])
86         // duplicate values along a range can't be removed nor easily canceled.
87         // So, no check. Never mind.
88     end
89
90     // Check v
91     // -------
92     // At the end, v must be either a vector with the pos's length (sameBits case)
93     // or an array with same sizes as pos (element-wise case)
94     if ~isdef("v","l") || v==[] then
95         v = ones(pos)
96     else
97         if  (type(v)<>1  & type(v)<>8) || or(v~=0 & v~=1)
98             msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
99             error(msprintf(msg, fname, 3, "0,1"))
100         end
101         if prod(size(v)(1:min(ndims(v),ndims(pos)))) == 1 // scalar or hypercolumn cases
102             v = v .*. ones(pos)
103         elseif prod(size(v)(1:ndims(pos))) ~= length(pos)
104             msg = gettext("%s: Arguments #%d and #%d: Incompatible sizes.\n")
105             error(msprintf(msg, fname, 2, 3))
106         end
107     end
108
109     // PROCESSING
110     // ==========
111     if sameBits then
112         nBitLayers = length(pos)
113         template = ones(x)
114     else
115         nBitLayers = size(pos,ndx+1)
116         // Extraction mask:
117         str = strcat(emptystr(1,ndx)+":,")+"iL"
118     end
119     Pos = pos
120     V = v
121     y = x
122     //
123     for iL = 1:nBitLayers
124         if sameBits
125             pos = template*Pos(iL)
126             v   = template*V(iL)
127         else
128             execstr("pos = Pos("+str+"); v = V("+str+")")
129         end
130         vZero = (v == 0)
131         vOne  = (v == 1)
132         x = y
133         if type(x)==8 then
134             mask =  2 .^ iconvert((pos-1), inttype(x))
135             y(vZero) = x(vZero) & (~mask(vZero))
136             y(vOne) = x(vOne) | mask(vOne)
137             y = matrix(y,sx)
138         else
139             b = bitget(x, pos)
140             tmp = vOne & b==0
141             if or(tmp)
142                 y(tmp) = y(tmp) + 2 .^(pos(tmp)-1)
143             end
144             tmp = vZero & b==1
145             if or(tmp)
146                 y(tmp) = y(tmp) - 2 .^(pos(tmp)-1)
147             end
148         end
149     end
150 endfunction