source: git/Singular/countedref.h @ 8d1432e

spielwiese
Last change on this file since 8d1432e was dcf46c, checked in by Oleksandr Motsak <motsak@…>, 10 years ago
Fixed the deps. between doxy pages
  • Property mode set to 100644
File size: 13.1 KB
Line 
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 **/
41template <class PtrType, bool Nondestructive = false, bool NeverNull = false,
42          class CountType = short>
43class CountedRefPtr {
44  typedef CountedRefPtr self;
45
46public:
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
54  CountedRefPtr(): m_ptr(NULL) {}
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>
61  CountedRefPtr(const CountedRefPtr<ptr_type, !nondestructive, Never, count_type>& rhs):
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
69  ~CountedRefPtr() { release(); }
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)
99      CountedRefPtr_kill(m_ptr);
100  }
101  //@}
102
103private:
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 **/
112class RefCounter {
113
114public:
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
127private:
128  /// Number of references
129  count_type ref;  // naming consistent with other classes
130};
131
132
133template <class PtrType>
134class CountedRefWeakPtr;
135
136template <class PtrType>
137class CountedRefIndirectPtr:
138  public RefCounter {
139public:
140  friend class CountedRefWeakPtr<PtrType>;
141  ~CountedRefIndirectPtr()  { }
142
143private:
144  CountedRefIndirectPtr(PtrType ptr): m_ptr(ptr) { }
145  CountedRefIndirectPtr& operator=(PtrType ptr) { m_ptr = ptr; return *this; }
146
147  PtrType m_ptr;
148};
149
150template <class PtrType>
151inline void CountedRefPtr_kill(CountedRefIndirectPtr<PtrType>* pval) { delete pval; }
152
153template <class PtrType>
154class CountedRefWeakPtr {
155  typedef CountedRefWeakPtr self;
156
157public:
158
159  /// @name Name template arguments
160  //@{ Name template arguments
161  typedef PtrType ptr_type;
162  typedef CountedRefPtr<CountedRefIndirectPtr<ptr_type>*> ptrptr_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)
175  ~CountedRefWeakPtr() { }
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  //@}
203private:
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 **/
213class LeftvHelper {
214public:
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 **/
284class LeftvShallow:
285  public LeftvHelper {
286  typedef LeftvShallow self;
287
288public:
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
297  ~LeftvShallow() {
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
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
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
414  BOOLEAN retrieve(leftv res) {
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
448private:
449  /// Store the actual data
450  leftv m_data;
451};
452
453/// Initialize @c blackbox types 'reference' and 'shared', or both
454void countedref_reference_load();
455void countedref_shared_load();
456
457inline void
458countedref_init()
459{
460  countedref_reference_load();
461  countedref_shared_load();
462}
463
464
465#endif /*SINGULAR_COUNTEDREF_H_ */
466
Note: See TracBrowser for help on using the repository browser.