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