source: git/Singular/countedref.h @ abb12f

spielwiese
Last change on this file since abb12f was bc2606, checked in by Oleksandr Motsak <motsak@…>, 11 years ago
Compiler warnings elimination
  • Property mode set to 100644
File size: 13.1 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  /*^ warning: 'const' type qualifier on return type has no effect!!! */
316  leftv operator->() { return m_data;  }
317  //@]
318
319protected:
320  /// The actual data pointer
321  leftv m_data;
322};
323
324/** @class LeftvDeep
325 * This class wraps @c leftv by taking into acount memory allocation, destruction
326 * as well as deeply copying of a given @c leftv, i.e. we also take over
327 * ownership of the @c leftv data.
328 *
329 * We have two variants:
330   + LeftvDeep(leftv):           treats referenced identifiers as "the data"
331   + LeftvDeep(leftv, copy_tag): takes care of a full copy of identifier's data
332 *
333 * @note It invalidats @c leftv on input.
334 **/
335class LeftvDeep: 
336  public LeftvHelper {
337  typedef LeftvDeep self;
338
339  /// @name Do not permit copying (avoid inconsistence)
340  //@{
341  self& operator=(const self&);
342  LeftvDeep(const self&);
343  //@}
344
345public:
346  /// Allocate all-zero object by default
347  LeftvDeep(): m_data(allocate()) {}
348
349  /// Store a deep copy of the data
350  /// @ note Occupies the provided @c leftv and invalidates the latter
351  LeftvDeep(leftv data): m_data(cpy(data)) { 
352    data->e = NULL;   // occupy subexpression
353    if(!isid()) m_data->data=data->CopyD(); 
354  }
355
356  /// Construct even deeper copy:
357  /// Skip identifier (if any) and take care of the data on our own
358  struct copy_tag {};
359  LeftvDeep(leftv data, copy_tag): m_data(allocate()) {  m_data->Copy(data);  }
360
361  /// Really clear data
362  ~LeftvDeep() { m_data->CleanUp(); }
363
364  /// @name Access via shallow copy to avoid invalidating the stored handle
365  //@{
366  operator LeftvShallow() { return m_data; }
367  LeftvShallow operator*() {return *this; }
368  //@}
369
370  /// Determine whether we point to the same data
371  bool like(const self& rhs) const { return m_data->data == rhs.m_data->data; }
372
373  /// Reassign a new deep copy by occupieing another @c leftv
374  /// @note clears @c *this in the first
375  self& operator=(leftv rhs) {
376    if(isid()) {
377      m_data->e = rhs->e;
378      rhs->e = NULL;
379      IDTYP((idhdl)m_data->data) =  rhs->Typ();
380      IDDATA((idhdl)m_data->data) = (char*) rhs->CopyD();
381    }
382    else {
383      m_data->CleanUp();
384      m_data->Copy(rhs);
385    }
386    return *this;
387  }
388
389  /// Check a given context for our identifier
390  BOOLEAN brokenid(idhdl context) const {
391    assume(isid());
392    return (context == NULL) || 
393      ((context != (idhdl) m_data->data) && brokenid(IDNEXT(context)));
394  }
395
396  /// Put a shallow copy to given @c leftv
397  BOOLEAN put(leftv result) {
398    leftv next = result->next;
399    result->next = NULL;
400    result->CleanUp();
401
402    shallowcpy(result, m_data);
403    result->next = next;
404
405    /// @note @c attrib should read the attributes of the identifier
406    if (isid()) {
407      result->attribute = ((idhdl)m_data->data)->attribute;
408      result->flag = ((idhdl)m_data->data)->flag;
409
410    }
411    return FALSE;
412  }
413
414  /// Get additional data (e.g. subexpression data) from likewise instances
415  BOOLEAN retrieve(leftv res) {
416    if (res->data == m_data->data)  {
417      if(m_data->e != res->e) recursivekill(m_data->e);
418      cpy(m_data, res);
419      res->Init();
420      return TRUE;
421    }
422    return FALSE;
423  }
424
425
426  /// Check for being an identifier
427  BOOLEAN isid() const { return m_data->rtyp==IDHDL;}
428  /// Test whether we reference to ring-dependent data
429  BOOLEAN ringed() { return m_data->RingDependend(); }
430  /// Check whether (all-zero) initialized data was never assigned.
431  BOOLEAN unassigned() const { return m_data->Typ()==0; }
432
433  /// Wrap data by identifier, if not done yet
434  leftv idify(idhdl* root) {
435    leftv res = (isid()? m_data: LeftvHelper::idify(m_data, root));
436    ++(((idhdl)res->data)->ref);
437    return res;
438  }
439
440  /// Erase identifier handles by @c *this
441  /// @note Assumes that we reference an identifier and that we own the latter.
442  /// This is useful to clear the result of a subsequent call of @c idify.
443  void clearid(idhdl* root) {
444    assume(isid());
445    if (--((idhdl)m_data->data)->ref <= 0)  // clear only if we own
446      LeftvHelper::clearid((idhdl)m_data->data, root);
447  }
448
449private:
450  /// Store the actual data
451  leftv m_data;
452};
453
454/// Initialize @c blackbox types 'reference' and 'shared', or both
455void countedref_reference_load();
456void countedref_shared_load();
457
458inline void
459countedref_init()
460{
461  countedref_reference_load();
462  countedref_shared_load();
463}
464
465
466#endif /*SINGULAR_COUNTEDREF_H_ */
467
Note: See TracBrowser for help on using the repository browser.