1 /*
  2  *   Copyright (c) 2007, Michael Lehn
  3  *
  4  *   All rights reserved.
  5  *
  6  *   Redistribution and use in source and binary forms, with or without
  7  *   modification, are permitted provided that the following conditions
  8  *   are met:
  9  *
 10  *   1) Redistributions of source code must retain the above copyright
 11  *      notice, this list of conditions and the following disclaimer.
 12  *   2) Redistributions in binary form must reproduce the above copyright
 13  *      notice, this list of conditions and the following disclaimer in
 14  *      the documentation and/or other materials provided with the
 15  *      distribution.
 16  *   3) Neither the name of the FLENS development group nor the names of
 17  *      its contributors may be used to endorse or promote products derived
 18  *      from this software without specific prior written permission.
 19  *
 20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 31  */
 32 
 33 #ifndef FLENS_STORAGE_ARRAY_ARRAYVIEW_TCC
 34 #define FLENS_STORAGE_ARRAY_ARRAYVIEW_TCC 1
 35 
 36 #include <cassert>
 37 #include <cxxblas/level1/copy.h>
 38 #include <flens/storage/array/array.h>
 39 #include <flens/storage/array/constarrayview.h>
 40 
 41 namespace flens {
 42 
 43 template <typename T, typename I, typename A>
 44 ArrayView<T, I, A>::ArrayView(IndexType length, ElementType *data,
 45                               IndexType stride, IndexType firstIndex,
 46                               const Allocator &allocator)
 47     : _data(data-firstIndex),
 48       _allocator(allocator),
 49       _length(length),
 50       _stride(stride),
 51       _firstIndex(firstIndex)
 52 {
 53     ASSERT(_length>=0);
 54 }
 55 
 56 template <typename T, typename I, typename A>
 57 ArrayView<T, I, A>::ArrayView(const ArrayView &rhs)
 58     : _data(rhs._data),
 59       _allocator(rhs.allocator()),
 60       _length(rhs.length()),
 61       _stride(rhs.stride()),
 62       _firstIndex(rhs.firstIndex())
 63 {
 64 }
 65 
 66 template <typename T, typename I, typename A>
 67 template <typename RHS>
 68 ArrayView<T, I, A>::ArrayView(RHS &rhs)
 69     : _data(rhs.data()-rhs.firstIndex()),
 70       _allocator(rhs.allocator()),
 71       _length(rhs.length()),
 72       _stride(rhs.stride()),
 73       _firstIndex(rhs.firstIndex())
 74 {
 75 }
 76 
 77 template <typename T, typename I, typename A>
 78 ArrayView<T, I, A>::~ArrayView()
 79 {
 80 }
 81 
 82 //-- operators -----------------------------------------------------------------
 83 
 84 template <typename T, typename I, typename A>
 85 const typename ArrayView<T, I, A>::ElementType &
 86 ArrayView<T, I, A>::operator()(IndexType index) const
 87 {
 88 #   ifndef NDEBUG
 89     if (lastIndex()>=firstIndex()) {
 90         ASSERT(index>=firstIndex());
 91         ASSERT(index<=lastIndex());
 92     }
 93 #   endif
 94 
 95     return _data[_firstIndex + _stride*(index-_firstIndex)];
 96 }
 97 
 98 template <typename T, typename I, typename A>
 99 typename ArrayView<T, I, A>::ElementType &
100 ArrayView<T, I, A>::operator()(IndexType index)
101 {
102 #   ifndef NDEBUG
103     if (lastIndex()>=firstIndex()) {
104         ASSERT(index>=firstIndex());
105         ASSERT(index<=lastIndex());
106     }
107 #   endif
108 
109     return _data[_firstIndex + _stride*(index-_firstIndex)];
110 }
111 
112 template <typename T, typename I, typename A>
113 typename ArrayView<T, I, A>::IndexType
114 ArrayView<T, I, A>::firstIndex() const
115 {
116     return _firstIndex;
117 }
118 
119 template <typename T, typename I, typename A>
120 typename ArrayView<T, I, A>::IndexType
121 ArrayView<T, I, A>::lastIndex() const
122 {
123     return _firstIndex+_length-1;
124 }
125 
126 template <typename T, typename I, typename A>
127 typename ArrayView<T, I, A>::IndexType
128 ArrayView<T, I, A>::length() const
129 {
130     return _length;
131 }
132 
133 template <typename T, typename I, typename A>
134 typename ArrayView<T, I, A>::IndexType
135 ArrayView<T, I, A>::stride() const
136 {
137     return _stride;
138 }
139 
140 template <typename T, typename I, typename A>
141 const typename ArrayView<T, I, A>::ElementType *
142 ArrayView<T, I, A>::data() const
143 {
144     return &_data[_firstIndex];
145 }
146 
147 template <typename T, typename I, typename A>
148 typename ArrayView<T, I, A>::ElementType *
149 ArrayView<T, I, A>::data()
150 {
151     return &_data[_firstIndex];
152 }
153 
154 template <typename T, typename I, typename A>
155 const typename ArrayView<T, I, A>::Allocator &
156 ArrayView<T, I, A>::allocator() const
157 {
158     return _allocator;
159 }
160 
161 template <typename T, typename I, typename A>
162 bool
163 ArrayView<T, I, A>::resize(IndexType DEBUG_VAR(length),
164                            IndexType,
165                            const ElementType &)
166 {
167     ASSERT(length==_length);
168     return false;
169 }
170 
171 template <typename T, typename I, typename A>
172 template <typename ARRAY>
173 bool
174 ArrayView<T, I, A>::resize(const ARRAY &rhs, const ElementType &value)
175 {
176     return resize(rhs.length(), rhs.firstIndex(), value);
177 }
178 
179 template <typename T, typename I, typename A>
180 bool
181 ArrayView<T, I, A>::fill(const ElementType &value)
182 {
183     for (IndexType i=firstIndex(); i<=lastIndex(); ++i) {
184         operator()(i) = value;
185     }
186     return true;
187 }
188 
189 template <typename T, typename I, typename A>
190 void
191 ArrayView<T, I, A>::changeIndexBase(IndexType DEBUG_VAR(firstIndex))
192 {
193     // TODO: Error message "changing index bases of views is not allowed"
194     // Lehn: Why is changing the index base not allowed here??
195     //       I inserted a mean ASSERT(0) just to see if anybody is
196     //       calling this method at all.  At the moment I think we
197     //       just could implement this.
198     ASSERT(_firstIndex==firstIndex);
199 }
200 
201 template <typename T, typename I, typename A>
202 const typename ArrayView<T, I, A>::ConstView
203 ArrayView<T, I, A>::view(IndexType from, IndexType to,
204                          IndexType stride, IndexType firstViewIndex) const
205 {
206     const IndexType length = (to-from)/stride+1;
207 
208 #   ifndef NDEBUG
209     // prevent an out-of-bound assertion in case a view is empty anyway
210     if (length==0) {
211         return ConstView(length,                // length
212                          0,                     // data
213                          stride*_stride,        // stride
214                          firstViewIndex,        // firstIndex in view
215                          allocator());          // allocator
216     }
217 #   endif
218 
219     ASSERT(firstIndex()<=from);
220     ASSERT(lastIndex()>=to);
221     ASSERT(from<=to);
222     ASSERT(stride>0);
223     return ConstView(length,                // length
224                      &operator()(from),     // data
225                      stride*_stride,        // stride
226                      firstViewIndex,        // firstIndex in view
227                      allocator());          // allocator
228 }
229 
230 template <typename T, typename I, typename A>
231 ArrayView<T, I, A>
232 ArrayView<T, I, A>::view(IndexType from, IndexType to,
233                          IndexType stride, IndexType firstViewIndex)
234 {
235     const IndexType length = (to-from)/stride+1;
236 
237 #   ifndef NDEBUG
238     // prevent an out-of-bound assertion in case a view is empty anyway
239     if (length==0) {
240         return ArrayView(length,                // length
241                          0,                     // data
242                          stride*_stride,        // stride
243                          firstViewIndex,        // firstIndex in view
244                          allocator());          // allocator
245     } else {
246         ASSERT(firstIndex()<=from);
247         ASSERT(lastIndex()>=to);
248         ASSERT(from<=to);
249     }
250 #   endif
251 
252     ASSERT(stride>0);
253     return ArrayView(length,                // length
254                      &operator()(from),     // data
255                      stride*_stride,        // stride
256                      firstViewIndex,        // firstIndex in view
257                      allocator());          // allocator
258 }
259 
260 // namespace flens
261 
262 #endif // FLENS_STORAGE_ARRAY_ARRAYVIEW_TCC