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