GetFEM++  5.3
bgeot_small_vector.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2000-2017 Julien Pommier
5 
6  This file is a part of GetFEM++
7 
8  GetFEM++ is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program; if not, write to the Free Software Foundation,
19  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, you may use this file as it is a part of a free
22  software library without restriction. Specifically, if other files
23  instantiate templates or use macros or inline functions from this file,
24  or you compile this file and link it with other files to produce an
25  executable, this file does not by itself cause the resulting executable
26  to be covered by the GNU Lesser General Public License. This exception
27  does not however invalidate any other reasons why the executable file
28  might be covered by the GNU Lesser General Public License.
29 
30 ===========================================================================*/
31 
32 /**@file bgeot_small_vector.h
33  @author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
34  @date January 2004.
35  @brief Small (dim < 8) vectors.
36 */
37 #ifndef BGEOT_SMALL_VECTOR_H
38 #define BGEOT_SMALL_VECTOR_H
39 
40 #include "dal_singleton.h"
41 #include "bgeot_config.h"
42 #ifdef DEBUG_SMALL_VECTOR
43 # include <cassert>
44 # define SVEC_ASSERT(x) assert(x)
45 #else
46 # define SVEC_ASSERT(x)
47 #endif
48 
49 namespace bgeot {
50 
51  class APIDECL block_allocator {
52  public:
53  typedef gmm::uint16_type uint16_type;
54  typedef gmm::uint32_type node_id;
55  typedef gmm::uint32_type size_type;
56  /* number of objects stored in a same block, power of 2 */
57  enum { p2_BLOCKSZ = 8, BLOCKSZ = 1<<p2_BLOCKSZ };
58  enum { OBJ_SIZE_LIMIT = 129 }; /* object size limit */
59  enum { MAXREF = 256 }; /* reference count limit before copying is used */
60  protected:
61  /* definition of a block (container of BLOCKSZ chunks) */
62  struct block {
63  /* effective data + reference count (stored in the BLOCKSZ first bytes) */
64  unsigned char * data;
65  /* keep track of unused chunks */
66  uint16_type first_unused_chunk, count_unused_chunk;
67  /* "pointers" for the list of free (or partially filled) blocks */
68  size_type prev_unfilled, next_unfilled;
69  size_type objsz; /* size (in bytes) of the chunks stored in this block */
70  block() : data(0) {}
71  block(size_type objsz_) : data(0),
72  prev_unfilled(size_type(-1)),
73  next_unfilled(size_type(-1)),
74  objsz(objsz_) {}
75  ~block() {} /* no cleanup of data, no copy constructor : it's on purpose
76  since the block will be moved a lot when the vector container
77  will be resized (cleanup done by ~block_allocator) */
78  void init() {
79  clear();
80  data = static_cast<unsigned char*>(::operator new(BLOCKSZ*objsz + BLOCKSZ));
81  /* first BLOCKSZ bytes are used for reference counting */
82  memset(data, 0, BLOCKSZ);
83  //cout << "init block&" << this << " allocated data: " << (void*)data << "\n";
84  }
85  void clear() {
86  //cout << "clear block&" << this << " frees data: " << (void*)data << "\n";
87  if (data) { ::operator delete(data); };
88  data = 0; first_unused_chunk = 0; count_unused_chunk = BLOCKSZ;
89  }
90  unsigned char& refcnt(size_type pos) { return data[pos]; }
91  bool empty() const { return data == 0; }
92  /* could be smarter .. */
93  };
94  /* container of all blocks .. a vector ensures fast access to
95  any element (better than deque) */
96  std::vector<block> blocks;
97  /* pointers to free (or partially free) blocks for each object size */
98  size_type first_unfilled[OBJ_SIZE_LIMIT];
99  public:
100  block_allocator();
101  ~block_allocator();
102  /* gets the data pointer for an object given its "id" */
103  void * obj_data(node_id id) {
104  return blocks[id/BLOCKSZ].data + BLOCKSZ + (id%BLOCKSZ)*blocks[id/BLOCKSZ].objsz;
105  }
106  dim_type obj_sz(node_id id) {
107  return dim_type(blocks[id/BLOCKSZ].objsz);
108  }
109  /* reference counting */
110  unsigned char& refcnt(node_id id) {
111  return blocks[id/BLOCKSZ].refcnt(id%BLOCKSZ);
112  }
113  node_id inc_ref(node_id id) {
114  if (id && ++refcnt(id) == 0) {
115  --refcnt(id);
116  id = duplicate(id);
117  }
118  return id;
119  }
120  void dec_ref(node_id id) {
121  SVEC_ASSERT(id==0 || refcnt(id));
122  if (id && --refcnt(id) == 0) {
123  ++refcnt(id);
124  deallocate(id);
125  }
126  }
127  void duplicate_if_aliased(node_id& id) {
128  if (refcnt(id) != 1) {
129  --refcnt(id);
130  id = duplicate(id); SVEC_ASSERT(id == 0 || refcnt(id)==1);
131  }
132  }
133  /* allocation of a chunk */
134  node_id allocate(block_allocator::size_type n);
135  /* deallocation of a chunk */
136  void deallocate(node_id nid);
137  void memstats();
138  protected:
139  /* won't work for non-POD types ... */
140  node_id duplicate(node_id id) {
141  node_id id2 = allocate(obj_sz(id));
142  memcpy(obj_data(id2),obj_data(id),obj_sz(id));
143  return id2;
144  }
145  void insert_block_into_unfilled(block_allocator::size_type bid);
146  void remove_block_from_unfilled(block_allocator::size_type bid);
147  };
148 
149  /* common class for all mini_vec, provides access to the common static allocator */
150  struct APIDECL static_block_allocator {
151  /* must be a pointer ... sgi CC is not able to order correctly the
152  destructors of static variables */
153  static block_allocator *palloc;
154  static_block_allocator() { if (!palloc) palloc=&dal::singleton<block_allocator,1000>::instance(); } //new block_allocator(); }
155  };
156 
157 #if !defined GETFEM_HAVE_OPENMP
158  /** container for small vectors of POD (Plain Old Data) types. Should be as fast as
159  std::vector<T> while beeing smaller and uses copy-on-write. The gain is especially
160  valuable on 64 bits architectures.
161  */
162  template<typename T> class small_vector : public static_block_allocator {
163  typedef block_allocator::node_id node_id;
164  node_id id;
165  public:
166  typedef small_vector<T> this_type;
167  typedef this_type vector_type;
168  typedef T value_type;
169  typedef T * pointer;
170  typedef const T * const_pointer;
171  typedef T& reference;
172  typedef const T & const_reference;
173  typedef T *iterator;
174  typedef const T * const_iterator;
175 
176  reference operator[](size_type l)
177  { GMM_ASSERT2(l <=size(), "out of range, l="<<l<<"size="<<size()); return base()[l]; }
178  value_type operator[](size_type l) const
179  { GMM_ASSERT2(l <= size(), "out of range, l="<<l<<"size="<<size()); return const_base()[l]; }
180  value_type at(size_type l) const { return const_base()[l]; }
181  iterator begin() { return base(); }
182  const_iterator begin() const { return const_base(); }
183  const_iterator const_begin() const { return const_base(); }
184  iterator end() { return base()+size(); }
185  const_iterator end() const { return const_base()+size(); }
186  const_iterator const_end() const { return const_base()+size(); }
187  void resize(size_type n) {
188  if (n == size()) return;
189  if (n) {
190  small_vector<T> other(n); SVEC_ASSERT(other.refcnt() == 1);
191  memcpy(other.base(), const_base(), std::min(size(),other.size())*sizeof(value_type));
192  SVEC_ASSERT(id==0 || refcnt());
193  swap(other);
194  SVEC_ASSERT(refcnt()); SVEC_ASSERT(other.id == 0 || other.refcnt());
195  } else { allocator().dec_ref(id); id=0; }
196  }
197  const small_vector<T>& operator=(const small_vector<T>& other) {
198  /* order very important when &other == this */
199  node_id id2 = allocator().inc_ref(other.id);
200  allocator().dec_ref(id); id = id2;
201  SVEC_ASSERT(id == 0 || refcnt()); SVEC_ASSERT(other.id == 0 || other.refcnt());
202  return *this;
203  }
204  void swap(small_vector<T> &v) { std::swap(id,v.id); }
205  small_vector() : id(0) {}
206  explicit small_vector(size_type n) : id(allocate(n)) {}
207  small_vector(const small_vector<T>& v) : static_block_allocator(), id(allocator().inc_ref(v.id)) {}
208  explicit small_vector(const std::vector<T>& v) : id(allocate(v.size())) {
209  std::copy(v.begin(),v.end(),begin());
210  }
211  ~small_vector() {
212  // in the wonderful world of static objects, the order of destruction
213  // can be really important when the memory allocator is destroyed
214  // before , for ex. a global variable of type small_vector...
215  // that's why there is a check on the state of the allocator..
216  if (!allocator_destroyed())
217  allocator().dec_ref(id);
218  }
219 
220  small_vector(T v1, T v2) : id(allocate(2))
221  { begin()[0] = v1; begin()[1] = v2; }
222  small_vector(T v1, T v2, T v3) : id(allocate(3))
223  { begin()[0] = v1; begin()[1] = v2; begin()[2] = v3; }
224  template<class UNOP> small_vector(const small_vector<T>& a, UNOP op)
225  : id(allocate(a.size())) { std::transform(a.begin(), a.end(), begin(), op); }
226  template<class BINOP> small_vector(const small_vector<T>& a, const small_vector<T>& b, BINOP op)
227  : id(allocate(a.size())) { std::transform(a.begin(), a.end(), b.begin(), begin(), op); }
228  bool empty() const { return id==0; }
229  unsigned char refcnt() const { return allocator().refcnt(id); }
230  dim_type size() const
231  { return dim_type(allocator().obj_sz(id)/sizeof(value_type)); }
232  small_vector<T> operator+(const small_vector<T>& other) const
233  { return small_vector<T>(*this,other,std::plus<T>()); }
234  small_vector<T> operator-(const small_vector<T>& other) const
235  { return small_vector<T>(*this,other,std::minus<T>()); }
236  small_vector<T> operator-() const
237  { return -1.*(*this); }
238  small_vector<T> operator*(T v) const
239  { return small_vector<T>(*this, std::bind2nd(std::multiplies<T>(),v)); }
240  small_vector<T> operator/(T v) const { return (*this)*(T(1)/v); }
241  small_vector<T>& operator+=(const small_vector<T>& other) {
242  const_iterator b = other.begin(); iterator it = begin();
243  for (size_type i=0; i < size(); ++i) *it++ += *b++;
244  return *this;
245  }
246  small_vector<T>& addmul(T v, const small_vector<T>& other) IS_DEPRECATED;
247  //{ std::transform(begin(), end(), other.begin(), begin(), std::plus<T>()); return *this; }
248  small_vector<T>& operator-=(const small_vector<T>& other) {
249  const_iterator b = other.begin(); iterator it = begin();
250  for (size_type i=0; i < size(); ++i) *it++ -= *b++;
251  return *this;
252  }
253  small_vector<T> operator*=(T v) { iterator it = begin(), ite=end(); while(it < ite) *it++ *= v; return *this; }
254  small_vector<T> operator/=(T v) { return operator*=(T(1)/v); }
255  bool operator<(const small_vector<T>& other) const;
256  void fill(T v) { for (iterator it=begin(); it != end(); ++it) *it = v; }
257  small_vector<T>& operator<<(T x) { push_back(x); return *this; }
258  small_vector<T>& clear() { resize(0); return *this; }
259  void push_back(T x) { resize(size()+1); begin()[size()-1] = x; }
260  size_type memsize() const { return (size()*sizeof(T) / refcnt()) + sizeof(*this); }
261  protected:
262  /* read-write access (ensures the refcount is 1) */
263  pointer base() {
264  allocator().duplicate_if_aliased(id);
265  return static_cast<pointer>(allocator().obj_data(id));
266  }
267  /* read-only access */
268  const_pointer const_base() const {
269  SVEC_ASSERT(id == 0 || refcnt()); return static_cast<pointer>(allocator().obj_data(id));
270  }
271  block_allocator& allocator() const { return *palloc; }
272  bool allocator_destroyed() const { return palloc == 0; }
273  node_id allocate(size_type n) {
274  return node_id(allocator().allocate(gmm::uint32_type(n*sizeof(value_type)))); SVEC_ASSERT(refcnt() == 1);
275  }
276  };
277 
278  template<class T> inline bool small_vector<T>::operator<(const small_vector<T>& other) const
279  {
280  return std::lexicographical_compare(begin(), end(), other.begin(), other.end());
281  }
282 
283  template<class T> inline small_vector<T>& small_vector<T>::addmul(T v, const small_vector<T>& other)
284  {
285  const_iterator b = other.begin(); iterator it = begin();
286  for (size_type i=0; i < size(); ++i) *it++ += v * *b++;
287  return *this;
288  }
289 
290 
291 #else
292 
293  /**In case of multi-threaded assembly with OpenMP using std::vector derived
294  class for it's thread safety*/
295  template<typename T> class small_vector : public std::vector<T>
296  {
297  public:
298  typedef typename std::vector<T>::const_iterator const_iterator;
299  typedef typename std::vector<T>::iterator iterator;
300 
301  const_iterator const_begin() const { return std::vector<T>::begin();}
302  const_iterator const_end() const { return std::vector<T>::end(); }
303 
304  small_vector() : std::vector<T>() {}
305 
306  explicit small_vector(size_type n) : std::vector<T>(n) {}
307 
308  small_vector(const small_vector<T>& v) : std::vector<T>(v) {}
309 
310  small_vector(const std::vector<T>& v) : std::vector<T>(v) {}
311 
312  small_vector(T v1, T v2) : std::vector<T>(2)
313  { (*this)[0] = v1; (*this)[1] = v2; }
314 
315  small_vector(T v1, T v2, T v3) : std::vector<T>(3)
316  { (*this)[0] = v1; (*this)[1] = v2; (*this)[2] = v3; }
317 
318  template<class UNOP> small_vector(const small_vector<T>& a, UNOP op)
319  : std::vector<T>(a.size())
320  { std::transform(a.begin(), a.end(), std::vector<T>::begin(), op); }
321 
322  template<class BINOP> small_vector(const small_vector<T>& a, const small_vector<T>& b, BINOP op)
323  : std::vector<T>(a.size())
324  { std::transform(a.begin(), a.end(), b.begin(), std::vector<T>::begin(), op); }
325 
326  small_vector<T> operator+(const small_vector<T>& other) const
327  { return small_vector<T>(*this,other,std::plus<T>()); }
328 
329  small_vector<T> operator-(const small_vector<T>& other) const
330  { return small_vector<T>(*this,other,std::minus<T>()); }
331 
332  small_vector<T> operator-() const
333  { return -1.*(*this); }
334 
335  small_vector<T> operator*(T v) const
336  { return small_vector<T>(*this, std::bind2nd(std::multiplies<T>(),v)); }
337 
338  small_vector<T> operator/(T v) const { return (*this)*(T(1)/v); }
339 
340  small_vector<T>& operator+=(const small_vector<T>& other)
341  {
342  const_iterator b = other.begin(); iterator it = std::vector<T>::begin();
343  for (size_type i=0; i < std::vector<T>::size(); ++i) *it++ += *b++;
344  return *this;
345  }
346 
347  small_vector<T>& addmul(T v, const small_vector<T>& other) IS_DEPRECATED;
348 
349  small_vector<T>& operator-=(const small_vector<T>& other)
350  {
351  const_iterator b = other.begin(); iterator it = std::vector<T>::begin();
352  for (size_type i=0; i < std::vector<T>::size(); ++i) *it++ -= *b++;
353  return *this;
354  }
355 
356  small_vector<T> operator*=(T v)
357  {
358  iterator it = std::vector<T>::begin(), ite=std::vector<T>::end();
359  while(it < ite) *it++ *= v;
360  return *this;
361  }
362 
363  small_vector<T> operator/=(T v) { return operator*=(T(1)/v); }
364 
365  void fill(T v) { for (iterator it=std::vector<T>::begin(); it != std::vector<T>::end(); ++it) *it = v; }
366  small_vector<T>& operator<<(T x) { push_back(x); return *this; }
367  size_type memsize() const { return (std::vector<T>::size()*sizeof(T)) + sizeof(*this); }
368  inline bool operator<(const small_vector<T>& other) const
369  {
370  return std::lexicographical_compare(std::vector<T>::begin(), std::vector<T>::end(), other.begin(), other.end());
371  }
372  };
373 
374  template<class T> inline small_vector<T>& small_vector<T>::addmul(T v, const small_vector<T>& other)
375  {
376  const_iterator b = other.begin(); iterator it = std::vector<T>::begin();
377  for (size_type i=0; i < std::vector<T>::size(); ++i) *it++ += v * *b++;
378  return *this;
379  }
380 
381 
382 #endif // #if !defined GETFEM_HAVE_OPENMP
383 
384 
385  template<class T> std::ostream& operator<<(std::ostream& os, const small_vector<T>& v) {
386  os << "["; for (size_type i=0; i < v.size(); ++i) { if (i) os << ", "; os << v[i]; }
387  os << "]"; return os;
388  }
389 
390  template<class T> inline small_vector<T> operator *(T x, const small_vector<T>& m)
391  { return m*x; }
392 
393 
394  template <class VEC_CONT>
395  void vectors_to_base_matrix(base_matrix &G, const VEC_CONT &a) {
396  size_type P = (*(a.begin())).size(), NP = a.end() - a.begin();
397  G.base_resize(P, NP);
398  typename VEC_CONT::const_iterator it = a.begin(), ite = a.end();
399  base_matrix::iterator itm = G.begin();
400  for (; it != ite; ++it, itm += P)
401  std::copy((*it).begin(), (*it).end(), itm);
402  }
403 
405  typedef base_small_vector base_node;
406 
407 }
408 
409 
410 namespace std {
411  inline void swap(bgeot::base_node& a, bgeot::base_node& b) { a.swap(b); }
412 }
413 
414 #include "gmm/gmm_interface_bgeot.h"
415 
416 #endif
container for small vectors of POD (Plain Old Data) types.
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
rational_fraction< T > operator+(const polynomial< T > &P, const rational_fraction< T > &Q)
Add Q to P.
Definition: bgeot_poly.h:750
rational_fraction< T > operator-(const polynomial< T > &P, const rational_fraction< T > &Q)
Subtract Q from P.
Definition: bgeot_poly.h:757
static T & instance()
Instance from the current thread.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
A simple singleton implementation.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
interface for bgeot::small_vector
Basic Geometric Tools.
defines and typedefs for namespace bgeot