countedref.h
Go to the documentation of this file.
1 // -*- c++ -*-
2 //*****************************************************************************
3 /** @file countedref.h
4  *
5  * This file defines reusable classes supporting reference counted interpreter
6  * objects and initiates the @c blackbox operations for high-level types
7  * 'reference' and 'shared'.
8  *
9  * @note This works was supported by the "Industrial Algebra" project.
10  *
11  * @author Alexander Dreyer
12  * @date 2012-08-15
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 <Singular/subexpr.h>
26 #include <Singular/idrec.h>
27 #include <Singular/ipid.h>
28 /** @class CountedRefPtr
29  * This class implements a smart pointer which handles pointer-style access
30  * to a reference-counted structure and destructing the latter after use.
31  *
32  * The template arguments, include the pointer type @c PtrType, and two
33  * integral (bool) properties: use @c Nondestructive to disallow destruction
34  * and @c NeverNull to assume, that @c PtrType cannot be @c NULL.
35  * Finally, @c CountType allows you to select a typ to represent the internal reference count.
36  *
37  * @note The class of @c PtrType must have an accessible integral attribute @c ref.
38  * For convenience use @c RefCounter as public base.
39  * In addition you must overload @c void CountedRefPtr_kill(PtrType) accordingly.
40  **/
41 template <class PtrType, bool Nondestructive = false, bool NeverNull = false,
42  class CountType = short>
44  typedef CountedRefPtr self;
45 
46 public:
47  //{ @name Name template arguments
48  typedef PtrType ptr_type;
49  typedef CountType count_type;
50  enum { nondestructive = Nondestructive, never_null = NeverNull };
51  //}
52 
53  /// Default constructor @note: exisis only if @c NeverNull is false
55 
56  /// Convert from pointer
57  CountedRefPtr(ptr_type ptr): m_ptr(ptr) { reclaim(); }
58 
59  /// Convert from compatible smart pointer
60  template <bool Never>
62  m_ptr(rhs.m_ptr) { reclaim(); }
63 
64  /// Construct refernce copy
65  CountedRefPtr(const self& rhs):
66  m_ptr(rhs.m_ptr) { reclaim(); }
67 
68  /// Unlink one reference
70 
71  //{ @name Replace data behind reference
72  self& operator=(const self& rhs) { return operator=(rhs.m_ptr); }
73  self& operator=(ptr_type ptr) {
74  release();
75  m_ptr = ptr;
76  reclaim();
77  return *this;
78  }
79  //}
80 
81  /// Checking equality
82  bool operator==(const self& rhs) const { return m_ptr == rhs.m_ptr; }
83 
84  //{ @name Pointer-style interface
85  bool operator==(ptr_type ptr) const { return m_ptr == ptr; }
86  operator bool() const { return NeverNull || m_ptr; }
87  operator const ptr_type() const { return m_ptr; }
88  operator ptr_type() { return m_ptr; }
89  const ptr_type operator->() const { return *this; }
90  ptr_type operator->() { return *this; }
91  //}
92 
93  /// @name Reference count interface
94  //@{
95  count_type count() const { return (*this? m_ptr->ref: 0); }
96  void reclaim() { if (*this) ++m_ptr->ref; }
97  void release() {
98  if (*this && (--m_ptr->ref <= 0) && !nondestructive)
100  }
101  //@}
102 
103 private:
104  /// Store actual pointer
105  ptr_type m_ptr;
106 };
107 
108 /** @class RefCounter
109  * This class implements implements a refernce counter which we can use
110  * as a public base of objects managed by @CountedRefPtr.
111  **/
112 class RefCounter {
113 
114 public:
115  /// Name numerical type for enumbering
116  typedef short count_type;
117 
118  /// Allow our smart pointer to access internals
119  template <class, bool, bool, class> friend class CountedRefPtr;
120 
121  /// Any Constructor resets the counter
122  RefCounter(...): ref(0) {}
123 
124  /// Destructor
125  ~RefCounter() { assume(ref == 0); }
126 
127 private:
128  /// Number of references
129  count_type ref; // naming consistent with other classes
130 };
131 
132 
133 template <class PtrType>
135 
136 template <class PtrType>
138  public RefCounter {
139 public:
140  friend class CountedRefWeakPtr<PtrType>;
142 
143 private:
144  CountedRefIndirectPtr(PtrType ptr): m_ptr(ptr) { }
145  CountedRefIndirectPtr& operator=(PtrType ptr) { m_ptr = ptr; return *this; }
146 
147  PtrType m_ptr;
148 };
149 
150 template <class PtrType>
151 inline void CountedRefPtr_kill(CountedRefIndirectPtr<PtrType>* pval) { delete pval; }
152 
153 template <class PtrType>
154 class CountedRefWeakPtr {
155  typedef CountedRefWeakPtr self;
156 
157 public:
158 
159  /// @name Name template arguments
160  //@{ Name template arguments
161  typedef PtrType ptr_type;
163  //@}
164 
165  /// Construct unassigned weak reference
166  CountedRefWeakPtr(): m_indirect(NULL) { }
167 
168  /// Convert from pointer
169  CountedRefWeakPtr(ptr_type ptr): m_indirect(new CountedRefIndirectPtr<ptr_type>(ptr)) { }
170 
171  /// Construct copy
172  CountedRefWeakPtr(const self& rhs): m_indirect(rhs.m_indirect) { }
173 
174  /// Unlink one reference (handled by CountedRefPtr)
176 
177  /// Mark weak reference as invalid
178  void invalidate() { *this = NULL; }
179 
180  /// Test whether reference was never used
181  bool unassigned() const { return !m_indirect; }
182  /// Pointer-style interface
183  //@{
184  operator bool() const { return operator->(); }
185  self& operator=(const self& rhs) {
186  m_indirect = rhs.m_indirect;
187  return *this;
188  }
189  self& operator=(ptr_type ptr) {
190  if (!m_indirect)
191  m_indirect = new CountedRefIndirectPtr<ptr_type>(ptr);
192  else
193  m_indirect->m_ptr = ptr;
194  return *this;
195  }
196  bool operator==(ptr_type ptr) const {
197  return m_indirect &&(m_indirect->m_ptr == ptr);
198  }
199  bool operator!=(ptr_type rhs) const { return !operator==(rhs); }
200  const ptr_type operator->() const { return (m_indirect? m_indirect->m_ptr: NULL); }
201  ptr_type operator->() { return (m_indirect? m_indirect->m_ptr:NULL); }
202  //@}
203 private:
204  ptrptr_type m_indirect;
205 };
206 
207 
208 
209 /** @class LeftvHelper
210  * This class implements some recurrent code sniplets to be used with
211  * @c leftv and @c idhdl.implements a refernce counter which we can use
212  **/
213 class LeftvHelper {
214 public:
215  static leftv idify(leftv head, idhdl* root) {
216  idhdl handle = newid(head, root);
217  leftv res = (leftv)omAlloc0(sizeof(*res));
218  res->data =(void*) handle;
219  res->rtyp = IDHDL;
220  return res;
221  }
222 
223  static idhdl newid(leftv head, idhdl* root) {
224 
225  static unsigned int counter = 0;
226  char* name = (char*) omAlloc0(512);
227  sprintf(name, " :%u:%p:_shared_: ", ++counter, head->data);
228  if ((*root) == NULL )
229  enterid(name, 0, head->rtyp, root, TRUE, FALSE);
230  else
231  *root = (*root)->set(name, 0, head->rtyp, TRUE);
232 
233  IDDATA(*root) = (char*) head->data;
234  return *root;
235  }
236 
237  static void clearid(idhdl handle, idhdl* root) {
238  IDDATA(handle)=NULL;
239  IDTYP(handle)=NONE;
240  killhdl2(handle, root, NULL);
241  }
242 
243  template <class Type>
244  static Type* cpy(Type* result, Type* data) {
245  return (Type*)memcpy(result, data, sizeof(Type));
246  }
247  template <class Type>
248  static Type* cpy(Type* data) {
249  return cpy((Type*)omAlloc0(sizeof(Type)), data);
250  }
251  template <class Type>
252  static Type* recursivecpy(Type* data) {
253  if (data == NULL) return data;
254  Type* result = cpy(data);
255  result->next = recursivecpy(data->next);
256  return result;
257  }
258  template <class Type>
259  static Type* shallowcpy(Type* result, Type* data) {
260  cpy(result, data)->e = recursivecpy(data->e);
261  return result;
262  }
263  template <class Type>
264  static Type* shallowcpy(Type* data) {
265  return shallowcpy((Type*) omAlloc0(sizeof(Type)), data);
266  }
267  template <class Type>
268  static void recursivekill(Type* current) {
269  if(current == NULL) return;
270  recursivekill(current->next);
271  omFree(current);
272  }
273  static leftv allocate() { return (leftv)omAlloc0(sizeof(sleftv)); }
274 
275 };
276 
277 /** @class LeftvShallow
278  * Ths class wraps @c leftv by taking into acount memory allocation, destruction
279  * as well as shallowly copying of a given @c leftv, i.e. we just copy auxiliary
280  * information (like subexpressions), but not the actual data.
281  *
282  * @note This is useful to avoid invalidating @c leftv while operating on th
283  **/
285  public LeftvHelper {
286  typedef LeftvShallow self;
287 
288 public:
289  /// Just allocate (all-zero) @c leftv
290  LeftvShallow(): m_data(allocate()) { }
291  /// Shallow copy the input data
292  LeftvShallow(leftv data): m_data(shallowcpy(data)) { }
293  /// Construct (shallow) copy of @c *this
294  LeftvShallow(const self& rhs): m_data(shallowcpy(rhs.m_data)) { }
295 
296  /// Destruct
298  recursivekill(m_data->e);
299  omFree(m_data);
300  }
301 
302  /// Assign shallow copy of the input
303  self& operator=(leftv rhs) {
304  recursivekill(m_data->e);
305  shallowcpy(m_data, rhs);
306  return *this;
307  }
308  /// Assign (shallow) copy of @c *this
309  self& operator=(const self& rhs) { return (*this) = rhs.m_data; }
310 
311  /// @name Pointer-style access
312  //@{
313  /*const*/ leftv operator->() const { return m_data; }
314  /*^ warning: 'const' type qualifier on return type has no effect!!! */
315  leftv operator->() { return m_data; }
316  //@]
317 
318 protected:
319  /// The actual data pointer
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  **/
334 class 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 
344 public:
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
397  leftv next = result->next;
398  result->next = NULL;
399  result->CleanUp();
400 
401  shallowcpy(result, m_data);
402  result->next = next;
403 
404  /// @note @c attrib should read the attributes of the identifier
405  if (isid()) {
406  result->attribute = ((idhdl)m_data->data)->attribute;
407  result->flag = ((idhdl)m_data->data)->flag;
408 
409  }
410  return FALSE;
411  }
412 
413  /// Get additional data (e.g. subexpression data) from likewise instances
415  if (res->data == m_data->data) {
416  if(m_data->e != res->e) recursivekill(m_data->e);
417  cpy(m_data, res);
418  res->Init();
419  return TRUE;
420  }
421  return FALSE;
422  }
423 
424 
425  /// Check for being an identifier
426  BOOLEAN isid() const { return m_data->rtyp==IDHDL;}
427  /// Test whether we reference to ring-dependent data
428  BOOLEAN ringed() { return m_data->RingDependend(); }
429  /// Check whether (all-zero) initialized data was never assigned.
430  BOOLEAN unassigned() const { return m_data->Typ()==0; }
431 
432  /// Wrap data by identifier, if not done yet
433  leftv idify(idhdl* root) {
434  leftv res = (isid()? m_data: LeftvHelper::idify(m_data, root));
435  ++(((idhdl)res->data)->ref);
436  return res;
437  }
438 
439  /// Erase identifier handles by @c *this
440  /// @note Assumes that we reference an identifier and that we own the latter.
441  /// This is useful to clear the result of a subsequent call of @c idify.
442  void clearid(idhdl* root) {
443  assume(isid());
444  if (--((idhdl)m_data->data)->ref <= 0) // clear only if we own
445  LeftvHelper::clearid((idhdl)m_data->data, root);
446  }
447 
448 private:
449  /// Store the actual data
451 };
452 
453 /// Initialize @c blackbox types 'reference' and 'shared', or both
456 
457 inline void
459 {
462 }
463 
464 
465 #endif /*SINGULAR_COUNTEDREF_H_ */
466 
CountedRefPtr()
Default constructor.
Definition: countedref.h:54
BOOLEAN unassigned() const
Check whether (all-zero) initialized data was never assigned.
Definition: countedref.h:430
void invalidate()
Mark weak reference as invalid.
Definition: countedref.h:178
void CountedRefPtr_kill(CountedRefIndirectPtr< PtrType > *pval)
Definition: countedref.h:151
Class used for (list of) interpreter objects.
Definition: subexpr.h:82
bool operator==(const self &rhs) const
Checking equality.
Definition: countedref.h:82
leftv m_data
The actual data pointer.
Definition: countedref.h:320
count_type ref
Number of references.
Definition: countedref.h:129
CountedRefPtr(const CountedRefPtr< ptr_type, !nondestructive, Never, count_type > &rhs)
Convert from compatible smart pointer.
Definition: countedref.h:61
RefCounter(...)
Any Constructor resets the counter.
Definition: countedref.h:122
CountedRefIndirectPtr & operator=(PtrType ptr)
Definition: countedref.h:145
static Type * shallowcpy(Type *result, Type *data)
Definition: countedref.h:259
Subexpr e
Definition: subexpr.h:105
BITSET flag
Definition: subexpr.h:90
leftv operator->()
The actual data pointer.
Definition: countedref.h:315
const ptr_type operator->() const
Pointer-style interface.
Definition: countedref.h:200
LeftvDeep(leftv data)
Store a deep copy of the data @ note Occupies the provided leftv and invalidates the latter...
Definition: countedref.h:350
#define FALSE
Definition: auxiliary.h:94
CountType count_type
Definition: countedref.h:49
static Type * shallowcpy(Type *data)
Definition: countedref.h:264
CountedRefPtr(const self &rhs)
Construct refernce copy.
Definition: countedref.h:65
ptr_type m_ptr
Store actual pointer.
Definition: countedref.h:105
CountedRefWeakPtr(ptr_type ptr)
Convert from pointer.
Definition: countedref.h:169
#define IDNEXT(a)
Definition: ipid.h:115
~LeftvShallow()
Destruct.
Definition: countedref.h:297
LeftvDeep()
Allocate all-zero object by default.
Definition: countedref.h:346
#define TRUE
Definition: auxiliary.h:98
self & operator=(ptr_type ptr)
Pointer-style interface.
Definition: countedref.h:189
static Type * cpy(Type *data)
Definition: countedref.h:248
void Init()
Definition: subexpr.h:107
sleftv * leftv
Definition: structs.h:60
void countedref_reference_load()
Initialize blackbox types &#39;reference&#39; and &#39;shared&#39;, or both.
Definition: countedref.cc:700
ptr_type operator->()
Definition: countedref.h:90
int Typ()
Definition: subexpr.cc:995
CountedRefWeakPtr(const self &rhs)
Construct copy.
Definition: countedref.h:172
void countedref_shared_load()
Definition: countedref.cc:724
bool operator==(ptr_type ptr) const
Pointer-style interface.
Definition: countedref.h:196
LeftvShallow()
Just allocate (all-zero) leftv.
Definition: countedref.h:290
Definition: idrec.h:34
#define IDHDL
Definition: tok.h:31
bool like(const self &rhs) const
Determine whether we point to the same data.
Definition: countedref.h:370
void * data
Definition: subexpr.h:88
poly res
Definition: myNF.cc:322
This class implements implements a refernce counter which we can use as a public base of objects mana...
Definition: countedref.h:112
#define IDTYP(a)
Definition: ipid.h:116
void killhdl2(idhdl h, idhdl *ih, ring r)
Definition: ipid.cc:408
idhdl enterid(const char *s, int lev, int t, idhdl *root, BOOLEAN init, BOOLEAN search)
Definition: ipid.cc:258
This class wraps leftv by taking into acount memory allocation, destruction as well as deeply copying...
Definition: countedref.h:334
BOOLEAN retrieve(leftv res)
Get additional data (e.g. subexpression data) from likewise instances.
Definition: countedref.h:414
Construct even deeper copy: Skip identifier (if any) and take care of the data on our own...
Definition: countedref.h:357
leftv m_data
Store the actual data.
Definition: countedref.h:450
Ths class wraps leftv by taking into acount memory allocation, destruction as well as shallowly copyi...
Definition: countedref.h:284
CountedRefPtr(ptr_type ptr)
Convert from pointer.
Definition: countedref.h:57
~CountedRefWeakPtr()
Unlink one reference (handled by CountedRefPtr)
Definition: countedref.h:175
bool unassigned() const
Test whether reference was never used.
Definition: countedref.h:181
#define omFree(addr)
Definition: omAllocDecl.h:261
#define assume(x)
Definition: mod2.h:394
static leftv idify(leftv head, idhdl *root)
Definition: countedref.h:215
~LeftvDeep()
Really clear data.
Definition: countedref.h:361
self & operator=(leftv rhs)
Assign shallow copy of the input.
Definition: countedref.h:303
CountedRefPtr< CountedRefIndirectPtr< ptr_type > * > ptrptr_type
Definition: countedref.h:162
bool operator==(ptr_type ptr) const
Definition: countedref.h:85
~RefCounter()
Destructor.
Definition: countedref.h:125
self & operator=(leftv rhs)
Reassign a new deep copy by occupieing another leftv.
Definition: countedref.h:374
BOOLEAN put(leftv result)
Put a shallow copy to given leftv.
Definition: countedref.h:396
LeftvShallow(leftv data)
Shallow copy the input data.
Definition: countedref.h:292
idrec * idhdl
Definition: ring.h:18
void reclaim()
Definition: countedref.h:96
void countedref_init()
Definition: countedref.h:458
self & operator=(const self &rhs)
Assign (shallow) copy of *this.
Definition: countedref.h:309
char name(const Variable &v)
Definition: factory.h:178
bool operator!=(ptr_type rhs) const
Pointer-style interface.
Definition: countedref.h:199
leftv next
Definition: subexpr.h:86
void release()
Definition: countedref.h:97
static void clearid(idhdl handle, idhdl *root)
Definition: countedref.h:237
LeftvShallow operator*()
Definition: countedref.h:366
CountedRefWeakPtr()
Construct unassigned weak reference.
Definition: countedref.h:166
static void recursivekill(Type *current)
Definition: countedref.h:268
#define NULL
Definition: omList.c:10
self & operator=(ptr_type ptr)
Definition: countedref.h:73
CanonicalForm head(const CanonicalForm &f)
ptr_type operator->()
Pointer-style interface.
Definition: countedref.h:201
leftv idify(idhdl *root)
Wrap data by identifier, if not done yet.
Definition: countedref.h:433
static Type * cpy(Type *result, Type *data)
Definition: countedref.h:244
This class implements a smart pointer which handles pointer-style access to a reference-counted struc...
Definition: countedref.h:43
~CountedRefPtr()
Unlink one reference.
Definition: countedref.h:69
LeftvDeep(leftv data, copy_tag)
Definition: countedref.h:358
int rtyp
Definition: subexpr.h:91
void CleanUp(ring r=currRing)
Definition: subexpr.cc:332
void clearid(idhdl *root)
Erase identifier handles by *this.
Definition: countedref.h:442
static leftv allocate()
Definition: countedref.h:273
static idhdl newid(leftv head, idhdl *root)
Definition: countedref.h:223
attr attribute
Definition: subexpr.h:89
PtrType ptr_type
Definition: countedref.h:48
leftv operator->() const
The actual data pointer.
Definition: countedref.h:313
self & operator=(const self &rhs)
Definition: countedref.h:72
count_type count() const
Definition: countedref.h:95
#define IDDATA(a)
Definition: ipid.h:123
CountedRefIndirectPtr(PtrType ptr)
Definition: countedref.h:144
BOOLEAN isid() const
Check for being an identifier.
Definition: countedref.h:426
int BOOLEAN
Definition: auxiliary.h:85
LeftvShallow(const self &rhs)
Construct (shallow) copy of *this.
Definition: countedref.h:294
static Type * recursivecpy(Type *data)
Definition: countedref.h:252
#define NONE
Definition: tok.h:216
self & operator=(const self &rhs)
Pointer-style interface.
Definition: countedref.h:185
BOOLEAN ringed()
Test whether we reference to ring-dependent data.
Definition: countedref.h:428
void * CopyD(int t)
Definition: subexpr.cc:707
idhdl set(const char *s, int lev, int t, BOOLEAN init=TRUE)
Definition: ipid.cc:217
#define omAlloc0(size)
Definition: omAllocDecl.h:211
return result
Definition: facAbsBiFact.cc:76
short count_type
Name numerical type for enumbering.
Definition: countedref.h:116
const ptr_type operator->() const
Definition: countedref.h:89
This class implements some recurrent code sniplets to be used with leftv and idhdl.implements a refernce counter which we can use.
Definition: countedref.h:213
utypes data
Definition: idrec.h:40
ptrptr_type m_indirect
Definition: countedref.h:204
ListNode * next
Definition: janet.h:31
BOOLEAN brokenid(idhdl context) const
Check a given context for our identifier.
Definition: countedref.h:389