GetFEM  5.4.3
bgeot_small_vector.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2000-2020 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 <[email protected]>
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  class 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  public:
155  static_block_allocator();
156  void memstats();
157  block_allocator& allocator() const;
158  bool allocator_destroyed() const;
159  void destroy();
160  };
161 
162 #ifdef GETFEM_HAS_OPENMP
163  /**In case of multi-threaded assembly with OpenMP using std::vector derived
164  class for it's thread safety*/
165  template<typename T> class small_vector : public std::vector<T>
166  {
167  public:
168  using typename std::vector<T>::const_iterator;
169  using typename std::vector<T>::iterator;
170  const_iterator begin() const { return std::vector<T>::begin(); }
171  iterator begin() { return std::vector<T>::begin(); }
172  const_iterator end() const { return std::vector<T>::end(); }
173  iterator end() { return std::vector<T>::end(); }
174 
175  const_iterator const_begin() const { return std::vector<T>::cbegin(); }
176  const_iterator const_end() const { return std::vector<T>::cend(); }
177  dim_type size() const { return dim_type(std::vector<T>::size()); }
178 
179  const small_vector<T>& operator=(const small_vector<T>& other) {
180  std::vector<T>::operator=(other);
181  return *this;
182  }
183 
184  small_vector() : std::vector<T>() {}
185 
186  explicit small_vector(size_type n) : std::vector<T>(n) {}
187 
188  small_vector(const small_vector<T>& v) : std::vector<T>(v) {}
189 
190  small_vector(const std::vector<T>& v) : std::vector<T>(v) {}
191 
192  small_vector(T v1, T v2) : std::vector<T>(2)
193  { (*this)[0] = v1; (*this)[1] = v2; }
194 
195  small_vector(T v1, T v2, T v3) : std::vector<T>(3)
196  { (*this)[0] = v1; (*this)[1] = v2; (*this)[2] = v3; }
197 
198  template<class UNOP> small_vector(const small_vector<T>& a, UNOP op)
199  : std::vector<T>(a.size())
200  { std::transform(a.begin(), a.end(), begin(), op); }
201 
202  template<class BINOP> small_vector(const small_vector<T>& a, const small_vector<T>& b, BINOP op)
203  : std::vector<T>(a.size())
204  { std::transform(a.begin(), a.end(), b.begin(), begin(), op); }
205 #else
206  /** container for small vectors of POD (Plain Old Data) types. Should be as fast as
207  std::vector<T> while beeing smaller and uses copy-on-write. The gain is especially
208  valuable on 64 bits architectures.
209  */
210  template<typename T> class small_vector : public static_block_allocator {
211  typedef block_allocator::node_id node_id;
212  node_id id;
213  public:
214  typedef small_vector<T> this_type;
215  typedef this_type vector_type;
216  typedef T value_type;
217  typedef T * pointer;
218  typedef const T * const_pointer;
219  typedef T& reference;
220  typedef const T & const_reference;
221  typedef T *iterator;
222  typedef const T * const_iterator;
223 
224  reference operator[](size_type l)
225  { GMM_ASSERT2(l <=size(), "out of range, l="<<l<<"size="<<size()); return base()[l]; }
226  value_type operator[](size_type l) const
227  { GMM_ASSERT2(l <= size(), "out of range, l="<<l<<"size="<<size()); return const_base()[l]; }
228  value_type at(size_type l) const { return const_base()[l]; }
229  iterator begin() { return base(); }
230  const_iterator begin() const { return const_base(); }
231  const_iterator const_begin() const { return const_base(); }
232  iterator end() { return base()+size(); }
233  const_iterator end() const { return const_base()+size(); }
234  const_iterator const_end() const { return const_base()+size(); }
235  void resize(size_type n) {
236  if (n == size()) return;
237  if (n) {
238  small_vector<T> other(n); SVEC_ASSERT(other.refcnt() == 1);
239  memcpy(other.base(), const_base(), std::min(size(),other.size())*sizeof(value_type));
240  SVEC_ASSERT(id==0 || refcnt());
241  swap(other);
242  SVEC_ASSERT(refcnt()); SVEC_ASSERT(other.id == 0 || other.refcnt());
243  } else { allocator().dec_ref(id); id=0; }
244  }
245  const small_vector<T>& operator=(const small_vector<T>& other) {
246  /* order very important when &other == this */
247  node_id id2 = allocator().inc_ref(other.id);
248  allocator().dec_ref(id); id = id2;
249  SVEC_ASSERT(id == 0 || refcnt()); SVEC_ASSERT(other.id == 0 || other.refcnt());
250  return *this;
251  }
252  void swap(small_vector<T> &v) { std::swap(id,v.id); }
253  small_vector() : id(0) {}
254  explicit small_vector(size_type n) : id(allocate(n)) {}
255  small_vector(const small_vector<T>& v) : static_block_allocator(), id(allocator().inc_ref(v.id)) {}
256  explicit small_vector(const std::vector<T>& v) : id(allocate(v.size())) {
257  std::copy(v.begin(),v.end(),begin());
258  }
259  ~small_vector() {
260  // in the wonderful world of static objects, the order of destruction
261  // can be really important when the memory allocator is destroyed
262  // before , for ex. a global variable of type small_vector...
263  // that's why there is a check on the state of the allocator..
264  if (!allocator_destroyed())
265  allocator().dec_ref(id);
266  }
267 
268  small_vector(T v1, T v2) : id(allocate(2))
269  { begin()[0] = v1; begin()[1] = v2; }
270  small_vector(T v1, T v2, T v3) : id(allocate(3))
271  { begin()[0] = v1; begin()[1] = v2; begin()[2] = v3; }
272  template<class UNOP> small_vector(const small_vector<T>& a, UNOP op)
273  : id(allocate(a.size())) { std::transform(a.begin(), a.end(), begin(), op); }
274  template<class BINOP> small_vector(const small_vector<T>& a, const small_vector<T>& b, BINOP op)
275  : id(allocate(a.size())) { std::transform(a.begin(), a.end(), b.begin(), begin(), op); }
276  bool empty() const { return id==0; }
277  unsigned char refcnt() const { return allocator().refcnt(id); }
278  dim_type size() const
279  { return dim_type(allocator().obj_sz(id)/sizeof(value_type)); }
280 #endif
281 
282  small_vector<T> operator+(const small_vector<T>& other) const
283  { return small_vector<T>(*this,other,std::plus<T>()); }
284 
285  small_vector<T> operator-(const small_vector<T>& other) const
286  { return small_vector<T>(*this,other,std::minus<T>()); }
287 
288  small_vector<T> operator-() const
289  { return -1.*(*this); }
290 
291  small_vector<T> operator*(T v) const
292  {return small_vector<T>(*this, [&v](const auto &x) {return v * x;});}
293 
294  small_vector<T> operator/(T v) const { return (*this)*(T(1)/v); }
295  small_vector<T>& operator+=(const small_vector<T>& other) {
296  const_iterator b = other.begin(); iterator it = begin();
297  for (size_type i=0; i < size(); ++i) *it++ += *b++;
298  return *this;
299  }
300 
301  small_vector<T>& addmul(T v, const small_vector<T>& other) IS_DEPRECATED;
302  //{ std::transform(begin(), end(), other.begin(), begin(), std::plus<T>()); return *this; }
303  small_vector<T>& operator-=(const small_vector<T>& other) {
304  const_iterator b = other.begin(); iterator it = begin();
305  for (size_type i=0; i < size(); ++i) *it++ -= *b++;
306  return *this;
307  }
308 
309  small_vector<T> operator*=(T v) {
310  iterator it = begin(), ite=end();
311  while(it < ite) *it++ *= v;
312  return *this;
313  }
314  small_vector<T> operator/=(T v) { return operator*=(T(1)/v); }
315  inline bool operator<(const small_vector<T>& other) const
316  {
317  return std::lexicographical_compare(begin(), end(), other.begin(), other.end());
318  }
319  void fill(T v) { for (iterator it=begin(); it != end(); ++it) *it = v; }
320  small_vector<T>& operator<<(T x) { push_back(x); return *this; }
321 #ifdef GETFEM_HAS_OPENMP
322  size_type memsize() const { return (size()*sizeof(T)) + sizeof(*this); }
323 #else
324  size_type memsize() const { return (size()*sizeof(T) / refcnt()) + sizeof(*this); }
325  small_vector<T>& clear() { resize(0); return *this; }
326  void push_back(T x) { resize(size()+1); begin()[size()-1] = x; }
327  protected:
328  /* read-write access (ensures the refcount is 1) */
329  pointer base() {
330  allocator().duplicate_if_aliased(id);
331  return static_cast<pointer>(allocator().obj_data(id));
332  }
333  /* read-only access */
334  const_pointer const_base() const {
335  SVEC_ASSERT(id == 0 || refcnt()); return static_cast<pointer>(allocator().obj_data(id));
336  }
337  node_id allocate(size_type n) {
338  return node_id(allocator().allocate(gmm::uint32_type(n*sizeof(value_type)))); SVEC_ASSERT(refcnt() == 1);
339  }
340 #endif
341  };
342 
343  template<class T> inline small_vector<T>& small_vector<T>::addmul(T v, const small_vector<T>& other)
344  {
345  const_iterator b = other.begin(); iterator it = begin();
346  for (size_type i=0; i < size(); ++i) *it++ += v * *b++;
347  return *this;
348  }
349 
350 
351  template<class T> std::ostream& operator<<(std::ostream& os, const small_vector<T>& v) {
352  os << "["; for (size_type i=0; i < v.size(); ++i) { if (i) os << ", "; os << v[i]; }
353  os << "]"; return os;
354  }
355 
356  template<class T> inline small_vector<T> operator *(T x, const small_vector<T>& m)
357  { return m*x; }
358 
359 
360  template <class VEC_CONT>
361  void vectors_to_base_matrix(base_matrix &G, const VEC_CONT &a) {
362  size_type P = (*(a.begin())).size(), NP = a.end() - a.begin();
363  G.base_resize(P, NP);
364  typename VEC_CONT::const_iterator it = a.begin(), ite = a.end();
365  base_matrix::iterator itm = G.begin();
366  for (; it != ite; ++it, itm += P)
367  std::copy((*it).begin(), (*it).end(), itm);
368  }
369 
370  typedef small_vector<scalar_type> base_small_vector;
371  typedef base_small_vector base_node;
372 
373 }
374 
375 
376 namespace std {
377  inline void swap(bgeot::base_node& a, bgeot::base_node& b) { a.swap(b); }
378 }
379 
380 #include "gmm/gmm_interface_bgeot.h"
381 
382 #endif
defines and typedefs for namespace bgeot
container for small vectors of POD (Plain Old Data) types.
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.
rational_fraction< T > operator-(const polynomial< T > &P, const rational_fraction< T > &Q)
Subtract Q from P.
Definition: bgeot_poly.h:756
rational_fraction< T > operator+(const polynomial< T > &P, const rational_fraction< T > &Q)
Add Q to P.
Definition: bgeot_poly.h:749
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49