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-2015 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 #include "Shape.hh"
22 #include "Value.hh"
23
24 //-----------------------------------------------------------------------------
Shape(const Value * A,int qio_A)25 Shape::Shape(const Value * A, int qio_A)
26 : rho_rho(0),
27 volume(1)
28 {
29 // check that A is a shape value, like the left argument of A⍴B
30 //
31 if (A->get_rank() > 1) RANK_ERROR;
32 if (A->element_count() > MAX_RANK) LIMIT_ERROR_RANK; // of A
33
34 loop(r, A->element_count())
35 {
36 add_shape_item(A->get_ravel(r).get_near_int() - qio_A);
37 }
38 }
39 //-----------------------------------------------------------------------------
abs() const40 Shape Shape::abs() const
41 {
42 Shape ret;
43 loop(r, rho_rho)
44 {
45 const ShapeItem len = rho[r];
46 if (len < 0) ret.add_shape_item(- len);
47 else ret.add_shape_item( len);
48 }
49
50 return ret;
51 }
52 //-----------------------------------------------------------------------------
53 bool
operator ==(const Shape & other) const54 Shape::operator ==(const Shape & other) const
55 {
56 if (rho_rho != other.rho_rho) return false;
57
58 loop(r, rho_rho)
59 if (rho[r] != other.rho[r]) return false;
60
61 return true;
62 }
63 //-----------------------------------------------------------------------------
64 void
expand(const Shape & B)65 Shape::expand(const Shape & B)
66 {
67 // increase rank as necessary
68 //
69 expand_rank(B.get_rank());
70
71 // increase axes as necessary
72 //
73 volume = 1;
74 loop(r, rho_rho)
75 {
76 if (rho[r] < B.rho[r]) rho[r] = B.rho[r];
77 volume *= rho[r];
78 }
79 }
80 //-----------------------------------------------------------------------------
81 Shape
insert_axis(Axis axis,ShapeItem len) const82 Shape::insert_axis(Axis axis, ShapeItem len) const
83 {
84 if (get_rank() >= MAX_RANK) LIMIT_ERROR_RANK;
85
86 if (axis <= 0) // insert before first axis
87 {
88 const Shape ret(len);
89 return ret + *this;
90 }
91
92 if (uAxis(axis) >= get_rank()) // insert after last axis
93 {
94 const Shape ret(len);
95 return *this + ret;
96 }
97
98 // insert after (including) axis
99 //
100 Shape ret;
101 loop(r, axis)
102 ret.add_shape_item(get_shape_item(r));
103
104 ret.add_shape_item(len);
105 loop(r, get_rank() - axis)
106 ret.add_shape_item(get_shape_item(r + axis));
107
108 return ret;
109 }
110 //-----------------------------------------------------------------------------
111 ShapeItem
ravel_pos(const Shape & idx) const112 Shape::ravel_pos(const Shape & idx) const
113 {
114 ShapeItem p = 0;
115 ShapeItem w = 1;
116
117 for (Rank r = get_rank(); r-- > 0;)
118 {
119 p += w*idx.get_shape_item(r);
120 w *= get_shape_item(r);
121 }
122
123 return p;
124 }
125 //-----------------------------------------------------------------------------
126 Shape
offset_to_index(ShapeItem offset) const127 Shape::offset_to_index(ShapeItem offset) const
128 {
129 Shape ret;
130 ret.rho_rho = rho_rho;
131 for (int r = rho_rho; r > 0;)
132 {
133 --r;
134 if (rho[r] == 0)
135 {
136 Assert(offset == 0);
137 ret.rho[r] = 0;
138 continue;
139 }
140
141 ret.rho[r] = offset % rho[r];
142 offset /= rho[r];
143 }
144
145 return ret;
146 }
147 //-----------------------------------------------------------------------------
148 void
check_same(const Shape & B,ErrorCode rank_err,ErrorCode len_err,const char * loc) const149 Shape::check_same(const Shape & B, ErrorCode rank_err, ErrorCode len_err,
150 const char * loc) const
151 {
152 if (get_rank() != B.get_rank())
153 throw_apl_error(rank_err, loc);
154
155 loop(r, get_rank())
156 {
157 if (get_shape_item(r) != B.get_shape_item(r))
158 throw_apl_error(len_err, loc);
159 }
160 }
161 //-----------------------------------------------------------------------------
162 ostream &
operator <<(ostream & out,const Shape & shape)163 operator <<(ostream & out, const Shape & shape)
164 {
165 out << "⊏";
166 loop(r, shape.get_rank())
167 {
168 if (r) out << ":";
169 out << shape.get_shape_item(r);
170 }
171 out << "⊐";
172 return out;
173 }
174 //-----------------------------------------------------------------------------
175