CXXR (C++ R) API
FixedVector.hpp
Go to the documentation of this file.
1 /*CXXR $Id: FixedVector.hpp 1375 2013-04-15 17:16:50Z arr $
2  *CXXR
3  *CXXR This file is part of CXXR, a project to refactor the R interpreter
4  *CXXR into C++. It may consist in whole or in part of program code and
5  *CXXR documentation taken from the R project itself, incorporated into
6  *CXXR CXXR (and possibly MODIFIED) under the terms of the GNU General Public
7  *CXXR Licence.
8  *CXXR
9  *CXXR CXXR is Copyright (C) 2008-13 Andrew R. Runnalls, subject to such other
10  *CXXR copyrights and copyright restrictions as may be stated below.
11  *CXXR
12  *CXXR CXXR is not part of the R project, and bugs and other issues should
13  *CXXR not be reported via r-bugs or other R project channels; instead refer
14  *CXXR to the CXXR website.
15  *CXXR */
16 
17 /*
18  * R : A Computer Language for Statistical Data Analysis
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2.1 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28  * GNU Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, a copy is available at
32  * http://www.r-project.org/Licenses/
33  */
34 
40 #ifndef FIXEDVECTOR_HPP
41 #define FIXEDVECTOR_HPP 1
42 
43 #include <boost/aligned_storage.hpp>
44 #include <boost/serialization/nvp.hpp>
45 
46 #include "CXXR/VectorBase.h"
47 
48 namespace CXXR {
74  // (Default binding of Initializer already defined in VectorBase.h)
75  template <typename T, SEXPTYPE ST,
76  typename Initializer /* = RObject::DoNothing */>
77  class FixedVector : public VectorBase {
78  public:
79  typedef T value_type;
80  typedef T* iterator;
81  typedef const T* const_iterator;
82 
90  FixedVector(std::size_t sz)
91  : VectorBase(ST, sz), m_data(singleton())
92  {
93  if (sz > 1)
94  m_data = allocData(sz);
95  if (ElementTraits::MustConstruct<T>::value) // known at compile-time
96  constructElements(begin(), end());
97  Initializer::initialize(this);
98  }
99 
111  template <typename U>
112  FixedVector(std::size_t sz, const U& fill_value);
113 
130  template <typename V>
131  FixedVector(const V& source, size_t index)
132  : VectorBase(ST, 1), m_data(singleton())
133  {
134  new (m_data) T(source[index]);
135  Initializer::initialize(this);
136  }
137 
143 
155  template <typename FwdIter>
156  FixedVector(FwdIter from, FwdIter to);
157 
165  T& operator[](unsigned int index)
166  {
167  return m_data[index];
168  }
169 
177  const T& operator[](unsigned int index) const
178  {
179  return m_data[index];
180  }
181 
187  iterator begin()
188  {
189  return m_data;
190  }
191 
197  const_iterator begin() const
198  {
199  return m_data;
200  }
201 
207  iterator end()
208  {
209  return begin() + size();
210  }
211 
217  const_iterator end() const
218  {
219  return begin() + size();
220  }
221 
231  static const char* staticTypeName();
232 
233  // Virtual functions of VectorBase:
234  void setSize(std::size_t new_size);
235 
236  // Virtual functions of RObject:
238  const char* typeName() const;
239 
240  // Virtual function of GCNode:
241  void visitReferents(const_visitor* v) const;
242  protected:
248  {
249  if (ElementTraits::MustDestruct<T>::value) // known at compile-time
250  destructElements();
251  if (m_data != singleton())
252  MemoryBank::deallocate(m_data, size()*sizeof(T));
253  }
254 
255  // Virtual function of GCNode:
256  void detachReferents();
257  private:
258  friend class boost::serialization::access;
259 
260  T* m_data; // pointer to the vector's data block.
261 
262  // If there is only one element, it is stored here, internally
263  // to the FixedVector object, rather than via a separate
264  // allocation from CXXR::MemoryBank. We put this last, so
265  // that it will be adjacent to any trailing redzone. Note
266  // that if a FixedVector is *resized* to 1, its data is held
267  // in a separate memory block, not here.
268  boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value>
269  m_singleton_buf;
270 
271  // Not implemented yet. Declared to prevent
272  // compiler-generated versions:
273  FixedVector& operator=(const FixedVector&);
274 
275  // If there is more than one element, this function is used to
276  // allocate the required memory block from CXXR::MemoryBank :
277  static T* allocData(std::size_t sz);
278 
279  static void constructElements(iterator from, iterator to);
280 
281  void destructElements();
282 
283  // Helper function for detachReferents():
284  void detachElements();
285 
286  template<class Archive>
287  void load(Archive & ar, const unsigned int version);
288 
289  template<class Archive>
290  void save(Archive & ar, const unsigned int version) const;
291 
292  template<class Archive>
293  void serialize(Archive & ar, const unsigned int version)
294  {
295  boost::serialization::split_member(ar, *this, version);
296  }
297 
298 
299  T* singleton()
300  {
301  return static_cast<T*>(static_cast<void*>(&m_singleton_buf));
302  }
303 
304  // Helper function for visitReferents():
305  void visitElements(const_visitor* v) const;
306  };
307 } // namespace CXXR
308 
309 // ***** boost serialization object construction *****
310 
311 namespace boost {
312  namespace serialization {
340  template<class Archive, class T, SEXPTYPE ST, typename Initr>
341  void load_construct_data(Archive& ar,
343  const unsigned int version)
344  {
345  std::size_t size;
346  ar >> BOOST_SERIALIZATION_NVP(size);
347  new (t) CXXR::FixedVector<T, ST, Initr>(size);
348  }
349 
379  template<class Archive, class T, SEXPTYPE ST, typename Initr>
380  void save_construct_data(Archive& ar,
382  const unsigned int version)
383  {
384  std::size_t size = t->size();
385  ar << BOOST_SERIALIZATION_NVP(size);
386  }
387  } // namespace serialization
388 } // namespace boost
389 
390 // ***** Implementation of non-inlined members *****
391 
392 #include <algorithm>
393 #include "localization.h"
394 #include "R_ext/Error.h"
395 
396 template <typename T, SEXPTYPE ST, typename Initr>
397 template <typename U>
399  const U& fill_value)
400  : VectorBase(ST, sz), m_data(singleton())
401 {
402  if (sz > 1)
403  m_data = allocData(sz);
404  for (T *p = m_data, *pend = m_data + sz; p != pend; ++p)
405  new (p) T(fill_value);
406  Initr::initialize(this);
407 }
408 
409 template <typename T, SEXPTYPE ST, typename Initr>
411  : VectorBase(pattern), m_data(singleton())
412 {
413  std::size_t sz = size();
414  if (sz > 1)
415  m_data = allocData(sz);
416  T* p = m_data;
417  for (const_iterator it = pattern.begin(), end = pattern.end();
418  it != end; ++it)
419  new (p++) T(*it);
420  Initr::initialize(this);
421 }
422 
423 template <typename T, SEXPTYPE ST, typename Initr>
424 template <typename FwdIter>
426  : VectorBase(ST, std::distance(from, to)), m_data(singleton())
427 {
428  if (size() > 1)
429  m_data = allocData(size());
430  T* p = m_data;
431  for (const_iterator it = from; it != to; ++it)
432  new (p++) T(*it);
433  Initr::initialize(this);
434 }
435 
436 template <typename T, SEXPTYPE ST, typename Initr>
438 {
439  std::size_t blocksize = sz*sizeof(T);
440  // Check for integer overflow:
441  if (blocksize/sizeof(T) != sz)
442  Rf_error(_("request to create impossibly large vector."));
443  return static_cast<T*>(MemoryBank::allocate(blocksize));
444 }
445 
446 template <typename T, SEXPTYPE ST, typename Initr>
448 {
449  // Can't use CXXR_NEW because the comma confuses GNU cpp:
450  return expose(new FixedVector<T, ST, Initr>(*this));
451 }
452 
453 template <typename T, SEXPTYPE ST, typename Initr>
455  iterator to)
456 {
457  for (iterator p = from; p != to; ++p)
458  new (p) T;
459 }
460 
461 template <typename T, SEXPTYPE ST, typename Initr>
463 {
464  // Destroy in reverse order, following C++ convention:
465  for (T* p = m_data + size() - 1; p >= m_data; --p)
466  p->~T();
467 }
468 
469 template <typename T, SEXPTYPE ST, typename Initr>
471 {
472  std::for_each(begin(), end(), ElementTraits::DetachReferents<T>());
473 }
474 
475 template <typename T, SEXPTYPE ST, typename Initr>
477 {
478  if (ElementTraits::HasReferents<T>::value) // known at compile-time
479  detachElements();
481 }
482 
483 template <typename T, SEXPTYPE ST, typename Initr>
484 template<class Archive>
485 void CXXR::FixedVector<T, ST, Initr>::load(Archive & ar,
486  const unsigned int version)
487 {
488  ar >> BOOST_SERIALIZATION_BASE_OBJECT_NVP(VectorBase);
489 
490  size_t numnas;
491  ar >> BOOST_SERIALIZATION_NVP(numnas);
492  std::vector<unsigned int> na_indices;
493  // Fill in NAs:
494  {
495  unsigned int idx = 0;
496  for (unsigned int i = 0; i < numnas; ++i) {
497  unsigned int ii;
498  ar >> BOOST_SERIALIZATION_NVP(ii);
499  idx += ii;
500  m_data[idx] = NA<T>();
501  na_indices.push_back(idx);
502  }
503  na_indices.push_back(size());
504  }
505 
506  // Fill in non-NA values:
507  {
508  unsigned int i = 0;
509  for (std::vector<unsigned int>::const_iterator it = na_indices.begin();
510  it != na_indices.end(); ++it) {
511  unsigned int stop = *it;
512  while (i != stop) {
513  ElementTraits::Serialize<T>()(ar, m_data[i]);
514  ++i;
515  }
516  ++i; // Skip NA slot
517  }
518  }
519 }
520 
521 // A FixedVector is serialized by first recording the number of NAs
522 // (if any) and the indices of the NAs (with all but the first
523 // expressed as an increment from the previous one), followed by the
524 // payloads of the non-NA values.
525 template <typename T, SEXPTYPE ST, typename Initr>
526 template<class Archive>
527 void CXXR::FixedVector<T, ST, Initr>::save(Archive & ar,
528  const unsigned int version) const
529 {
530  ar << BOOST_SERIALIZATION_BASE_OBJECT_NVP(VectorBase);
531 
532  std::vector<unsigned int> na_indices;
533 
534  // Collect indices of NAs (if any):
535  for (unsigned int i = 0; i < size(); ++i)
536  if (isNA(m_data[i]))
537  na_indices.push_back(i);
538 
539  // Record first differences of NA indices:
540  {
541  size_t numnas = na_indices.size();
542  ar << BOOST_SERIALIZATION_NVP(numnas);
543  unsigned int last_idx = 0;
544  for (std::vector<unsigned int>::const_iterator it = na_indices.begin();
545  it != na_indices.end(); ++it) {
546  unsigned int idx = *it;
547  unsigned int ii = idx - last_idx; // ii = "index increment"
548  ar << BOOST_SERIALIZATION_NVP(ii);
549  last_idx = idx;
550  }
551  }
552 
553  // Record payloads of non-NAs:
554  for (unsigned int i = 0; i < size(); ++i)
555  if (!isNA(m_data[i]))
556  ElementTraits::Serialize<T>()(ar, m_data[i]);
557 };
558 
559 template <typename T, SEXPTYPE ST, typename Initr>
561 {
562  std::size_t copysz = std::min(size(), new_size);
563  T* newblock = singleton(); // Setting used only if new_size == 0
564  if (new_size > 0)
565  newblock = allocData(new_size);
566  // The following is essential for e.g. RHandles, otherwise they
567  // may contain junk pointers.
568  if (ElementTraits::MustConstruct<T>::value) // known at compile time
569  constructElements(newblock, newblock + copysz);
570  T* p = std::copy(begin(), begin() + copysz, newblock);
571  T* newblockend = newblock + new_size;
572  for (; p != newblockend; ++p)
573  new (p) T(NA<T>());
574  if (ElementTraits::MustDestruct<T>::value) // known at compile-time
575  destructElements();
576  if (m_data != singleton())
577  MemoryBank::deallocate(m_data, size()*sizeof(T));
578  m_data = newblock;
579  adjustSize(new_size);
580 }
581 
582 template <typename T, SEXPTYPE ST, typename Initr>
584 {
586 }
587 
588 template <typename T, SEXPTYPE ST, typename Initr>
589 void CXXR::FixedVector<T, ST, Initr>::visitElements(const_visitor* v) const
590 {
591  std::for_each(begin(), end(), ElementTraits::VisitReferents<T>(v));
592 }
593 
594 template <typename T, SEXPTYPE ST, typename Initr>
596 {
597  if (ElementTraits::HasReferents<T>::value) // known at compile-time
598  visitElements(v);
600 }
601 
602 #endif // FIXEDVECTOR_HPP