b47408c17296f85fd0a5d9ceb9b962fb0e9df9c3
[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     // Check consistency between x and pos sizes
62     sx = size(x)
63     ndx = ndims(x)
64     sp = size(pos)
65     ndp = ndims(pos)
66     sameBits = ndp<ndx | ~and(sx(1:ndx)==sp(1:ndx)) // Same bits for all x components
67     if sameBits then
68         if ~isscalar(pos) & ~isvector(pos)
69             msg = gettext("%s: Arguments #%d and #%d: Incompatible sizes.\n")
70             error(msprintf(msg, fname, 1, 2))
71         end
72         if ~isdef("v","l") | size(v,"*")==1
73             pos = unique(pos)
74             // we can't do that if an array v is provided, because then
75             // its length must match the pos one.
76         else
77             if length(pos)>posmax
78                 msg = gettext("%s: Argument #%d is longer than %d. Please check against duplicate values.\n")
79                 error(msprintf(msg, fname, 2, posmax))
80             end
81         end
82     else // ndp>=ndx & and(sx(1:ndx)==sp(1:ndx))
83         pos = matrix(pos,[sx -1])
84         // duplicate values along a range can't be removed nor easily canceled.
85         // So, no check. Never mind.
86     end
87
88     // Check v
89     // -------
90     // At the end, v must be either a vector with the pos's length (sameBits case)
91     // or an array with same sizes as pos (element-wise case)
92     if ~isdef("v","l") || v==[] then
93         v = ones(pos)
94     else
95         if  (type(v)<>1  & type(v)<>8) || or(v~=0 & v~=1)
96             msg = _("%s: Argument #%d: Must be in the set {%s}.\n")
97             error(msprintf(msg, fname, 3, "0,1"))
98         end
99         if prod(size(v)(1:min(ndims(v),ndims(pos)))) == 1 // scalar or hypercolumn cases
100             v = v .*. ones(pos)
101         elseif prod(size(v)(1:ndims(pos))) ~= length(pos)
102             msg = gettext("%s: Arguments #%d and #%d: Incompatible sizes.\n")
103             error(msprintf(msg, fname, 2, 3))
104         end
105     end
106
107     // PROCESSING
108     // ==========
109     if sameBits then
110         nBitLayers = length(pos)
111         template = ones(x)
112     else
113         nBitLayers = size(pos,ndx+1)
114         // Extraction mask:
115         str = strcat(emptystr(1,ndx)+":,")+"iL"
116     end
117     Pos = pos
118     V = v
119     y = x
120     //
121     for iL = 1:nBitLayers
122         if sameBits
123             pos = template*Pos(iL)
124             v   = template*V(iL)
125         else
126             execstr("pos = Pos("+str+"); v = V("+str+")")
127         end
128         vZero = (v == 0)
129         vOne  = (v == 1)
130         x = y
131         if type(x)==8 then
132             mask =  2 .^ iconvert((pos-1), inttype(x))
133             y(vZero) = x(vZero) & (~mask(vZero))
134             y(vOne) = x(vOne) | mask(vOne)
135             y = matrix(y,sx)
136         else
137             b = bitget(x, pos)
138             tmp = vOne & b==0
139             if or(tmp)
140                 y(tmp) = y(tmp) + 2 .^(pos(tmp)-1)
141             end
142             tmp = vZero & b==1
143             if or(tmp)
144                 y(tmp) = y(tmp) - 2 .^(pos(tmp)-1)
145             end
146         end
147     end
148 endfunction