1/*****************************************************************************/
2/*                                    Xdmf                                   */
3/*                       Extensible Data Model and Format                    */
4/*                                                                           */
5/*  Id : XdmfArray.tpp                                                       */
6/*                                                                           */
7/*  Author:                                                                  */
8/*     Kenneth Leiter                                                        */
9/*     kenneth.leiter@arl.army.mil                                           */
10/*     US Army Research Laboratory                                           */
11/*     Aberdeen Proving Ground, MD                                           */
12/*                                                                           */
13/*     Copyright @ 2011 US Army Research Laboratory                          */
14/*     All Rights Reserved                                                   */
15/*     See Copyright.txt for details                                         */
16/*                                                                           */
17/*     This software is distributed WITHOUT ANY WARRANTY; without            */
18/*     even the implied warranty of MERCHANTABILITY or FITNESS               */
19/*     FOR A PARTICULAR PURPOSE.  See the above copyright notice             */
20/*     for more information.                                                 */
21/*                                                                           */
22/*****************************************************************************/
23
24#include <functional>
25#include <numeric>
26#include <sstream>
27#include "XdmfArray.hpp"
28
29template <typename T>
30class XdmfArray::GetValue : public boost::static_visitor<T> {
31public:
32
33  GetValue(const unsigned int index) :
34    mIndex(index)
35  {
36  }
37
38  T
39  operator()(const boost::blank &) const
40  {
41    return 0;
42  }
43
44  T
45  operator()(const shared_ptr<std::vector<std::string> > & array) const
46  {
47    return (T)atof(array->operator[](mIndex).c_str());
48  }
49
50  template<typename U>
51  T
52  operator()(const shared_ptr<std::vector<U> > & array) const
53  {
54    return (T)array->operator[](mIndex);
55  }
56
57  template<typename U>
58  T
59  operator()(const boost::shared_array<const U> & array) const
60  {
61    return (T)array[mIndex];
62  }
63
64private:
65
66  const unsigned int mIndex;
67};
68
69template <>
70class XdmfArray::GetValue<std::string> :
71  public boost::static_visitor<std::string> {
72public:
73
74  GetValue(const unsigned int index) :
75    mIndex(index)
76  {
77  }
78
79  std::string
80  operator()(const boost::blank &) const
81  {
82    return "";
83  }
84
85  std::string
86  operator()(const shared_ptr<std::vector<std::string> > & array) const
87  {
88    return array->operator[](mIndex);
89  }
90
91  template<typename U>
92  std::string
93  operator()(const shared_ptr<std::vector<U> > & array) const
94  {
95    std::stringstream value;
96    value << array->operator[](mIndex);
97    return value.str();
98  }
99
100  std::string
101  operator()(const boost::shared_array<const std::string> & array) const
102  {
103    return array[mIndex];
104  }
105
106  template<typename U>
107  std::string
108  operator()(const boost::shared_array<const U> & array) const
109  {
110    std::stringstream value;
111    value << array[mIndex];
112    return value.str();
113  }
114
115private:
116
117  const unsigned int mIndex;
118};
119
120template <typename T>
121class XdmfArray::GetValues : public boost::static_visitor<void> {
122public:
123
124  GetValues(const unsigned int startIndex,
125            T * valuesPointer,
126            const unsigned int numValues,
127            const unsigned int arrayStride,
128            const unsigned int valuesStride) :
129    mStartIndex(startIndex),
130    mValuesPointer(valuesPointer),
131    mNumValues(numValues),
132    mArrayStride(arrayStride),
133    mValuesStride(valuesStride)
134  {
135  }
136
137  void
138  operator()(const boost::blank &) const
139  {
140    return;
141  }
142
143  void
144  operator()(const shared_ptr<std::vector<std::string> > & array) const
145  {
146    for(unsigned int i=0; i<mNumValues; ++i) {
147      mValuesPointer[i*mValuesStride] =
148        (T)atof(array->operator[](mStartIndex + i*mArrayStride).c_str());
149    }
150  }
151
152  template<typename U>
153  void
154  operator()(const shared_ptr<std::vector<U> > & array) const
155  {
156    for(unsigned int i=0; i<mNumValues; ++i) {
157      mValuesPointer[i*mValuesStride] =
158        (T)array->operator[](mStartIndex + i*mArrayStride);
159    }
160  }
161
162  template<typename U>
163  void
164  operator()(const boost::shared_array<const U> & array) const
165  {
166    for(unsigned int i=0; i<mNumValues; ++i) {
167      mValuesPointer[i*mValuesStride] = (T)array[mStartIndex + i*mArrayStride];
168    }
169  }
170
171private:
172
173  const unsigned int mStartIndex;
174  T * mValuesPointer;
175  const unsigned int mNumValues;
176  const unsigned int mArrayStride;
177  const unsigned int mValuesStride;
178};
179
180template <>
181class XdmfArray::GetValues<std::string> : public boost::static_visitor<void> {
182public:
183
184  GetValues(const unsigned int startIndex,
185            std::string * valuesPointer,
186            const unsigned int numValues,
187            const unsigned int arrayStride,
188            const unsigned int valuesStride) :
189    mStartIndex(startIndex),
190    mValuesPointer(valuesPointer),
191    mNumValues(numValues),
192    mArrayStride(arrayStride),
193    mValuesStride(valuesStride)
194  {
195  }
196
197  void
198  operator()(const boost::blank &) const
199  {
200    return;
201  }
202
203  template<typename U>
204  void
205  operator()(const shared_ptr<std::vector<U> > & array) const
206  {
207    for(unsigned int i=0; i<mNumValues; ++i) {
208      std::stringstream value;
209      value << array->operator[](mStartIndex + i*mArrayStride);
210      mValuesPointer[i*mValuesStride] = value.str();
211    }
212  }
213
214  template<typename U>
215  void
216  operator()(const boost::shared_array<const U> & array) const
217  {
218    for(unsigned int i=0; i<mNumValues; ++i) {
219      std::stringstream value;
220      value << array[mStartIndex + i*mArrayStride];
221      mValuesPointer[i*mValuesStride] = value.str();
222    }
223  }
224
225private:
226
227  const unsigned int mStartIndex;
228  std::string * mValuesPointer;
229  const unsigned int mNumValues;
230  const unsigned int mArrayStride;
231  const unsigned int mValuesStride;
232};
233
234template <typename T>
235class XdmfArray::Insert : public boost::static_visitor<void> {
236public:
237
238  Insert(XdmfArray * const array,
239         const unsigned int startIndex,
240         const T * const valuesPointer,
241         const unsigned int numValues,
242         const unsigned int arrayStride,
243         const unsigned int valuesStride,
244         std::vector<unsigned int> & dimensions) :
245    mArray(array),
246    mStartIndex(startIndex),
247    mValuesPointer(valuesPointer),
248    mNumValues(numValues),
249    mArrayStride(arrayStride),
250    mValuesStride(valuesStride),
251    mDimensions(dimensions)
252  {
253  }
254
255  void
256  operator()(const boost::blank &) const
257  {
258    mArray->initialize<T>();
259    boost::apply_visitor(*this,
260                         mArray->mArray);
261  }
262
263  void
264  operator()(shared_ptr<std::vector<std::string> > & array) const
265  {
266    unsigned int size = mStartIndex + (mNumValues - 1) * mArrayStride + 1;
267    if(array->size() < size) {
268      array->resize(size);
269      mDimensions.clear();
270    }
271    for(unsigned int i=0; i<mNumValues; ++i) {
272      std::stringstream value;
273      value << mValuesPointer[i*mValuesStride];
274      array->operator[](mStartIndex + i*mArrayStride) = value.str();
275    }
276  }
277
278  template<typename U>
279  void
280  operator()(shared_ptr<std::vector<U> > & array) const
281  {
282    unsigned int size = mStartIndex + (mNumValues - 1) * mArrayStride + 1;
283    if(array->size() < size) {
284      array->resize(size);
285      mDimensions.clear();
286    }
287    for(unsigned int i=0; i<mNumValues; ++i) {
288      array->operator[](mStartIndex + i*mArrayStride) =
289        (U)mValuesPointer[i*mValuesStride];
290    }
291  }
292
293  template<typename U>
294  void
295  operator()(boost::shared_array<const U> &) const
296  {
297    mArray->internalizeArrayPointer();
298    boost::apply_visitor(*this,
299                         mArray->mArray);
300  }
301
302private:
303
304  XdmfArray * const mArray;
305  const unsigned int mStartIndex;
306  const T * const mValuesPointer;
307  const unsigned int mNumValues;
308  const unsigned int mArrayStride;
309  const unsigned int mValuesStride;
310  std::vector<unsigned int> & mDimensions;
311};
312
313template <>
314class XdmfArray::Insert<std::string> : public boost::static_visitor<void> {
315public:
316
317  Insert(XdmfArray * const array,
318         const unsigned int startIndex,
319         const std::string * const valuesPointer,
320         const unsigned int numValues,
321         const unsigned int arrayStride,
322         const unsigned int valuesStride,
323         std::vector<unsigned int> & dimensions) :
324    mArray(array),
325    mStartIndex(startIndex),
326    mValuesPointer(valuesPointer),
327    mNumValues(numValues),
328    mArrayStride(arrayStride),
329    mValuesStride(valuesStride),
330    mDimensions(dimensions)
331  {
332  }
333
334  void
335  operator()(const boost::blank &) const
336  {
337    mArray->initialize<std::string>();
338    boost::apply_visitor(*this,
339                         mArray->mArray);
340  }
341
342  void
343  operator()(shared_ptr<std::vector<std::string> > & array) const
344  {
345    unsigned int size = mStartIndex + (mNumValues - 1) * mArrayStride + 1;
346    if(array->size() < size) {
347      array->resize(size);
348      mDimensions.clear();
349    }
350    for(unsigned int i=0; i<mNumValues; ++i) {
351      array->operator[](mStartIndex + i*mArrayStride) =
352        mValuesPointer[i*mValuesStride].c_str();
353    }
354  }
355
356  template<typename U>
357  void
358  operator()(shared_ptr<std::vector<U> > & array) const
359  {
360    unsigned int size = mStartIndex + (mNumValues - 1) * mArrayStride + 1;
361    if(array->size() < size) {
362      array->resize(size);
363      mDimensions.clear();
364    }
365    for(unsigned int i=0; i<mNumValues; ++i) {
366      array->operator[](mStartIndex + i*mArrayStride) =
367        (U)atof(mValuesPointer[i*mValuesStride].c_str());
368    }
369  }
370
371  template<typename U>
372  void
373  operator()(boost::shared_array<const U> &) const
374  {
375    mArray->internalizeArrayPointer();
376    boost::apply_visitor(*this,
377                         mArray->mArray);
378  }
379
380private:
381
382  XdmfArray * const mArray;
383  const unsigned int mStartIndex;
384  const std::string * const mValuesPointer;
385  const unsigned int mNumValues;
386  const unsigned int mArrayStride;
387  const unsigned int mValuesStride;
388  std::vector<unsigned int> & mDimensions;
389};
390
391template <typename T>
392class XdmfArray::PushBack : public boost::static_visitor<void> {
393public:
394
395  PushBack(const T & val,
396           XdmfArray * const array) :
397    mVal(val),
398    mArray(array)
399  {
400  }
401
402  void
403  operator()(const boost::blank &) const
404  {
405    mArray->initialize<T>();
406    boost::apply_visitor(*this,
407                         mArray->mArray);
408  }
409
410  void
411  operator()(shared_ptr<std::vector<std::string> > & array) const
412  {
413    std::stringstream value;
414    value << mVal;
415    array->push_back(value.str());
416    mArray->mDimensions.clear();
417  }
418
419  template<typename U>
420  void
421  operator()(shared_ptr<std::vector<U> > & array) const
422  {
423    array->push_back((U)mVal);
424    mArray->mDimensions.clear();
425  }
426
427  template<typename U>
428  void
429  operator()(const boost::shared_array<const U> &) const
430  {
431    mArray->internalizeArrayPointer();
432    boost::apply_visitor(*this,
433                         mArray->mArray);
434  }
435
436private:
437
438  const T & mVal;
439  XdmfArray * const mArray;
440};
441
442template <>
443class XdmfArray::PushBack<std::string> : public boost::static_visitor<void> {
444public:
445
446  PushBack(const std::string & val,
447           XdmfArray * const array) :
448    mVal(val),
449    mArray(array)
450  {
451  }
452
453  void
454  operator()(const boost::blank &) const
455  {
456    mArray->initialize<std::string>();
457    boost::apply_visitor(*this,
458                         mArray->mArray);
459  }
460
461  void
462  operator()(shared_ptr<std::vector<std::string> > & array) const
463  {
464    array->push_back(mVal);
465    mArray->mDimensions.clear();
466  }
467
468  template<typename U>
469  void
470  operator()(shared_ptr<std::vector<U> > & array) const
471  {
472    array->push_back((U)atof(mVal.c_str()));
473    mArray->mDimensions.clear();
474  }
475
476  template<typename U>
477  void
478  operator()(const boost::shared_array<const U> &) const
479  {
480    mArray->internalizeArrayPointer();
481    boost::apply_visitor(*this,
482                         mArray->mArray);
483  }
484
485private:
486
487  const std::string & mVal;
488  XdmfArray * const mArray;
489};
490
491template <typename T>
492class XdmfArray::Resize : public boost::static_visitor<void> {
493public:
494
495  Resize(XdmfArray * const array,
496         const unsigned int numValues,
497         const T & val) :
498    mArray(array),
499    mNumValues(numValues),
500    mVal(val)
501  {
502  }
503
504  void
505  operator()(const boost::blank &) const
506  {
507    mArray->initialize<T>();
508    boost::apply_visitor(*this,
509                         mArray->mArray);
510  }
511
512  void
513  operator()(shared_ptr<std::vector<std::string> > & array) const
514  {
515    std::stringstream value;
516    value << mVal;
517    array->resize(mNumValues, value.str());
518    mArray->mDimensions.clear();
519  }
520
521  template<typename U>
522  void
523  operator()(shared_ptr<std::vector<U> > & array) const
524  {
525    array->resize(mNumValues, (U)mVal);
526    mArray->mDimensions.clear();
527  }
528
529  template<typename U>
530  void
531  operator()(const boost::shared_array<const U> &) const
532  {
533    mArray->internalizeArrayPointer();
534    boost::apply_visitor(*this,
535                         mArray->mArray);
536  }
537
538private:
539
540  XdmfArray * mArray;
541  const unsigned int mNumValues;
542  const T & mVal;
543};
544
545template <>
546class XdmfArray::Resize<std::string> : public boost::static_visitor<void> {
547public:
548
549  Resize(XdmfArray * const array,
550         const unsigned int numValues,
551         const std::string & val) :
552    mArray(array),
553    mNumValues(numValues),
554    mVal(val)
555  {
556  }
557
558  void
559  operator()(const boost::blank &) const
560  {
561    mArray->initialize<std::string>();
562    boost::apply_visitor(*this,
563                         mArray->mArray);
564  }
565
566  void
567  operator()(shared_ptr<std::vector<std::string> > & array) const
568  {
569    array->resize(mNumValues, mVal);
570    mArray->mDimensions.clear();
571  }
572
573  template<typename U>
574  void
575  operator()(shared_ptr<std::vector<U> > & array) const
576  {
577    array->resize(mNumValues, (U)atof(mVal.c_str()));
578    mArray->mDimensions.clear();
579  }
580
581  template<typename U>
582  void
583  operator()(const boost::shared_array<const U> &) const
584  {
585    mArray->internalizeArrayPointer();
586    boost::apply_visitor(*this,
587                         mArray->mArray);
588  }
589
590private:
591
592  XdmfArray * mArray;
593  const unsigned int mNumValues;
594  const std::string & mVal;
595};
596
597struct XdmfArray::NullDeleter
598{
599  void
600  operator()(void const *) const
601  {
602  }
603};
604
605template <typename T>
606T
607XdmfArray::getValue(const unsigned int index) const
608{
609  return boost::apply_visitor(GetValue<T>(index),
610                              mArray);
611}
612
613template <typename T>
614void
615XdmfArray::getValues(const unsigned int startIndex,
616                     T * const valuesPointer,
617                     const unsigned int numValues,
618                     const unsigned int arrayStride,
619                     const unsigned int valuesStride) const
620{
621  boost::apply_visitor(GetValues<T>(startIndex,
622                                    valuesPointer,
623                                    numValues,
624                                    arrayStride,
625                                    valuesStride),
626                       mArray);
627}
628
629template <typename T>
630shared_ptr<std::vector<T> >
631XdmfArray::getValuesInternal()
632{
633  this->internalizeArrayPointer();
634  try {
635    shared_ptr<std::vector<T> > currArray =
636      boost::get<shared_ptr<std::vector<T> > >(mArray);
637    return currArray;
638  }
639  catch(const boost::bad_get & exception) {
640    return shared_ptr<std::vector<T> >();
641  }
642}
643
644template <typename T>
645shared_ptr<std::vector<T> >
646XdmfArray::initialize(const unsigned int size)
647{
648  // Set type of variant to type of pointer
649  shared_ptr<std::vector<T> > newArray(new std::vector<T>(size));
650  if(mTmpReserveSize > 0) {
651    newArray->reserve(mTmpReserveSize);
652    mTmpReserveSize = 0;
653  }
654  mArray = newArray;
655  return newArray;
656}
657
658template <typename T>
659shared_ptr<std::vector<T> >
660XdmfArray::initialize(const std::vector<unsigned int> & dimensions)
661{
662  mDimensions = dimensions;
663  const unsigned int size = static_cast<unsigned int>(
664    std::accumulate(dimensions.begin(),
665                                            dimensions.end(),
666                                            1,
667                    std::multiplies<unsigned int>()));
668  return this->initialize<T>(size);
669}
670
671template<typename T>
672void
673XdmfArray::insert(const unsigned int index,
674                  const T & value)
675{
676  boost::apply_visitor(Insert<T>(this,
677                                 index,
678                                 &value,
679                                 1,
680                                 0,
681                                 0,
682                                 mDimensions),
683                       mArray);
684}
685
686template <typename T>
687void
688XdmfArray::insert(const unsigned int startIndex,
689                  const T * const valuesPointer,
690                  const unsigned int numValues,
691                  const unsigned int arrayStride,
692                  const unsigned int valuesStride)
693{
694  boost::apply_visitor(Insert<T>(this,
695                                 startIndex,
696                                 valuesPointer,
697                                 numValues,
698                                 arrayStride,
699                                 valuesStride,
700                                 mDimensions),
701                       mArray);
702}
703
704template <typename T>
705void
706XdmfArray::pushBack(const T & value)
707{
708  return boost::apply_visitor(PushBack<T>(value,
709                                          this),
710                              mArray);
711}
712
713template<typename T>
714void
715XdmfArray::resize(const unsigned int numValues,
716                  const T & value)
717{
718  return boost::apply_visitor(Resize<T>(this,
719                                        numValues,
720                                        value),
721                              mArray);
722  std::vector<unsigned int> newDimensions;
723  newDimensions.push_back(numValues);
724}
725
726template<typename T>
727void
728XdmfArray::resize(const std::vector<unsigned int> & dimensions,
729                  const T & value)
730{
731  const unsigned int size = static_cast<unsigned int>(
732    std::accumulate(dimensions.begin(),
733                                            dimensions.end(),
734                                            1,
735                    std::multiplies<unsigned int>()));
736  this->resize(size, value);
737  mDimensions = dimensions;
738}
739
740template <typename T>
741void
742XdmfArray::setValuesInternal(const T * const arrayPointer,
743                             const unsigned int numValues,
744                             const bool transferOwnership)
745{
746  // Remove contents of internal array.
747  if(transferOwnership) {
748    const boost::shared_array<const T> newArrayPointer(arrayPointer);
749    mArray = newArrayPointer;
750  }
751  else {
752    const boost::shared_array<const T> newArrayPointer(arrayPointer,
753                                                       NullDeleter());
754    mArray = newArrayPointer;
755  }
756  mArrayPointerNumValues = numValues;
757}
758
759template <typename T>
760void
761XdmfArray::setValuesInternal(std::vector<T> & array,
762                             const bool transferOwnership)
763{
764  if(transferOwnership) {
765    shared_ptr<std::vector<T> > newArray(&array);
766    mArray = newArray;
767  }
768  else {
769    shared_ptr<std::vector<T> > newArray(&array, NullDeleter());
770    mArray = newArray;
771  }
772}
773
774template <typename T>
775void
776XdmfArray::setValuesInternal(const shared_ptr<std::vector<T> > array)
777{
778  mArray = array;
779}
780
781template <typename T>
782bool
783XdmfArray::swap(std::vector<T> & array)
784{
785  this->internalizeArrayPointer();
786  if(!this->isInitialized()) {
787    this->initialize<T>();
788  }
789  try {
790    shared_ptr<std::vector<T> > currArray =
791      boost::get<shared_ptr<std::vector<T> > >(mArray);
792    currArray->swap(array);
793    return true;
794  }
795  catch(const boost::bad_get & exception) {
796    return false;
797  }
798}
799
800template <typename T>
801bool
802XdmfArray::swap(const shared_ptr<std::vector<T> > array)
803{
804  return this->swap(*array.get());
805}
806