source: git/Singular/countedref.cc @ 75c668

jengelh-datetimespielwiese
Last change on this file since 75c668 was 75c668, checked in by Alexander Dreyer <alexander.dreyer@…>, 10 years ago
Introducing blackbox type "shared" fix: newstruc's subexpressions working fix: support subexpr of subexpr chg: simplified reference dereferencing chg: simplified shallow copies of sleftv new: blackbox type
  • Property mode set to 100644
File size: 9.7 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};
41
42class RefCounter {
43  typedef RefCounter self;
44
45  /// Name numerical type for enumbering
46  typedef unsigned long count_type;
47
48public:
49  /// Default Constructor
50  RefCounter(): m_count(0) {}
51
52  /// Copying resets the counter
53  RefCounter(const self& rhs): m_count(0) {}
54
55  /// Destructor
56  ~RefCounter() { assume(m_count == 0); }
57
58  /// @name Reference counter management
59  //@{
60  count_type reclaim() { return ++m_count; }
61  count_type release() { return --m_count; }
62  count_type count() const { return m_count; }
63  //@}
64
65private:
66  /// Number of references
67  count_type m_count;
68};
69
70class LeftvShallow {
71  typedef LeftvShallow self;
72
73public:
74  LeftvShallow(leftv data): m_data(*data) {  copy(&m_data.e, data->e); }
75  LeftvShallow(const self& rhs): m_data(rhs.m_data) { copy(&m_data.e, rhs.m_data.e); }
76
77  ~LeftvShallow() {  kill(m_data.e); }
78
79  BOOLEAN get(leftv result) {
80    leftv next = result->next;
81    result->next = NULL;
82    result->CleanUp();
83    memcpy(result, &m_data, sizeof(m_data));
84    copy(&result->e, m_data.e);
85    result->next = next;
86    return FALSE;
87  }
88
89  /// Read-only access to object
90  const leftv operator->() { return &m_data; }
91
92private:
93  static void copy(Subexpr* result, Subexpr rhs) {
94    for (Subexpr* current = result; rhs != NULL; 
95         current = &(*current)->next, rhs = rhs->next)
96      *current = (Subexpr)memcpy(omAlloc0Bin(sSubexpr_bin), rhs, sizeof(*rhs));
97  }
98
99  static void kill(Subexpr rhs) {
100    for (Subexpr next; rhs!=NULL; rhs = next, next = rhs->next) {
101      next = rhs->next;
102      omFree(rhs);
103    }
104  }
105  sleftv m_data;
106};
107
108/** @class CountedRefData
109 * This class stores a reference counter as well as a Singular interpreter object.
110 *
111 * It also stores the Singular token number, once per type.
112 **/
113class CountedRefData:
114  public RefCounter {
115  typedef CountedRefData self;
116  typedef RefCounter base;
117
118  /// Forbit copy construction and normal assignment
119  CountedRefData(const self&);
120  self& operator=(const self&);
121
122public:
123  /// Construct reference for Singular object
124  CountedRefData(leftv data): base(), m_data(data), m_ring(NULL) {
125    if (RingDependend(data->Typ())  && (currRing != NULL) ) {
126      m_ring = currRing;
127      ++m_ring->ref;
128    }
129
130  }
131
132  static idhdl* id_root;
133
134  /// Destructor
135  ~CountedRefData()  { }
136
137  BOOLEAN get(leftv result) {
138    if (m_ring && (m_ring != currRing)) {
139      Werror("Can only use references from current ring.");
140      return TRUE;
141    }
142    // dereferencing only makes sense, if something else points here, too.
143    assume(count() > 1);
144    return m_data.get(result);
145  }
146
147  LeftvShallow get() {
148    if (m_ring && (m_ring != currRing))
149      Werror("Can only use references from current ring.");
150 
151    return LeftvShallow(m_data);
152  }
153
154private:
155
156  /// Singular object
157  LeftvShallow m_data;
158
159  /// Store ring for ring-dependent objects
160  ring m_ring;
161};
162
163/// blackbox support - initialization
164/// @note deals as marker for compatible references, too.
165void* countedref_Init(blackbox*)
166{
167  return NULL;
168}
169
170class CountedRef {
171  typedef CountedRef self;
172
173public:
174  /// name type for identifiers
175  typedef int id_type;
176
177  /// Name type for handling reference data
178  typedef CountedRefData data_type;
179
180  /// Check whether argument is already a reference type
181  static BOOLEAN is_ref(int typ) {
182    return ((typ > MAX_TOK) &&
183           (getBlackboxStuff(typ)->blackbox_Init == countedref_Init));
184  }
185
186  /// Construct reference data object from
187  static BOOLEAN construct(leftv result, leftv arg) {
188    data_type* data = (result->Typ() == arg->Typ()? 
189                       static_cast<data_type*>(arg->Data()): new data_type(arg));
190    data->reclaim();
191    if (result->rtyp == IDHDL)
192      IDDATA((idhdl)result->data) = (char *)data;
193    else
194      result->data = (void *)data;
195    return (data == NULL? TRUE: FALSE);
196  }
197
198  /// Kills the link to the referenced object
199  static void destruct(data_type* data) {
200    if(data && !data->release()) {
201      delete data;
202    }
203  }
204
205  /// Get the actual object
206  /// @note It may change leftv. It is common practice, so we are fine with it.
207  static BOOLEAN dereference(leftv arg) {
208    assume((arg != NULL) && is_ref(arg->Typ()));
209    do {
210      assume(arg->Data() != NULL);
211      data_type* data = static_cast<data_type*>(arg->Data());
212      if(data->get(arg)) return TRUE;
213    } while (is_ref(arg->Typ()));
214    return resolve_tail(arg);
215  }
216
217  /// If necessary dereference.
218  /// @note The may change leftv. It is common practice, so we are fine with it.
219  static BOOLEAN resolve(leftv arg) {
220    assume(arg != NULL);
221    while (is_ref(arg->Typ())) { if(dereference(arg)) return TRUE; };
222    return resolve_tail(arg);
223  }
224
225private:
226  /// Dereference (is needed) subsequent objects of sequences
227  static BOOLEAN resolve_tail(leftv arg) {
228    for(leftv next = arg->next; next != NULL; next = next->next)
229      if(resolve(next))
230        return TRUE;
231    return FALSE;
232  }
233};
234
235/// blackbox support - convert to string representation
236void countedref_Print(blackbox *b, void* ptr)
237{
238  if (ptr != NULL) static_cast<CountedRefData*>(ptr)->get()->Print();
239}
240
241/// blackbox support - convert to string representation
242char* countedref_String(blackbox *b, void* ptr)
243{
244  if (ptr != NULL) return static_cast<CountedRefData*>(ptr)->get()->String();
245}
246
247/// blackbox support - copy element
248void* countedref_Copy(blackbox*b, void* ptr)
249{ 
250  if (ptr) static_cast<CountedRefData*>(ptr)->reclaim();
251  return ptr;
252}
253
254/// blackbox support - assign element
255BOOLEAN countedref_Assign(leftv result, leftv arg)
256{
257  // Case: replace assignment behind reference
258  if (result->Data() != NULL) 
259    return CountedRef::dereference(result) || CountedRef::resolve(arg) ||
260      iiAssign(result, arg);
261 
262  // Case: new reference
263  if(arg->rtyp == IDHDL) 
264    return CountedRef::construct(result, arg);
265 
266  Werror("Can only take reference from identifier");
267  return FALSE;
268}
269                                                                     
270/// blackbox support - unary operations
271BOOLEAN countedref_Op1(int op, leftv res, leftv head)
272{
273  if(op == TYPEOF_CMD)
274    return blackboxDefaultOp1(op, res, head);
275
276  return CountedRef::dereference(head) || 
277    iiExprArith1(res, head, (op == DEF_CMD? head->Typ(): op));
278}
279
280/// blackbox support - binary operations
281BOOLEAN countedref_Op2(int op, leftv res, leftv head, leftv arg)
282{
283  return CountedRef::dereference(head) || CountedRef::resolve(arg) ||
284    iiExprArith2(res, head, op, arg);
285}
286
287/// blackbox support - ternary operations
288BOOLEAN countedref_Op3(int op, leftv res, leftv head, leftv arg1, leftv arg2)
289{
290  return CountedRef::dereference(head) || 
291    CountedRef::resolve(arg1) || CountedRef::resolve(arg2) ||
292    iiExprArith3(res, op, head, arg1, arg2);
293}
294
295
296/// blackbox support - n-ary operations
297BOOLEAN countedref_OpM(int op, leftv res, leftv args)
298{
299  return CountedRef::dereference(args) || iiExprArithM(res, args, op);
300}
301
302/// blackbox support - destruction
303void countedref_destroy(blackbox *b, void* ptr)
304{
305  CountedRef::destruct(static_cast<CountedRefData*>(ptr));
306}
307
308
309/// blackbox support - assign element
310BOOLEAN countedref_AssignShared(leftv result, leftv arg)
311{
312  // Case: replace assignment behind reference
313  if (result->Data() != NULL)
314    return CountedRef::dereference(result) || CountedRef::resolve(arg) ||
315      iiAssign(result, arg);
316 
317 
318  if(CountedRef::resolve(arg))
319    return TRUE;
320
321  char* name=(char*)omAlloc0(512);
322  static unsigned long counter = 0;
323  do {
324    sprintf(name, "_shareddata_%s_%s_%d\0", result->Name(), arg->Name(), ++counter);
325  }
326  while(ggetid(name));
327  idhdl handle = enterid(name, 0, arg->Typ(), &IDROOT, FALSE);
328  omFree(name);
329  if (handle==NULL) {
330    Werror("Initializing shared failed");
331    return TRUE;
332  }
333 
334  IDDATA(handle) = (char*)arg->CopyD();
335  arg->data = handle;
336  arg->rtyp = IDHDL;
337 
338  return CountedRef::construct(result, arg);
339}
340
341/// blackbox support - destruction
342void countedref_destroyShared(blackbox *b, void* ptr)
343{
344  CountedRefData* data = static_cast<CountedRefData*>(ptr);
345
346  if(data && !data->release()) {
347    leftv tmp = (leftv) omAlloc0(sizeof(*tmp));
348    data->get(tmp);
349    killid(IDID((idhdl)(tmp->data)), &IDROOT);
350    delete data;
351  }
352
353}
354
355void countedref_init() 
356{
357  blackbox *bbx = (blackbox*)omAlloc0(sizeof(blackbox));
358  bbx->blackbox_destroy = countedref_destroy;
359  bbx->blackbox_String  = countedref_String;
360  bbx->blackbox_Print  = countedref_Print;
361  bbx->blackbox_Init    = countedref_Init;
362  bbx->blackbox_Copy    = countedref_Copy;
363  bbx->blackbox_Assign  = countedref_Assign;
364  bbx->blackbox_Op1     = countedref_Op1;
365  bbx->blackbox_Op2     = countedref_Op2;
366  bbx->blackbox_Op3     = countedref_Op3;
367  bbx->blackbox_OpM     = countedref_OpM;
368  bbx->data             = omAlloc0(newstruct_desc_size());
369  setBlackboxStuff(bbx, "reference");
370
371  blackbox *bbxshared = 
372    (blackbox*)memcpy(omAlloc(sizeof(blackbox)), bbx, sizeof(blackbox));
373  bbxshared->blackbox_Assign  = countedref_AssignShared;
374  bbxshared->blackbox_destroy = countedref_destroyShared;
375  setBlackboxStuff(bbxshared, "shared");
376}
377
378extern "C" { void mod_init() { countedref_init(); } }
379
Note: See TracBrowser for help on using the repository browser.