source: git/Singular/countedref.h @ cda275f

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