source: git/Singular/countedref.cc @ fc70ac

spielwiese
Last change on this file since fc70ac was fc70ac, checked in by Alexander Dreyer <alexander.dreyer@…>, 12 years ago
Treating subscriptable objects fix: 'shared' of subscriptable types new: reference counting rings here chg: classes for LeftvDeep/Shallow chg: Using class for construction fix: got reference counts right
  • Property mode set to 100644
File size: 13.8 KB
Line 
1// -*- c++ -*-
2//*****************************************************************************
3/** @file countedref.cc
4 *
5 * @author Alexander Dreyer
6 * @date 2010-12-15
7 *
8 * This file defines the @c blackbox operations for the countedref type.
9 *
10 * @par Copyright:
11 *   (c) 2010 by The Singular Team, see LICENSE file
12**/
13//*****************************************************************************
14
15
16
17
18
19#include <Singular/mod2.h>
20
21#include <Singular/ipid.h>
22#include <Singular/blackbox.h>
23#include <Singular/newstruct.h>
24
25#include <omalloc/omalloc.h>
26#include <kernel/febase.h>
27#include <kernel/longrat.h>
28#include <Singular/subexpr.h>
29#include <Singular/ipshell.h>
30
31#include "lists.h"
32#include "attrib.h"
33
34
35class CountedRefEnv {
36  typedef CountedRefEnv self;
37
38
39
40};
41idhdl* getmyroot() {
42  static idhdl myroot = NULL;
43  if (myroot == NULL) {
44    myroot = enterid(" _shared_data_ ", 0, PACKAGE_CMD, &IDROOT, TRUE);
45  }
46  return &myroot;
47}
48
49class RefCounter {
50  typedef RefCounter self;
51
52  /// Name numerical type for enumbering
53  typedef unsigned long count_type;
54
55public:
56  /// Default Constructor
57  RefCounter(): m_count(0) {}
58
59  /// Copying resets the counter
60  RefCounter(const self&): m_count(0) {}
61
62  /// Destructor
63  ~RefCounter() { assume(m_count == 0); }
64
65  /// @name Reference counter management
66  //@{
67  count_type reclaim() { return ++m_count; }
68  count_type release() { return --m_count; }
69  count_type count() const { return m_count; }
70  //@}
71
72private:
73  /// Number of references
74  count_type m_count;
75};
76
77class LeftvShallow {
78  typedef LeftvShallow self;
79 
80public:
81  LeftvShallow(): m_data(allocate()) { }
82  LeftvShallow(leftv data): 
83    m_data(init(allocate(), data)) { }
84  LeftvShallow(const self& rhs):
85    m_data(init(allocate(), rhs.m_data)) { }
86
87  ~LeftvShallow() { 
88    kill();
89    omFree(m_data);
90  }
91  self& operator=(leftv rhs) {
92    kill();
93    init(m_data, rhs);
94    return *this;
95  }
96
97  self& operator=(const self& rhs) { return (*this) = rhs.m_data; }
98
99  BOOLEAN get(leftv result) {
100    leftv next = result->next;
101    result->next = NULL;
102    result->CleanUp();
103    init(result, m_data);
104    result->next = next;
105    return FALSE;
106  }
107
108  /// Access to object
109  leftv operator->() { return m_data;  }
110
111protected:
112  static leftv allocate() { return (leftv)omAlloc0(sizeof(sleftv)); }
113  static leftv init(leftv result, leftv data) {
114    memcpy(result, data, sizeof(sleftv));
115    copy(result->e, data->e);
116    result-> next = NULL;
117    return result;
118  }
119  static void copy(Subexpr& current, Subexpr rhs)  {
120    if (rhs == NULL) return;
121    current = (Subexpr)memcpy(omAlloc0Bin(sSubexpr_bin), rhs, sizeof(*rhs));
122    copy(current->next, rhs->next);
123  }
124  void kill() { kill(m_data->e); }
125  static void kill(Subexpr current) {
126    if(current == NULL) return;
127    kill(current->next);
128    omFree(current);
129  }
130protected:
131  leftv m_data;
132};
133
134
135class LeftvDeep:
136  public LeftvShallow {
137  typedef LeftvDeep self;
138  typedef LeftvShallow base;
139
140public:
141  LeftvDeep(): base() {}
142  LeftvDeep(leftv data): base(data) { }
143  LeftvDeep(const self& rhs): base(rhs) { }
144
145  ~LeftvDeep() { m_data->CleanUp(); }
146
147  self& operator=(const self& rhs) { return operator=(rhs.m_data); }
148  self& operator=(leftv rhs) {
149    m_data->CleanUp();
150    m_data->Copy(rhs);
151    return *this;
152  }
153};
154
155
156/** @class CountedRefData
157 * This class stores a reference counter as well as a Singular interpreter object.
158 *
159 * It also stores the Singular token number, once per type.
160 **/
161class CountedRefData:
162  public RefCounter {
163  typedef CountedRefData self;
164  typedef RefCounter base;
165
166public:
167  /// Construct reference for Singular object
168  explicit CountedRefData(leftv data, idhdl* ctx = &IDROOT):
169    base(), m_data(data), m_context(ctx) { context(); }
170
171  /// Construct deep copy
172  CountedRefData(const self& rhs):
173    base(), m_data(rhs.m_data), m_context(rhs.m_context) { }
174 
175  /// Destruct
176  ~CountedRefData()  { }
177
178  /// Replace data
179  self& operator=(const self& rhs) {
180    m_data = rhs.m_data;
181    m_context = rhs.m_context;
182    return *this;
183  }
184 
185  /// Replace with other Singular data
186  void set(leftv rhs, idhdl* ctx = &IDROOT) {
187    m_data = rhs;
188    m_context = ctx;
189    context();
190  }
191
192  /// Write (shallow) copy to given handle
193  BOOLEAN get(leftv res) {
194    reclaim();
195    BOOLEAN b = broken() || m_data.get(res); 
196    release();
197    return b;
198  }
199
200  /// Extract (shallow) copy of stored data
201  LeftvShallow operator*() { return (broken()? LeftvShallow(): m_data); }
202
203private:
204  /// Check whether identifier became invalid
205  /// @note Sergio Leone memorial function
206  BOOLEAN broken() {
207    if( (m_context == getmyroot()) || (m_context == &currRing->idroot))
208      return FALSE;                  // the good,
209
210    if (m_data->RingDependend())     // the bad,
211      return complain("Referenced identifier not available in current ring");
212
213    return (brokenid(m_context) &&   // and the ugly (case)
214            ((m_context == &basePack->idroot) || brokenid())) &&
215      complain("Referenced identifier not found in current context");
216  }
217
218  /// Determine corresponding context
219  /// @note for ring-dependent object we always store @c currRing's root as marker
220  void context() { if (m_data->RingDependend()) m_context = &currRing->idroot; }
221
222  ///
223  BOOLEAN complain(const char* text) {
224    Werror(text);
225    return TRUE;
226  }
227  BOOLEAN brokenid(idhdl* root = &basePack->idroot) {
228    idhdl handle = (idhdl) m_data->data;
229    for(idhdl current = *root; current != NULL; current = IDNEXT(current))
230      if (current == handle) return FALSE;
231    return TRUE;
232  }
233
234
235  /// Singular object
236  LeftvDeep m_data;
237
238  /// Store namespace for ring-dependent objects
239  idhdl* m_context;
240};
241
242/// blackbox support - initialization
243/// @note deals as marker for compatible references, too.
244void* countedref_Init(blackbox*)
245{
246  return NULL;
247}
248
249class CountedRef {
250  typedef CountedRef self;
251
252public:
253  /// name type for identifiers
254  typedef int id_type;
255
256  /// Name type for handling reference data
257  typedef CountedRefData data_type;
258
259  /// Check whether argument is already a reference type
260  static BOOLEAN is_ref(leftv arg) {
261    int typ = arg->Typ();
262    return ((typ > MAX_TOK) &&
263           (getBlackboxStuff(typ)->blackbox_Init == countedref_Init));
264  }
265
266  /// Construct new reference from Singular data 
267  CountedRef(leftv arg):  m_data(new data_type(arg)) { m_data->reclaim(); }
268
269protected:
270  /// Recover previously constructed reference
271  CountedRef(data_type* arg):  m_data(arg) { assume(arg); m_data->reclaim(); }
272
273public:
274  /// Construct copy
275  CountedRef(const self& rhs): m_data(rhs.m_data) { m_data->reclaim(); }
276
277  /// Replace reference
278  self& operator=(const self& rhs) {
279    destruct();
280    m_data = rhs.m_data;
281    m_data->reclaim();
282    return *this;
283  }
284
285  /// Replace data that reference is pointing to
286  self& operator=(leftv rhs) {
287    m_data->set(rhs);
288    return *this;
289  }
290
291  /// Extract (shallow) copy of stored data
292  LeftvShallow operator*() { return m_data->operator*(); }
293
294  /// Construct reference data object from
295  BOOLEAN outcast(leftv result) {
296    m_data->reclaim();
297    if (result->rtyp == IDHDL)
298      IDDATA((idhdl)result->data) = (char *)m_data;
299    else
300      result->data = (void *)m_data;
301    return FALSE;
302  }
303  data_type* outcast() { 
304    m_data->reclaim();
305    return m_data;
306  }
307  /// Kills a link to the referenced object
308  void destruct() { if(!m_data->release()) delete m_data; }
309
310  /// Kills the link to the referenced object
311  ~CountedRef() { destruct(); }
312
313  BOOLEAN dereference(leftv arg) {
314    assume(is_ref(arg));
315    return m_data->get(arg) || ((arg->next != NULL) && resolve(arg->next));
316  }
317
318
319  /// Get the actual object
320  /// @note It may change leftv. It is common practice, so we are fine with it.
321
322  static self cast(void* data) {
323    assume(data != NULL);
324    return self(static_cast<data_type*>(data));
325  }
326
327  static self cast(leftv arg) {
328    assume((arg != NULL) && is_ref(arg));
329    return self::cast(arg->Data());
330  }
331
332  /// If necessary dereference.
333  /// @note The may change leftv. It is common practice, so we are fine with it.
334  static BOOLEAN resolve(leftv arg) {
335    assume(arg != NULL);
336    while (is_ref(arg)) { if(CountedRef::cast(arg).dereference(arg)) return TRUE; };
337    return (arg->next != NULL) && resolve(arg->next);
338  }
339
340  //private:
341protected:
342  /// Store pointer to actual data
343  data_type* m_data;
344};
345
346/// blackbox support - convert to string representation
347void countedref_Print(blackbox *b, void* ptr)
348{
349  if (ptr == NULL)  return;
350  (*CountedRef::cast(ptr))->Print();
351}
352
353/// blackbox support - convert to string representation
354char* countedref_String(blackbox *b, void* ptr)
355{
356  if (ptr == NULL) return NULL;
357  return (*CountedRef::cast(ptr))->String();
358}
359
360/// blackbox support - copy element
361void* countedref_Copy(blackbox*b, void* ptr)
362{ 
363  if (ptr) return CountedRef::cast(ptr).outcast();
364  return NULL;
365}
366
367/// blackbox support - assign element
368BOOLEAN countedref_Assign(leftv result, leftv arg)
369{
370  // Case: replace assignment behind reference
371  if (result->Data() != NULL) {
372    return CountedRef::cast(result).dereference(result) ||
373      CountedRef::resolve(arg) ||
374      iiAssign(result, arg);
375  }
376 
377  // Case: new reference
378  if(arg->rtyp == IDHDL) 
379    return (result->Typ() == arg->Typ()?
380            CountedRef::cast(arg):
381            CountedRef(arg)).outcast(result);
382
383  Werror("Can only take reference from identifier");
384  return FALSE;
385}
386                                                                     
387/// blackbox support - unary operations
388BOOLEAN countedref_Op1(int op, leftv res, leftv head)
389{
390  if(op == TYPEOF_CMD)
391    return blackboxDefaultOp1(op, res, head);
392
393  return CountedRef::cast(head).dereference(head) || 
394    iiExprArith1(res, head, (op == DEF_CMD? head->Typ(): op));
395}
396
397/// blackbox support - binary operations
398BOOLEAN countedref_Op2(int op, leftv res, leftv head, leftv arg)
399{
400
401  return CountedRef::cast(head).dereference(head) || CountedRef::resolve(arg) ||
402    iiExprArith2(res, head, op, arg);
403}
404
405/// blackbox support - ternary operations
406BOOLEAN countedref_Op3(int op, leftv res, leftv head, leftv arg1, leftv arg2)
407{
408  return  CountedRef::cast(head).dereference(head) || 
409    CountedRef::resolve(arg1) || CountedRef::resolve(arg2) ||
410    iiExprArith3(res, op, head, arg1, arg2);
411}
412
413
414/// blackbox support - n-ary operations
415BOOLEAN countedref_OpM(int op, leftv res, leftv args)
416{
417  return CountedRef::cast(args).dereference(args) || iiExprArithM(res, args, op);
418}
419
420/// blackbox support - destruction
421void countedref_destroy(blackbox *b, void* ptr)
422{
423  if (ptr) CountedRef::cast(ptr).destruct();
424}
425
426
427class CountedRefShared:
428  public CountedRef {
429  typedef CountedRefShared self;
430  typedef CountedRef base;
431public:
432  /// Construct new reference from Singular data 
433  CountedRefShared(leftv arg):  base(new data_type(wrap(arg), getmyroot())) { }
434
435private:
436  /// Recover previously constructed shared data
437  CountedRefShared(data_type* arg):  base(arg) { }
438  CountedRefShared(const base& rhs):  base(rhs) { }
439public:
440  /// Construct copy
441  CountedRefShared(const self& rhs): base(rhs) { }
442
443  ~CountedRefShared() {  kill(); }
444
445  self& operator=(const self& rhs) {
446    kill();
447    base::operator=(rhs);
448    return *this;
449  }
450
451  /// Replace data that reference is pointing to
452  self& operator=(leftv rhs) {
453    m_data->set(wrap(rhs), getmyroot());
454    return *this;
455  }
456  void destruct() {
457    kill();
458    base::destruct();
459  }
460
461  static self cast(leftv arg) { return base::cast(arg); }
462  static self cast(void* arg) { return base::cast(arg); }
463private:
464
465  static leftv wrap(leftv arg) {
466      char* name = (char*)omAlloc0(512);
467      static unsigned int counter = 0;
468      idhdl* myroot=getmyroot();
469      sprintf(name, " :%u:%p:_shared_: ", ++counter, arg->Data());
470      assume((*myroot)->get(name, 0) == NULL); 
471      idhdl handle = (*myroot)->set(name, 0, arg->Typ(), FALSE);
472      ++(*myroot)->ref;
473
474      IDDATA(handle) = (char*) arg->CopyD();
475      arg->CleanUp();
476      arg->data = handle;
477      arg->rtyp = IDHDL;
478      arg->name = name;
479
480    return arg;
481  }
482
483 void kill() {
484   if (m_data->count() > 1) return;
485
486   LeftvShallow data = base::operator*();
487   idhdl* myroot = getmyroot();
488   killhdl2((idhdl)(data->data), myroot, currRing);
489   data->data = NULL;
490   data->rtyp = NONE;
491   
492   if(--((*myroot)->ref)) {
493     killhdl2(*myroot, &IDROOT, currRing);
494     (*myroot) = NULL;
495   }
496 }
497};
498
499
500/// blackbox support - assign element
501BOOLEAN countedref_AssignShared(leftv result, leftv arg)
502{
503  /// Case: replace assignment behind reference
504  if ((result->Data()) != NULL) {
505    if (CountedRefShared::resolve(arg)) return TRUE;
506    CountedRefShared::cast(result) = arg;
507    return FALSE;
508  }
509 
510  /// Case: new shared data
511  if (result->Typ() == arg->Typ()) 
512    return CountedRefShared::cast(arg).outcast(result);
513
514  return CountedRefShared(arg).outcast(result);
515}
516
517/// blackbox support - destruction
518void countedref_destroyShared(blackbox *b, void* ptr)
519{
520  if (ptr) CountedRefShared::cast(ptr).destruct();
521}
522
523void countedref_init() 
524{
525  blackbox *bbx = (blackbox*)omAlloc0(sizeof(blackbox));
526  bbx->blackbox_destroy = countedref_destroy;
527  bbx->blackbox_String  = countedref_String;
528  bbx->blackbox_Print  = countedref_Print;
529  bbx->blackbox_Init    = countedref_Init;
530  bbx->blackbox_Copy    = countedref_Copy;
531  bbx->blackbox_Assign  = countedref_Assign;
532  bbx->blackbox_Op1     = countedref_Op1;
533  bbx->blackbox_Op2     = countedref_Op2;
534  bbx->blackbox_Op3     = countedref_Op3;
535  bbx->blackbox_OpM     = countedref_OpM;
536  bbx->data             = omAlloc0(newstruct_desc_size());
537  setBlackboxStuff(bbx, "reference");
538
539  /// The @c shared type is "inherited" from @c reference.
540  /// It just uses another constructor (to make its own copy of the).
541  blackbox *bbxshared = 
542    (blackbox*)memcpy(omAlloc(sizeof(blackbox)), bbx, sizeof(blackbox));
543  bbxshared->blackbox_Assign  = countedref_AssignShared;
544  bbxshared->blackbox_destroy  = countedref_destroyShared;
545
546  setBlackboxStuff(bbxshared, "shared");
547}
548
549extern "C" { void mod_init() { countedref_init(); } }
550
Note: See TracBrowser for help on using the repository browser.