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_ARRAY_TCC
 34 #define FLENS_STORAGE_ARRAY_ARRAY_TCC 1
 35 
 36 #include <cassert>
 37 #include <cxxblas/level1/copy.h>
 38 #include <flens/storage/array/arrayview.h>
 39 #include <flens/storage/array/constarrayview.h>
 40 
 41 namespace flens {
 42 
 43 template <typename T, typename I, typename A>
 44 Array<T, I, A>::Array()
 45     : _data(0), _length(0), _firstIndex(1)
 46 {
 47 }
 48 
 49 template <typename T, typename I, typename A>
 50 Array<T, I, A>::Array(IndexType length, IndexType firstIndex,
 51                       const ElementType &value, const Allocator &allocator)
 52     : _data(0), _allocator(allocator), _length(length), _firstIndex(firstIndex)
 53 {
 54     ASSERT(_length>=0);
 55 
 56     _allocate(value);
 57 }
 58 
 59 template <typename T, typename I, typename A>
 60 Array<T, I, A>::Array(const Array &rhs)
 61     : _data(0), _allocator(rhs.allocator()),
 62       _length(rhs.length()), _firstIndex(rhs.firstIndex())
 63 {
 64     ASSERT(_length>=0);
 65 
 66     if (length()>0) {
 67         _allocate();
 68         cxxblas::copy(length(), rhs.data(), rhs.stride(), data(), stride());
 69     }
 70 }
 71 
 72 template <typename T, typename I, typename A>
 73 template <typename RHS>
 74 Array<T, I, A>::Array(const RHS &rhs)
 75     : _data(0), _allocator(rhs.allocator()),
 76       _length(rhs.length()), _firstIndex(rhs.firstIndex())
 77 {
 78     if (length()>0) {
 79         _allocate();
 80         cxxblas::copy(length(), rhs.data(), rhs.stride(), data(), stride());
 81     }
 82 }
 83 
 84 template <typename T, typename I, typename A>
 85 Array<T, I, A>::~Array()
 86 {
 87     _release();
 88 }
 89 
 90 //-- operators -----------------------------------------------------------------
 91 
 92 template <typename T, typename I, typename A>
 93 const typename Array<T, I, A>::ElementType &
 94 Array<T, I, A>::operator()(IndexType index) const
 95 {
 96     ASSERT(index>=firstIndex());
 97     ASSERT(index<=lastIndex());
 98     return _data[index];
 99 }
100 
101 template <typename T, typename I, typename A>
102 typename Array<T, I, A>::ElementType &
103 Array<T, I, A>::operator()(IndexType index)
104 {
105     ASSERT(index>=firstIndex());
106     ASSERT(index<=lastIndex());
107     return _data[index];
108 }
109 
110 template <typename T, typename I, typename A>
111 typename Array<T, I, A>::IndexType
112 Array<T, I, A>::firstIndex() const
113 {
114     return _firstIndex;
115 }
116 
117 template <typename T, typename I, typename A>
118 typename Array<T, I, A>::IndexType
119 Array<T, I, A>::lastIndex() const
120 {
121     return _firstIndex+_length-IndexType(1);
122 }
123 
124 template <typename T, typename I, typename A>
125 typename Array<T, I, A>::IndexType
126 Array<T, I, A>::length() const
127 {
128     return _length;
129 }
130 
131 template <typename T, typename I, typename A>
132 typename Array<T, I, A>::IndexType
133 Array<T, I, A>::stride() const
134 {
135     return IndexType(1);
136 }
137 
138 template <typename T, typename I, typename A>
139 const typename Array<T, I, A>::ElementType *
140 Array<T, I, A>::data() const
141 {
142     return &_data[_firstIndex];
143 }
144 
145 template <typename T, typename I, typename A>
146 typename Array<T, I, A>::ElementType *
147 Array<T, I, A>::data()
148 {
149     return &_data[_firstIndex];
150 }
151 
152 template <typename T, typename I, typename A>
153 const typename Array<T, I, A>::Allocator &
154 Array<T, I, A>::allocator() const
155 {
156     return _allocator;
157 }
158 
159 template <typename T, typename I, typename A>
160 bool
161 Array<T, I, A>::resize(IndexType length, IndexType firstIndex,
162                        const ElementType &value)
163 {
164     if (length!=_length) {
165         _release();
166         _length = length;
167         _firstIndex = firstIndex;
168         _allocate(value);
169         return true;
170     }
171     changeIndexBase(firstIndex);
172     return false;
173 }
174 
175 template <typename T, typename I, typename A>
176 template <typename ARRAY>
177 bool
178 Array<T, I, A>::resize(const ARRAY &rhs, const ElementType &value)
179 {
180     return resize(rhs.length(), rhs.firstIndex(), value);
181 }
182 
183 template <typename T, typename I, typename A>
184 bool
185 Array<T, I, A>::fill(const ElementType &value)
186 {
187     std::fill_n(data(), length(), value);
188     return true;
189 }
190 
191 template <typename T, typename I, typename A>
192 void
193 Array<T, I, A>::changeIndexBase(IndexType firstIndex)
194 {
195     _data += _firstIndex - firstIndex;
196     _firstIndex = firstIndex;
197 }
198 
199 template <typename T, typename I, typename A>
200 const typename Array<T, I, A>::ConstView
201 Array<T, I, A>::view(IndexType from, IndexType to,
202                      IndexType stride, IndexType firstViewIndex) const
203 {
204     const IndexType length = (to-from)/stride+1;
205 
206 #   ifndef NDEBUG
207     // prevent an out-of-bound assertion in case a view is empty anyway
208     const ElementType   *data = (length!=0) ? &operator()(from) : 0;
209 
210     if (length!=0) {
211         ASSERT(firstIndex()<=from);
212         ASSERT(lastIndex()>=to);
213         ASSERT(from<=to);
214     }
215     ASSERT(stride>=1);
216 #   else
217     const ElementType   *data = &operator()(from);
218 #   endif
219 
220     return ConstView(length, data, stride, firstViewIndex, allocator());
221 }
222 
223 template <typename T, typename I, typename A>
224 typename Array<T, I, A>::View
225 Array<T, I, A>::view(IndexType from, IndexType to,
226                      IndexType stride, IndexType firstViewIndex)
227 {
228     const IndexType     length = (to-from)/stride+1;
229 
230 #   ifndef NDEBUG
231     // prevent an out-of-bound assertion in case a view is empty anyway
232     ElementType         *data = (length!=0) ? &operator()(from) : 0;
233 
234     if (length!=0) {
235         ASSERT(firstIndex()<=from);
236         ASSERT(lastIndex()>=to);
237         ASSERT(from<=to);
238     }
239     ASSERT(stride>=1);
240 #   else
241     ElementType         *data = &operator()(from);
242 #   endif
243 
244     return View(length, data, stride, firstViewIndex, allocator());
245 }
246 
247 //-- private methods -----------------------------------------------------------
248 
249 template <typename T, typename I, typename A>
250 void
251 Array<T, I, A>::_raw_allocate()
252 {
253     ASSERT(!_data);
254     ASSERT(length()>=0);
255 
256     if (length()>0) {
257         _data = _allocator.allocate(_length) - _firstIndex;
258         ASSERT(_data+_firstIndex);
259         ASSERT(_data);
260     }
261 }
262 
263 template <typename T, typename I, typename A>
264 void
265 Array<T, I, A>::_allocate(const ElementType &value)
266 {
267     _raw_allocate();
268     for (IndexType i=firstIndex(); i<=lastIndex(); ++i) {
269         _allocator.construct(_data+i, value);
270     }
271 }
272 
273 template <typename T, typename I, typename A>
274 void
275 Array<T, I, A>::_release()
276 {
277     if (_data) {
278         for (IndexType i=firstIndex(); i<=lastIndex(); ++i) {
279             _allocator.destroy(_data+i);
280         }
281         _allocator.deallocate(data(), _length);   
282         _data = 0;     
283     }
284     ASSERT(_data==0);
285 }
286 
287 // namespace flens
288 
289 #endif // FLENS_STORAGE_ARRAY_ARRAY_TCC