source: git/Singular/countedref.h @ d1fbbf

jengelh-datetimespielwiese
Last change on this file since d1fbbf was d1fbbf, checked in by Alexander Dreyer <alexander.dreyer@…>, 11 years ago
Making autoloading of 'reference' and 'shared' customizable new Added configure option chg Explained more generic CountedRef::is_ref(leftv)
  • Property mode set to 100644
File size: 12.8 KB
Line 
1/// -*- c++ -*-
2//*****************************************************************************
3/** @file countedref.h
4 *
5 * @author Alexander Dreyer
6 * @date 2012-08-15
7 *
8 * This file defines reusable classes supporting reference counted interpreter
9 * objects and initiates the @c blackbox operations for high-level types
10 * 'reference' and 'shared'.
11 *
12 * @note This works was supported by the "Industrial Algebra" project.
13 *
14 * @par Copyright:
15 *   (c) 2012 by The Singular Team, see LICENSE file
16**/
17//*****************************************************************************
18
19
20#ifndef SINGULAR_COUNTEDREF_H_
21#define SINGULAR_COUNTEDREF_H_
22
23#include <omalloc/omalloc.h>
24#include <kernel/structs.h>
25#include <kernel/febase.h>
26#include "subexpr.h"
27#include "idrec.h"
28#include "ipid.h"
29/** @class CountedRefPtr
30 * This class implements a smart pointer which handles pointer-style access
31 * to a reference-counted structure and destructing the latter after use.
32 *
33 * The template arguments, include the pointer type @c PtrType, and two
34 * integral (bool) properties: use @c Nondestructive to disallow destruction
35 * and @c NeverNull to assume, that @c PtrType cannot be @c NULL.
36 * Finally, @c CountType allows you to select a typ to represent the internal reference count.
37 *
38 * @note The class of @c PtrType must have an accessible integral attribute @c ref.
39 * For convenience use @c RefCounter as public base.
40 * In addition you must overload @c void CountedRefPtr_kill(PtrType) accordingly.
41 **/
42template <class PtrType, bool Nondestructive = false, bool NeverNull = false,
43          class CountType = short>
44class CountedRefPtr {
45  typedef CountedRefPtr self;
46
47public:
48  //{ @name Name template arguments
49  typedef PtrType ptr_type;
50  typedef CountType count_type;
51  enum { nondestructive = Nondestructive, never_null = NeverNull };
52  //}
53
54  /// Default constructor @note: exisis only if @c NeverNull is false
55  CountedRefPtr(): m_ptr(NULL) {}
56
57  /// Convert from pointer
58  CountedRefPtr(ptr_type ptr): m_ptr(ptr) { reclaim(); }
59
60  /// Convert from compatible smart pointer
61  template <bool Never>
62  CountedRefPtr(const CountedRefPtr<ptr_type, !nondestructive, Never, count_type>& rhs):
63    m_ptr(rhs.m_ptr) { reclaim(); }
64
65  /// Construct refernce copy
66  CountedRefPtr(const self& rhs):
67    m_ptr(rhs.m_ptr) { reclaim(); }
68
69  /// Unlink one reference
70  ~CountedRefPtr() { release(); }
71
72  //{ @name Replace data behind reference
73  self& operator=(const self& rhs) { return operator=(rhs.m_ptr); }
74  self& operator=(ptr_type ptr) {
75    release();
76    m_ptr = ptr;
77    reclaim();
78    return *this;
79  }
80  //}
81
82  /// Checking equality
83  bool operator==(const self& rhs) const { return m_ptr == rhs.m_ptr; }
84
85  //{ @name Pointer-style interface
86  bool operator==(ptr_type ptr) const { return m_ptr == ptr; }
87  operator bool() const { return NeverNull || m_ptr; }
88  operator const ptr_type() const { return m_ptr; }
89  operator ptr_type() { return m_ptr; }
90  const ptr_type operator->() const { return *this; }
91  ptr_type operator->() { return *this; }
92  //}
93
94  /// @name Reference count interface
95  //@{
96  count_type count() const { return (*this? m_ptr->ref: 0); }
97  void reclaim() { if (*this) ++m_ptr->ref; }
98  void release() { 
99    if (*this && (--m_ptr->ref <= 0) && !nondestructive)
100      CountedRefPtr_kill(m_ptr); 
101  }
102  //@}
103
104private:
105  /// Store actual pointer
106  ptr_type m_ptr;
107};
108
109/** @class RefCounter
110 * This class implements implements a refernce counter which we can use
111 * as a public base of objects managed by @CountedRefPtr.
112 **/
113class RefCounter {
114
115public:
116  /// Name numerical type for enumbering
117  typedef short count_type;
118
119  /// Allow our smart pointer to access internals
120  template <class, bool, bool, class> friend class CountedRefPtr;
121
122  /// Any Constructor resets the counter
123  RefCounter(...): ref(0) {}
124
125  /// Destructor
126  ~RefCounter() { assume(ref == 0); }
127
128private:
129  /// Number of references
130  count_type ref;  // naming consistent with other classes
131};
132
133
134template <class PtrType>
135class CountedRefWeakPtr;
136
137template <class PtrType>
138class CountedRefIndirectPtr: 
139  public RefCounter {
140public:
141  friend class CountedRefWeakPtr<PtrType>;
142  ~CountedRefIndirectPtr()  { }
143
144private:
145  CountedRefIndirectPtr(PtrType ptr): m_ptr(ptr) { }
146  CountedRefIndirectPtr& operator=(PtrType ptr) { m_ptr = ptr; return *this; }
147
148  PtrType m_ptr;
149};
150
151template <class PtrType> 
152inline void CountedRefPtr_kill(CountedRefIndirectPtr<PtrType>* pval) { delete pval; }
153
154template <class PtrType>
155class CountedRefWeakPtr {
156  typedef CountedRefWeakPtr self;
157
158public:
159
160  /// @name Name template arguments
161  //@{ Name template arguments
162  typedef PtrType ptr_type;
163  typedef CountedRefPtr<CountedRefIndirectPtr<ptr_type>*> ptrptr_type;
164  //@}
165
166  /// Construct unassigned weak reference
167  CountedRefWeakPtr(): m_indirect(NULL) { }
168
169  /// Convert from pointer
170  CountedRefWeakPtr(ptr_type ptr): m_indirect(new CountedRefIndirectPtr<ptr_type>(ptr)) { }
171
172  /// Construct copy
173  CountedRefWeakPtr(const self& rhs):  m_indirect(rhs.m_indirect) { }
174
175  /// Unlink one reference (handled by CountedRefPtr)
176  ~CountedRefWeakPtr() { }
177
178  /// Mark weak reference as invalid
179  void invalidate() {  *this = NULL; }
180
181  /// Test whether reference was never used
182  bool unassigned() const { return !m_indirect; }
183  /// Pointer-style interface
184  //@{
185  operator bool() const {  return operator->(); }
186  self& operator=(const self& rhs) { 
187    m_indirect = rhs.m_indirect;
188    return *this;
189  }
190  self& operator=(ptr_type ptr) {
191    if (!m_indirect) 
192      m_indirect = new CountedRefIndirectPtr<ptr_type>(ptr);
193    else
194      m_indirect->m_ptr = ptr;
195    return *this;
196  }
197  bool operator==(ptr_type ptr) const {
198    return m_indirect &&(m_indirect->m_ptr == ptr);
199  }
200  bool operator!=(ptr_type rhs) const { return !operator==(rhs); }
201  const ptr_type operator->() const { return (m_indirect? m_indirect->m_ptr: NULL); }
202  ptr_type operator->() {   return (m_indirect? m_indirect->m_ptr:NULL); }
203  //@}
204private:
205  ptrptr_type m_indirect;
206};
207
208
209
210/** @class LeftvHelper
211 * This class implements some recurrent code sniplets to be used with
212 * @c leftv and @c idhdl.implements a refernce counter which we can use
213 **/
214class LeftvHelper {
215public:
216  static leftv idify(leftv head, idhdl* root) {
217    idhdl handle = newid(head, root);
218    leftv res = (leftv)omAlloc0(sizeof(*res));
219    res->data =(void*) handle;
220    res->rtyp = IDHDL;
221    return res;
222  }
223
224  static idhdl newid(leftv head, idhdl* root) {
225
226    static unsigned int counter = 0;
227    char* name = (char*) omAlloc0(512);
228    sprintf(name, " :%u:%p:_shared_: ", ++counter, head->data);
229    if ((*root) == NULL )
230      enterid(name, 0, head->rtyp, root, TRUE, FALSE);
231    else
232      *root = (*root)->set(name, 0, head->rtyp, TRUE);
233
234    IDDATA(*root) = (char*) head->data;
235    return *root;
236  }
237
238  static void clearid(idhdl handle, idhdl* root) {
239    IDDATA(handle)=NULL;
240    IDTYP(handle)=NONE;
241    killhdl2(handle, root, NULL);
242  }
243
244  template <class Type>
245  static Type* cpy(Type* result, Type* data)  {
246    return (Type*)memcpy(result, data, sizeof(Type));
247  }
248  template <class Type>
249  static Type* cpy(Type* data)  {
250    return cpy((Type*)omAlloc0(sizeof(Type)), data);
251  }
252  template <class Type>
253  static Type* recursivecpy(Type* data)  {
254    if (data == NULL) return data;
255    Type* result = cpy(data);
256    result->next = recursivecpy(data->next);
257    return result;
258  }
259  template <class Type>
260  static Type* shallowcpy(Type* result, Type* data)  {
261    cpy(result, data)->e = recursivecpy(data->e);
262    return result;
263  }
264  template <class Type>
265  static Type* shallowcpy(Type* data)  {
266    return shallowcpy((Type*) omAlloc0(sizeof(Type)), data);
267  }
268  template <class Type>
269  static void recursivekill(Type* current) {
270    if(current == NULL) return;
271    recursivekill(current->next);
272    omFree(current);
273  }
274  static leftv allocate() { return (leftv)omAlloc0(sizeof(sleftv)); }
275
276};
277
278/** @class LeftvShallow
279 * Ths class wraps @c leftv by taking into acount memory allocation, destruction
280 * as well as shallowly copying of a given @c leftv, i.e. we just copy auxiliary
281 * information (like subexpressions), but not the actual data.
282 *
283 * @note This is useful to avoid invalidating @c leftv while operating on th
284 **/
285class LeftvShallow:
286  public LeftvHelper {
287  typedef LeftvShallow self;
288 
289public:
290  /// Just allocate (all-zero) @c leftv
291  LeftvShallow(): m_data(allocate()) { }
292  /// Shallow copy the input data
293  LeftvShallow(leftv data): m_data(shallowcpy(data)) { }
294  /// Construct (shallow) copy of @c *this
295  LeftvShallow(const self& rhs):  m_data(shallowcpy(rhs.m_data)) { }
296
297  /// Destruct
298  ~LeftvShallow() { 
299    recursivekill(m_data->e);
300    omFree(m_data);
301  }
302
303  /// Assign shallow copy of the input
304  self& operator=(leftv rhs) {
305    recursivekill(m_data->e);
306    shallowcpy(m_data, rhs);
307    return *this;
308  }
309  /// Assign (shallow) copy of @c *this
310  self& operator=(const self& rhs) { return (*this) = rhs.m_data; }
311
312  /// @name Pointer-style access
313  //@{
314  const leftv operator->() const { return m_data;  }
315  leftv operator->() { return m_data;  }
316  //@]
317
318protected:
319  /// The actual data pointer
320  leftv m_data;
321};
322
323/** @class LeftvDeep
324 * This class wraps @c leftv by taking into acount memory allocation, destruction
325 * as well as deeply copying of a given @c leftv, i.e. we also take over
326 * ownership of the @c leftv data.
327 *
328 * We have two variants:
329   + LeftvDeep(leftv):           treats referenced identifiers as "the data"
330   + LeftvDeep(leftv, copy_tag): takes care of a full copy of identifier's data
331 *
332 * @note It invalidats @c leftv on input.
333 **/
334class LeftvDeep: 
335  public LeftvHelper {
336  typedef LeftvDeep self;
337
338  /// @name Do not permit copying (avoid inconsistence)
339  //@{
340  self& operator=(const self&);
341  LeftvDeep(const self&);
342  //@}
343
344public:
345  /// Allocate all-zero object by default
346  LeftvDeep(): m_data(allocate()) {}
347
348  /// Store a deep copy of the data
349  /// @ note Occupies the provided @c leftv and invalidates the latter
350  LeftvDeep(leftv data): m_data(cpy(data)) { 
351    data->e = NULL;   // occupy subexpression
352    if(!isid()) m_data->data=data->CopyD(); 
353  }
354
355  /// Construct even deeper copy:
356  /// Skip identifier (if any) and take care of the data on our own
357  struct copy_tag {};
358  LeftvDeep(leftv data, copy_tag): m_data(allocate()) {  m_data->Copy(data);  }
359
360  /// Really clear data
361  ~LeftvDeep() { m_data->CleanUp(); }
362
363  /// @name Access via shallow copy to avoid invalidating the stored handle
364  //@{
365  operator LeftvShallow() { return m_data; }
366  LeftvShallow operator*() {return *this; }
367  //@}
368
369  /// Determine whether we point to the same data
370  bool like(const self& rhs) const { return m_data->data == rhs.m_data->data; }
371
372  /// Reassign a new deep copy by occupieing another @c leftv
373  /// @note clears @c *this in the first
374  self& operator=(leftv rhs) {
375    if(isid()) {
376      m_data->e = rhs->e;
377      rhs->e = NULL;
378      IDTYP((idhdl)m_data->data) =  rhs->Typ();
379      IDDATA((idhdl)m_data->data) = (char*) rhs->CopyD();
380    }
381    else {
382      m_data->CleanUp();
383      m_data->Copy(rhs);
384    }
385    return *this;
386  }
387
388  /// Check a given context for our identifier
389  BOOLEAN brokenid(idhdl context) const {
390    assume(isid());
391    return (context == NULL) || 
392      ((context != (idhdl) m_data->data) && brokenid(IDNEXT(context)));
393  }
394
395  /// Put a shallow copy to given @c leftv
396  BOOLEAN put(leftv result) {
397    leftv next = result->next;
398    result->next = NULL;
399    result->CleanUp();
400
401    shallowcpy(result, m_data);
402    result->next = next;
403    return FALSE;
404  }
405
406  /// Get additional data (e.g. subexpression data) from likewise instances
407  BOOLEAN retrieve(leftv res) {
408    if (res->data == m_data->data)  {
409      if(m_data->e != res->e) recursivekill(m_data->e);
410      cpy(m_data, res);
411      res->Init();
412      return TRUE;
413    }
414    return FALSE;
415  }
416
417
418  /// Check for being an identifier
419  BOOLEAN isid() const { return m_data->rtyp==IDHDL;}
420  /// Test whether we reference to ring-dependent data
421  BOOLEAN ringed() { return m_data->RingDependend(); }
422  /// Check whether (all-zero) initialized data was never assigned.
423  BOOLEAN unassigned() const { return m_data->Typ()==0; }
424
425  /// Wrap data by identifier, if not done yet
426  leftv idify(idhdl* root) {
427    leftv res = (isid()? m_data: LeftvHelper::idify(m_data, root));
428    ++(((idhdl)res->data)->ref);
429    return res;
430  }
431
432  /// Erase identifier handles by @c *this
433  /// @note Assumes that we reference an identifier and that we own the latter.
434  /// This is useful to clear the result of a subsequent call of @c idify.
435  void clearid(idhdl* root) {
436    assume(isid());
437    if (--((idhdl)m_data->data)->ref <= 0)  // clear only if we own
438      LeftvHelper::clearid((idhdl)m_data->data, root);
439  }
440
441private:
442  /// Store the actual data
443  leftv m_data;
444};
445
446/// Initialize @c blackbox types 'reference' and 'shared', or both
447void countedref_reference_load();
448void countedref_shared_load();
449
450inline void
451countedref_init()
452{
453  countedref_reference_load();
454  countedref_shared_load();
455}
456
457
458#endif /*SINGULAR_COUNTEDREF_H_ */
459
Note: See TracBrowser for help on using the repository browser.