1 /* 2 This file is part of GNU APL, a free implementation of the 3 ISO/IEC Standard 13751, "Programming Language APL, Extended" 4 5 Copyright (C) 2008-2019 Dr. Jürgen Sauermann 6 7 This program is free software: you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #ifndef __BIF_F12_TAKE_DROP_HH_DEFINED__ 22 #define __BIF_F12_TAKE_DROP_HH_DEFINED__ 23 24 #include "Common.hh" 25 #include "PrimitiveFunction.hh" 26 27 //============================================================================= 28 /** primitive functions Take and First */ 29 /// The class implementing ↑ 30 class Bif_F12_TAKE : public NonscalarFunction 31 { 32 public: 33 /// Constructor Bif_F12_TAKE()34 Bif_F12_TAKE() 35 : NonscalarFunction(TOK_F12_TAKE) 36 {} 37 38 /// overloaded Function::eval_B() eval_B(Value_P B)39 virtual Token eval_B(Value_P B) 40 { return Token(TOK_APL_VALUE1, first(B));} 41 42 /// overloaded Function::eval_AB() 43 virtual Token eval_AB(Value_P A, Value_P B); 44 45 /// overloaded Function::eval_AXB() 46 virtual Token eval_AXB(Value_P A, Value_P X, Value_P B); 47 48 /// Take from B according to ravel_A 49 static Value_P do_take(const Shape & shape_Zi, Value_P B); 50 51 /// Fill Z with B, pad as necessary 52 static void fill(const Shape & shape_Zi, Cell * cZ, Value & Z_owner, 53 Value_P B); 54 55 static Bif_F12_TAKE * fun; ///< Built-in function 56 static Bif_F12_TAKE _fun; ///< Built-in function 57 58 /// ↑B 59 static Value_P first(Value_P B); 60 61 protected: 62 /// Take A from B 63 Token take(Value_P A, Value_P B); 64 }; 65 //============================================================================= 66 /** primitive function drop */ 67 /// The class implementing ↓ 68 class Bif_F12_DROP : public NonscalarFunction 69 { 70 public: 71 /// Constructor Bif_F12_DROP()72 Bif_F12_DROP() 73 : NonscalarFunction(TOK_F12_DROP) 74 {} 75 76 /// overloaded Function::eval_AB() 77 virtual Token eval_AB(Value_P A, Value_P B); 78 79 /// overloaded Function::eval_AXB() 80 virtual Token eval_AXB(Value_P A, Value_P X, Value_P B); 81 82 static Bif_F12_DROP * fun; ///< Built-in function 83 static Bif_F12_DROP _fun; ///< Built-in function 84 85 protected: 86 87 }; 88 //============================================================================= 89 /** A helper class for Bif_F12_TAKE and Bif_F12_DROP. It implements an iterator 90 that iterates over the indices (as dictated by left argument A) of the 91 right argument B of A↑B or A↓B, 92 **/ 93 class TakeDropIterator 94 { 95 public: 96 /// constructor TakeDropIterator(bool take,const Shape & sh_A,const Shape & sh_B)97 TakeDropIterator(bool take, const Shape & sh_A, const Shape & sh_B) 98 : ref_B(sh_B), 99 current_offset(0), 100 outside_B(0), 101 has_overtake(false), 102 done(false) 103 { 104 ShapeItem _weight = 1; 105 loop(r, sh_A.get_rank()) 106 { 107 const ShapeItem sA = sh_A.get_transposed_shape_item(r); 108 const ShapeItem sB = sh_B.get_transposed_shape_item(r); 109 ShapeItem _from, _to; 110 if (take) // sh_A ↑ B 111 { 112 if (sA < 0) // take from end 113 { 114 _to = sB; 115 _from = sB + sA; // + since sA < 0 116 } 117 else // take from start 118 { 119 _from = 0; 120 _to = sA; 121 } 122 123 if (_from < 0 || _from >= sB) outside_B |= 1ULL << r; 124 if (_from < 0 || _to >= sB) has_overtake = true; 125 } 126 else // sh_A ↓ B 127 { 128 if (sA < 0) // drop from end 129 { 130 _from = 0; 131 _to = sB + sA; // + since sA < 0 132 } 133 else // drop from start 134 { 135 _from = sA; 136 _to = sB; 137 } 138 139 if (_from >= _to) // over-drop 140 { 141 _from = 0; 142 _to = 0; 143 } 144 } 145 146 Assert(_from <= _to); 147 148 _ftwc & ftwc_r = ftwc[r]; 149 ftwc_r.from = _from; 150 ftwc_r.to = _to; 151 ftwc_r.weight = _weight; 152 ftwc_r.current = _from; 153 current_offset += _from * _weight; 154 155 if (_from == _to) done = true; // empty array 156 157 _weight *= sB; 158 } 159 } 160 161 /// the work-horse of the iterator operator ++()162 void operator++() 163 { 164 loop(r, ref_B.get_rank()) 165 { 166 _ftwc & ftwc_r = ftwc[r]; 167 ++ftwc_r.current; 168 current_offset += ftwc_r.weight; 169 if (has_overtake) 170 { 171 if (ftwc_r.current < 0 || 172 ftwc_r.current >= ref_B.get_transposed_shape_item(r)) 173 outside_B |= 1ULL << r; 174 else 175 outside_B &= ~(1ULL << r); 176 } 177 178 if (ftwc_r.current < ftwc_r.to) return; 179 180 // end of dimension reached: reset this dimension 181 // and increment next dimension 182 // 183 current_offset -= ftwc_r.weight * (ftwc_r.current - ftwc_r.from); 184 ftwc_r.current = ftwc_r.from; 185 if (has_overtake) 186 { 187 if (ftwc_r.current < 0 || 188 ftwc_r.current >= ref_B.get_transposed_shape_item(r)) 189 outside_B |= 1ULL << r; 190 else 191 outside_B &= ~(1ULL << r); 192 } 193 } 194 done = true; 195 } 196 197 /// return true iff this inerator has more items to come. more() const198 bool more() const { return !done; } 199 200 /// return the current offset (if inside B) or else -1. operator ()() const201 ShapeItem operator()() const 202 { return outside_B ? -1 : current_offset; } 203 204 protected: 205 /// shape of the source array 206 const Shape & ref_B; 207 208 /// from / to / weight / current 209 struct _ftwc ftwc[MAX_RANK]; 210 211 /// the current offset from ↑B 212 ShapeItem current_offset; 213 214 /// a bitmask of dimensions with overtake 215 ShapeItem outside_B; 216 217 /// true iff over-Take of at least one dimension 218 bool has_overtake; 219 220 /// true iff this interator has reached its final item 221 bool done; 222 }; 223 //============================================================================= 224 #endif // __BIF_F12_TAKE_DROP_HH_DEFINED__ 225