OSDN Git Service

1dc78cb3745f675f7823758b2395742edf71a4d6
[pf3gnuchains/gcc-fork.git] / libgfortran / intrinsics / reshape_generic.c
1 /* Generic implementation of the RESHAPE intrinsic
2    Copyright 2002 Free Software Foundation, Inc.
3    Contributed by Paul Brook <paul@nowt.org>
4
5 This file is part of the GNU Fortran 95 runtime library (libgfortran).
6
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file.  (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
19 executable.)
20
21 Ligbfortran is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public
27 License along with libgfortran; see the file COPYING.  If not,
28 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29 Boston, MA 02110-1301, USA.  */
30
31 #include "config.h"
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35 #include "libgfortran.h"
36
37 typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type;
38 typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) parray;
39
40 extern void reshape (parray *, parray *, shape_type *, parray *, shape_type *);
41 export_proto(reshape);
42
43 /* The shape parameter is ignored. We can currently deduce the shape from the
44    return array.  */
45
46 void
47 reshape (parray *ret, parray *source, shape_type *shape,
48          parray *pad, shape_type *order)
49 {
50   /* r.* indicates the return array.  */
51   index_type rcount[GFC_MAX_DIMENSIONS];
52   index_type rextent[GFC_MAX_DIMENSIONS];
53   index_type rstride[GFC_MAX_DIMENSIONS];
54   index_type rstride0;
55   index_type rdim;
56   index_type rsize;
57   index_type rs;
58   index_type rex;
59   char *rptr;
60   /* s.* indicates the source array.  */
61   index_type scount[GFC_MAX_DIMENSIONS];
62   index_type sextent[GFC_MAX_DIMENSIONS];
63   index_type sstride[GFC_MAX_DIMENSIONS];
64   index_type sstride0;
65   index_type sdim;
66   index_type ssize;
67   const char *sptr;
68   /* p.* indicates the pad array.  */
69   index_type pcount[GFC_MAX_DIMENSIONS];
70   index_type pextent[GFC_MAX_DIMENSIONS];
71   index_type pstride[GFC_MAX_DIMENSIONS];
72   index_type pdim;
73   index_type psize;
74   const char *pptr;
75
76   const char *src;
77   int n;
78   int dim;
79   int size;
80
81   if (source->dim[0].stride == 0)
82     source->dim[0].stride = 1;
83   if (shape->dim[0].stride == 0)
84     shape->dim[0].stride = 1;
85   if (pad && pad->dim[0].stride == 0)
86     pad->dim[0].stride = 1;
87   if (order && order->dim[0].stride == 0)
88     order->dim[0].stride = 1;
89
90   if (ret->data == NULL)
91     {
92       size = GFC_DESCRIPTOR_SIZE (ret);
93       rdim = shape->dim[0].ubound - shape->dim[0].lbound + 1;
94       rs = 1;
95       for (n=0; n < rdim; n++)
96         {
97           ret->dim[n].lbound = 0;
98           rex = shape->data[n * shape->dim[0].stride];
99           ret->dim[n].ubound =  rex - 1;
100           ret->dim[n].stride = rs;
101           rs *= rex;
102         }
103       ret->offset = 0;
104       ret->data = internal_malloc_size ( rs * size );
105       ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rdim;
106     }
107   else
108     {
109       size = GFC_DESCRIPTOR_SIZE (ret);
110       rdim = GFC_DESCRIPTOR_RANK (ret);
111       if (ret->dim[0].stride == 0)
112         ret->dim[0].stride = 1;
113     }
114
115   rsize = 1;
116   for (n = 0; n < rdim; n++)
117     {
118       if (order)
119         dim = order->data[n * order->dim[0].stride] - 1;
120       else
121         dim = n;
122
123       rcount[n] = 0;
124       rstride[n] = ret->dim[dim].stride;
125       rextent[n] = ret->dim[dim].ubound + 1 - ret->dim[dim].lbound;
126
127       if (rextent[n] != shape->data[dim * shape->dim[0].stride])
128         runtime_error ("shape and target do not conform");
129
130       if (rsize == rstride[n])
131         rsize *= rextent[n];
132       else
133         rsize = 0;
134       if (rextent[n] <= 0)
135         return;
136     }
137
138   sdim = GFC_DESCRIPTOR_RANK (source);
139   ssize = 1;
140   for (n = 0; n < sdim; n++)
141     {
142       scount[n] = 0;
143       sstride[n] = source->dim[n].stride;
144       sextent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound;
145       if (sextent[n] <= 0)
146         abort ();
147
148       if (ssize == sstride[n])
149         ssize *= sextent[n];
150       else
151         ssize = 0;
152     }
153
154   if (pad)
155     {
156       pdim = GFC_DESCRIPTOR_RANK (pad);
157       psize = 1;
158       for (n = 0; n < pdim; n++)
159         {
160           pcount[n] = 0;
161           pstride[n] = pad->dim[n].stride;
162           pextent[n] = pad->dim[n].ubound + 1 - pad->dim[n].lbound;
163           if (pextent[n] <= 0)
164             abort ();
165           if (psize == pstride[n])
166             psize *= pextent[n];
167           else
168             psize = 0;
169         }
170       pptr = pad->data;
171     }
172   else
173     {
174       pdim = 0;
175       psize = 1;
176       pptr = NULL;
177     }
178
179   if (rsize != 0 && ssize != 0 && psize != 0)
180     {
181       rsize *= size;
182       ssize *= size;
183       psize *= size;
184       reshape_packed (ret->data, rsize, source->data, ssize,
185                       pad ? pad->data : NULL, psize);
186       return;
187     }
188   rptr = ret->data;
189   src = sptr = source->data;
190   rstride0 = rstride[0] * size;
191   sstride0 = sstride[0] * size;
192
193   while (rptr)
194     {
195       /* Select between the source and pad arrays.  */
196       memcpy(rptr, src, size);
197       /* Advance to the next element.  */
198       rptr += rstride0;
199       src += sstride0;
200       rcount[0]++;
201       scount[0]++;
202       /* Advance to the next destination element.  */
203       n = 0;
204       while (rcount[n] == rextent[n])
205         {
206           /* When we get to the end of a dimension, reset it and increment
207              the next dimension.  */
208           rcount[n] = 0;
209           /* We could precalculate these products, but this is a less
210              frequently used path so proabably not worth it.  */
211           rptr -= rstride[n] * rextent[n] * size;
212           n++;
213           if (n == rdim)
214             {
215               /* Break out of the loop.  */
216               rptr = NULL;
217               break;
218             }
219           else
220             {
221               rcount[n]++;
222               rptr += rstride[n] * size;
223             }
224         }
225       /* Advance to the next source element.  */
226       n = 0;
227       while (scount[n] == sextent[n])
228         {
229           /* When we get to the end of a dimension, reset it and increment
230              the next dimension.  */
231           scount[n] = 0;
232           /* We could precalculate these products, but this is a less
233              frequently used path so proabably not worth it.  */
234           src -= sstride[n] * sextent[n] * size;
235           n++;
236           if (n == sdim)
237             {
238               if (sptr && pad)
239                 {
240                   /* Switch to the pad array.  */
241                   sptr = NULL;
242                   sdim = pdim;
243                   for (dim = 0; dim < pdim; dim++)
244                     {
245                       scount[dim] = pcount[dim];
246                       sextent[dim] = pextent[dim];
247                       sstride[dim] = pstride[dim];
248                       sstride0 = sstride[0] * size;
249                     }
250                 }
251               /* We now start again from the beginning of the pad array.  */
252               src = pptr;
253               break;
254             }
255           else
256             {
257               scount[n]++;
258               sptr += sstride[n] * size;
259             }
260         }
261     }
262 }