1 | // $Source$ |
---|
2 | // $Revision: 288 $ |
---|
3 | // $Date: 2002-12-19 12:11:29 +0000 (Thu, 19 Dec 2002) $ |
---|
4 | |
---|
5 | #ifndef __rf_expr_hh__ |
---|
6 | #define __rf_expr_hh__ |
---|
7 | |
---|
8 | #include "rf_common.hh" |
---|
9 | #include "rf_term.hh" |
---|
10 | #include "pxx_memory_chunk.hh" |
---|
11 | |
---|
12 | #include <new> |
---|
13 | #include <string.h> |
---|
14 | |
---|
15 | namespace rfrt |
---|
16 | { |
---|
17 | |
---|
18 | // |
---|
19 | // expression splitting directions |
---|
20 | enum Direction |
---|
21 | { |
---|
22 | d_lt, // split from left |
---|
23 | d_rt // split from right |
---|
24 | }; |
---|
25 | |
---|
26 | // |
---|
27 | // Refal+ expression class |
---|
28 | class Expr |
---|
29 | { |
---|
30 | |
---|
31 | // |
---|
32 | // iterator is our friend |
---|
33 | template <Direction D = d_lt> |
---|
34 | friend class SplitIterator ; |
---|
35 | |
---|
36 | // |
---|
37 | // term is our friend |
---|
38 | friend class Term ; |
---|
39 | |
---|
40 | private: |
---|
41 | |
---|
42 | // |
---|
43 | // pointer to the first term |
---|
44 | Term* first; |
---|
45 | // |
---|
46 | // pointer beyond the last term |
---|
47 | Term* last; |
---|
48 | // |
---|
49 | // pointer to expression's holder in memory |
---|
50 | M_Chunk* mem_chunk; |
---|
51 | // |
---|
52 | // flag pointing that expression has bracket terms |
---|
53 | uintptr_t flags; |
---|
54 | |
---|
55 | private: |
---|
56 | |
---|
57 | // |
---|
58 | // private constructor reserving for expression with specified len |
---|
59 | inline Expr (size_t const _len, int _d) |
---|
60 | { |
---|
61 | init(_len, _d); |
---|
62 | flags = 0; |
---|
63 | D( printf("+ %p(%p,%p,%p) of size %d\n", this, first, last, mem_chunk, _len); ) |
---|
64 | } |
---|
65 | |
---|
66 | public: |
---|
67 | |
---|
68 | // |
---|
69 | // constructor from character string |
---|
70 | inline Expr (char const* _s = null) |
---|
71 | { |
---|
72 | // |
---|
73 | // initialize expression |
---|
74 | init(_s != null ? strlen(_s) : 0, 0); |
---|
75 | // |
---|
76 | // in a loop... |
---|
77 | for (Term* p = first; p < last; p++, _s++) { |
---|
78 | // |
---|
79 | // ...create a symbol in place |
---|
80 | new(p) Term(*_s); |
---|
81 | } |
---|
82 | // |
---|
83 | // mark expression as flat |
---|
84 | flags = 0; |
---|
85 | D( printf("+ %p(%p,%p,%p) from %s\n", this, first, last, mem_chunk, _s); ) |
---|
86 | } |
---|
87 | |
---|
88 | // |
---|
89 | // constructor from expression holder |
---|
90 | inline Expr( Term const* _cp ) |
---|
91 | { |
---|
92 | // |
---|
93 | // if we really have a reference to expression... |
---|
94 | if( _cp->is_ref() ) { |
---|
95 | // |
---|
96 | // ...get its first term... |
---|
97 | first = _cp->get_first(); |
---|
98 | // |
---|
99 | // ...and last term |
---|
100 | last = _cp->get_last(); |
---|
101 | // |
---|
102 | // obtain a pointer to expression's memory chunk |
---|
103 | mem_chunk = _cp->get_mem_chunk(); |
---|
104 | // |
---|
105 | // increment reference counter |
---|
106 | mem_chunk->inc_ref_count(); |
---|
107 | // |
---|
108 | // check whether reference expression is flat and set a flag otherwise |
---|
109 | flags = _cp->data1 & REF_BIT; |
---|
110 | D( printf("+ %p(%p,%p,%p) from %p()\n", this, first, last, mem_chunk, _cp); ) |
---|
111 | } |
---|
112 | // |
---|
113 | // no, we have a symbol... |
---|
114 | else { |
---|
115 | // |
---|
116 | // ...and this is the error |
---|
117 | FATAL( "Unable to construct expression from symbol" ); |
---|
118 | } |
---|
119 | } |
---|
120 | |
---|
121 | // |
---|
122 | //! Dereference constructor. Should be called only with valid |
---|
123 | // position. |
---|
124 | inline Expr (Expr const& _expr, uintptr_t _pos) |
---|
125 | { |
---|
126 | new(this) Expr(_expr.first + _pos); |
---|
127 | } |
---|
128 | |
---|
129 | // |
---|
130 | //! Subexpression constructor |
---|
131 | inline Expr (Expr const& _expr, uintptr_t _pos, uintptr_t _length) |
---|
132 | { |
---|
133 | new(this) Expr( |
---|
134 | _expr.first + _pos, _expr.first + _pos + _length, |
---|
135 | _expr.mem_chunk, |
---|
136 | _expr.flags |
---|
137 | ); |
---|
138 | } |
---|
139 | |
---|
140 | // |
---|
141 | // constructor from term |
---|
142 | inline Expr (Term const& _cp) |
---|
143 | { |
---|
144 | init(1, 0); |
---|
145 | *first = _cp; |
---|
146 | flags |= REF_BIT; |
---|
147 | // ref_childs(); |
---|
148 | D( printf("+ %p(%p,%p,%p) by copy from term %p\n", |
---|
149 | this, first, last, mem_chunk, &_cp); ) |
---|
150 | } |
---|
151 | |
---|
152 | // |
---|
153 | // copy constructor |
---|
154 | inline Expr (Expr const& _expr) : |
---|
155 | first (_expr.first), |
---|
156 | last (_expr.last), |
---|
157 | mem_chunk (_expr.mem_chunk), |
---|
158 | flags (_expr.flags) |
---|
159 | { |
---|
160 | // |
---|
161 | // increment a reference counter to allocated block |
---|
162 | mem_chunk->inc_ref_count(); |
---|
163 | D( printf("+ %p(%p,%p,%p) by copy from %p\n", this, first, last, mem_chunk, &_expr); ) |
---|
164 | } |
---|
165 | |
---|
166 | // |
---|
167 | // generic constructor - should not be called directly |
---|
168 | inline Expr ( |
---|
169 | Term* const _first, Term* const _last, |
---|
170 | M_Chunk* const _mem_chunk, uintptr_t const _flags |
---|
171 | ) : |
---|
172 | first (_first), |
---|
173 | last (_last), |
---|
174 | mem_chunk (_mem_chunk), |
---|
175 | flags (_flags) |
---|
176 | { |
---|
177 | // |
---|
178 | // increment a reference counter to allocated block |
---|
179 | mem_chunk->inc_ref_count(); |
---|
180 | D( printf("+ %p(%p,%p,%p) by generic constructor", |
---|
181 | this, first, last, mem_chunk); ) |
---|
182 | } |
---|
183 | |
---|
184 | inline Expr (Expr const* _expr) : |
---|
185 | first (_expr->first), |
---|
186 | last (_expr->last), |
---|
187 | mem_chunk (_expr->mem_chunk), |
---|
188 | flags (_expr->flags) |
---|
189 | { |
---|
190 | // |
---|
191 | // increment a reference counter to allocated block |
---|
192 | // inc_ref_count(); |
---|
193 | D( printf("+ %p(%p,%p,%p) from *%p\n", |
---|
194 | this, first, last, mem_chunk, _expr); ) |
---|
195 | } |
---|
196 | |
---|
197 | // |
---|
198 | // destructor |
---|
199 | inline ~Expr () |
---|
200 | { |
---|
201 | D( printf("- %p(%p,%p,%p)\n", this, first, last, mem_chunk); ) |
---|
202 | drop(); |
---|
203 | } |
---|
204 | |
---|
205 | // |
---|
206 | //! Drop an expression |
---|
207 | inline void drop() |
---|
208 | { |
---|
209 | // |
---|
210 | // decrement reference counter and destroy an object if it is zero |
---|
211 | if( mem_chunk != null && !mem_chunk->dec_ref_count() ) { |
---|
212 | // |
---|
213 | // walk through and decrement reference counters on childs |
---|
214 | deref_childs(); |
---|
215 | // |
---|
216 | // destruct expression holder in memory |
---|
217 | mem_chunk->destruct( &allocator ); |
---|
218 | D( printf("-- %p\n", mem_chunk); ) |
---|
219 | } |
---|
220 | // first = last = null; |
---|
221 | mem_chunk = null; |
---|
222 | // flags = 0; |
---|
223 | } |
---|
224 | |
---|
225 | // |
---|
226 | // assignment operator |
---|
227 | inline const Expr &operator=( const Expr &_expr ) |
---|
228 | { |
---|
229 | D( printf("%p(%p,%p,%p) = %p(%p,%p,%p)\n", |
---|
230 | this, first, last, mem_chunk, |
---|
231 | &_expr, _expr.first, _expr.last, _expr.mem_chunk); ) |
---|
232 | // |
---|
233 | // if we are not assigning to self |
---|
234 | if( this != &_expr ) { |
---|
235 | // |
---|
236 | // destroy old expression |
---|
237 | drop(); |
---|
238 | // |
---|
239 | // and build a copy in place |
---|
240 | // new(this) Expr(_expr); // not very good idea indeed |
---|
241 | first = _expr.first; |
---|
242 | last = _expr.last; |
---|
243 | mem_chunk = _expr.mem_chunk; |
---|
244 | flags = _expr.flags; |
---|
245 | // |
---|
246 | // |
---|
247 | mem_chunk->inc_ref_count(); |
---|
248 | } |
---|
249 | // |
---|
250 | // return reference to self |
---|
251 | return *this; |
---|
252 | } |
---|
253 | |
---|
254 | private: |
---|
255 | |
---|
256 | // |
---|
257 | // init an expression |
---|
258 | inline void init( size_t _len, int _d ) |
---|
259 | { |
---|
260 | D( printf("init is called for %p\n", this); ) |
---|
261 | // |
---|
262 | // construct new memory chunk with a help from allocator |
---|
263 | mem_chunk = pxx::construct_mem_chunk( &allocator, _len * sizeof(Term) ); |
---|
264 | // |
---|
265 | // get pointers to the first and beyond the last terms in allocated block |
---|
266 | Term *start = static_cast<Term*>( mem_chunk->get_first() ); |
---|
267 | Term *end = static_cast<Term*>( mem_chunk->get_last () ); |
---|
268 | // |
---|
269 | // if we place expression at the left side of allocated block... |
---|
270 | if( _d > 0 ) { |
---|
271 | first = start; |
---|
272 | last = first + _len; |
---|
273 | } |
---|
274 | // |
---|
275 | // ...or at the right side of allocated block... |
---|
276 | else if( _d < 0 ) { |
---|
277 | last = end; |
---|
278 | first = last - _len; |
---|
279 | } |
---|
280 | // |
---|
281 | // ...or in the middle of allocated block |
---|
282 | else { |
---|
283 | first = start + (mem_chunk->get_size() / sizeof(Term) - _len) / 2; |
---|
284 | last = first + _len; |
---|
285 | } |
---|
286 | Term* prev = first - 1; |
---|
287 | // |
---|
288 | // if we have at least one term to the left of the first term |
---|
289 | if( prev >= start ) { |
---|
290 | // |
---|
291 | // setup border symbol |
---|
292 | prev ->data1 = SYM_BORDER; |
---|
293 | start->data1 = SYM_EMPTY; |
---|
294 | start->data2 = first - start; |
---|
295 | } |
---|
296 | // |
---|
297 | // if we have at least one term to the right of the last term |
---|
298 | if( last < end ) { |
---|
299 | // |
---|
300 | // setup border symbol |
---|
301 | last->data1 = SYM_BORDER; |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | inline void ref_childs() const |
---|
306 | { |
---|
307 | for( Term *p = first; p < last; p++ ) |
---|
308 | { |
---|
309 | if( p->is_ref() ) |
---|
310 | p->get_mem_chunk()->inc_ref_count(); |
---|
311 | } |
---|
312 | } |
---|
313 | /* |
---|
314 | Term* p = first; |
---|
315 | while (p < last) { |
---|
316 | if (p->is_ref()) { |
---|
317 | Expr e(p); |
---|
318 | e.inc_ref_count(); |
---|
319 | |
---|
320 | } |
---|
321 | p++; |
---|
322 | } |
---|
323 | } |
---|
324 | */ |
---|
325 | |
---|
326 | inline void deref_childs () const |
---|
327 | { |
---|
328 | Term *p = static_cast<Term*>( mem_chunk->get_first() ); |
---|
329 | Term *q = static_cast<Term*>( mem_chunk->get_last() ); |
---|
330 | if (p->data1 == SYM_EMPTY) p += p->data2; |
---|
331 | // ОК, сейчас попали на первый терм выражения, под которое выделялся |
---|
332 | // chunk. Так как deref_childs вызывается только из деструктора, то это |
---|
333 | // выражение всегда совпадает с *this. Или это неправда??? |
---|
334 | // |
---|
335 | // Между прочим, SYM_EMPTY нужен только для этого - находить |
---|
336 | // первоначальное выражение в chunk'е. |
---|
337 | // |
---|
338 | // Итого: |
---|
339 | // Едем по куску chunk'а, который был отдан под изначальное выражение |
---|
340 | // (для которого он выделялся). |
---|
341 | // |
---|
342 | // Для каждого встретившегося скобочного терма, уменьшаем кол-во ссылок |
---|
343 | // на него. |
---|
344 | // |
---|
345 | // Если встретили this выражение, и оно flat, то пропускаем его |
---|
346 | // полностью, что разумно. |
---|
347 | // |
---|
348 | while ((p < q) && !p->is_border()) { |
---|
349 | if (p == first && is_flat()) { p = last; continue; } |
---|
350 | if (p->is_ref()) { |
---|
351 | p->get_mem_chunk()->dec_ref_count(); |
---|
352 | } |
---|
353 | p++; |
---|
354 | } |
---|
355 | } |
---|
356 | |
---|
357 | public: |
---|
358 | |
---|
359 | inline void write (FILE* _fp) const |
---|
360 | { |
---|
361 | bool chars_flag = false; |
---|
362 | for (Term* p = first; p < last; p++) { |
---|
363 | if (p->is_sym()) { |
---|
364 | if (p->is_char()) { |
---|
365 | if (!chars_flag) { |
---|
366 | if (p != first) fputc(' ', _fp); |
---|
367 | fputc('\'', _fp); |
---|
368 | chars_flag = true; |
---|
369 | } |
---|
370 | fputc(p->get_char(), _fp); |
---|
371 | } else { |
---|
372 | FATAL("Not supported yet"); |
---|
373 | } |
---|
374 | } else { |
---|
375 | if (chars_flag) { |
---|
376 | fputc('\'', _fp); |
---|
377 | chars_flag = false; |
---|
378 | } |
---|
379 | if (p != first) fputc(' ', _fp); |
---|
380 | fputc('(', _fp); |
---|
381 | Expr e(p); |
---|
382 | e.write(_fp); |
---|
383 | fputc(')', _fp); |
---|
384 | } |
---|
385 | } |
---|
386 | if (chars_flag) { |
---|
387 | fputc('\'', _fp); |
---|
388 | } |
---|
389 | } |
---|
390 | |
---|
391 | inline void writeln (FILE* _fp) const |
---|
392 | { |
---|
393 | write (_fp); |
---|
394 | fputc('\n', _fp); |
---|
395 | } |
---|
396 | |
---|
397 | private: |
---|
398 | |
---|
399 | inline bool rt_alloc( uintptr_t _len ) const |
---|
400 | { |
---|
401 | Term *p = static_cast<Term*>( mem_chunk->get_last() ); |
---|
402 | // |
---|
403 | // Если на наш chunk есть только одна ссылка (значит с нашего выражения), |
---|
404 | // то убираем по ссылке со всех скобочных термов, которые лежат правее |
---|
405 | // нашего выражения. |
---|
406 | // |
---|
407 | // Если справа от нашего выражения есть пространство, то выставляем |
---|
408 | // границу после последнего терма нашего выражения. А почему её там не |
---|
409 | // стояло????? !!!!! |
---|
410 | // |
---|
411 | if( mem_chunk->no_extern_refs() ) |
---|
412 | { |
---|
413 | for( Term* q = last; (q < p) && (q->data1 != SYM_BORDER); q++ ) |
---|
414 | { |
---|
415 | if( q->is_ref() ) |
---|
416 | q->get_mem_chunk()->dec_ref_count(); |
---|
417 | } |
---|
418 | if( last < p ) |
---|
419 | last->data1 = SYM_BORDER; |
---|
420 | } |
---|
421 | // |
---|
422 | // Если справа от нашего выражения есть достаточно места (_len) и |
---|
423 | // выставлена граница после последнего терма (БЛИН!!! КАК она может быть |
---|
424 | // НЕ выставлена????? Если _len == 0 ???), то выставить новую границу, |
---|
425 | // если ещё остаётся место и вернуть true. |
---|
426 | // |
---|
427 | // Иначе вернуть false. |
---|
428 | // |
---|
429 | if( (last + _len <= p) && (last->data1 == SYM_BORDER) ) |
---|
430 | { |
---|
431 | if( last + _len < p ) |
---|
432 | { |
---|
433 | (last + _len)->data1 = SYM_BORDER; |
---|
434 | } |
---|
435 | return true; |
---|
436 | } |
---|
437 | else |
---|
438 | return false; |
---|
439 | } |
---|
440 | |
---|
441 | inline bool lt_alloc( uintptr_t _len ) const |
---|
442 | { |
---|
443 | Term *p = static_cast<Term*>( mem_chunk->get_first() ); |
---|
444 | if( mem_chunk->no_extern_refs() ) |
---|
445 | { |
---|
446 | for( Term* q = first - 1; (q >= p) && (q->data1 != SYM_BORDER); q-- ) |
---|
447 | { |
---|
448 | if( q->is_ref() ) |
---|
449 | q->get_mem_chunk()->dec_ref_count(); |
---|
450 | } |
---|
451 | if( first > p ) |
---|
452 | { |
---|
453 | (first - 1)->data1 = SYM_BORDER; |
---|
454 | p->data2 = first - p; |
---|
455 | } |
---|
456 | } |
---|
457 | if( (first - _len >= p) && ((first - 1)->data1 == SYM_BORDER) ) |
---|
458 | { |
---|
459 | if( first - _len > p ) |
---|
460 | { |
---|
461 | (first - (_len + 1))->data1 = SYM_BORDER; |
---|
462 | p->data2 = (first - _len) - p; |
---|
463 | } |
---|
464 | return true; |
---|
465 | } |
---|
466 | else |
---|
467 | return false; |
---|
468 | } |
---|
469 | // |
---|
470 | // Гм. Чтобы это могло лежать справа и слева от выражения, |
---|
471 | // если ref_count == 1 ??? !!!!! |
---|
472 | // |
---|
473 | |
---|
474 | public: |
---|
475 | |
---|
476 | inline Expr operator + (Expr const& _expr) const |
---|
477 | { |
---|
478 | D( printf("Adding %p to %p\n", &_expr, this); ) |
---|
479 | uintptr_t len1 = last - first; |
---|
480 | uintptr_t len2 = _expr.last - _expr.first; |
---|
481 | uintptr_t len = len1 + len2; |
---|
482 | if (len2 == 0) { |
---|
483 | #if DEBUG |
---|
484 | empty_copy++; |
---|
485 | #endif |
---|
486 | return *this; |
---|
487 | } else if (len1 == 0) { |
---|
488 | #if DEBUG |
---|
489 | empty_copy++; |
---|
490 | #endif |
---|
491 | return _expr; |
---|
492 | } else if (rt_alloc(len2)) { |
---|
493 | // |
---|
494 | // Copy second arg |
---|
495 | #if DEBUG |
---|
496 | rt_copy++; |
---|
497 | #endif |
---|
498 | if (!_expr.is_flat()) _expr.ref_childs(); |
---|
499 | Expr e(*this); |
---|
500 | e.flags |= _expr.flags; |
---|
501 | memcpy(e.last, _expr.first, len2 * sizeof(Term)); |
---|
502 | e.last += len2; |
---|
503 | return e; |
---|
504 | } else if (_expr.lt_alloc(len1)) { |
---|
505 | // |
---|
506 | // Copy first arg |
---|
507 | #if DEBUG |
---|
508 | lt_copy++; |
---|
509 | #endif |
---|
510 | if (!is_flat()) ref_childs(); |
---|
511 | Expr e(_expr); |
---|
512 | e.flags |= flags; |
---|
513 | e.first -= len1; |
---|
514 | memcpy(e.first, first, len1 * sizeof(Term)); |
---|
515 | return e; |
---|
516 | } else { |
---|
517 | // |
---|
518 | // Copy both args |
---|
519 | #if DEBUG |
---|
520 | both_copy++; |
---|
521 | #endif |
---|
522 | Expr e(len, len1 >= len2 ? 1 : -1); |
---|
523 | e.flags = flags | _expr.flags; |
---|
524 | memcpy(e.first, first, len1 * sizeof(Term)); |
---|
525 | memcpy(e.first + len1, _expr.first, len2 * sizeof(Term)); |
---|
526 | if (!e.is_flat()) e.ref_childs(); |
---|
527 | return e; |
---|
528 | } |
---|
529 | } |
---|
530 | |
---|
531 | inline Term operator () () const |
---|
532 | // inline Expr operator () () const |
---|
533 | { |
---|
534 | return Term(*this); |
---|
535 | // return Expr(Term(self)); |
---|
536 | } |
---|
537 | |
---|
538 | inline Expr operator * () const |
---|
539 | { |
---|
540 | if (last - first == 1) { |
---|
541 | return Expr(first); |
---|
542 | } else { |
---|
543 | FATAL("Expression length not equal to 1"); |
---|
544 | } |
---|
545 | } |
---|
546 | |
---|
547 | inline Expr operator + (Term const& _term) const |
---|
548 | { |
---|
549 | uintptr_t len1 = last - first; |
---|
550 | uintptr_t len = len1 + 1; |
---|
551 | if (rt_alloc(1)) { |
---|
552 | // |
---|
553 | // Copy second arg |
---|
554 | #if DEBUG |
---|
555 | rt_copy++; |
---|
556 | #endif |
---|
557 | Expr e(*this); |
---|
558 | if (_term.is_ref()) e.flags |= REF_BIT; |
---|
559 | *e.last = _term; |
---|
560 | e.last++; |
---|
561 | return e; |
---|
562 | } else { |
---|
563 | // |
---|
564 | // Copy both args |
---|
565 | #if DEBUG |
---|
566 | both_copy++; |
---|
567 | #endif |
---|
568 | Expr e(len, 1); |
---|
569 | if (!is_flat()) { |
---|
570 | e.flags = REF_BIT; |
---|
571 | ref_childs(); |
---|
572 | } |
---|
573 | if (_term.is_ref()) e.flags |= REF_BIT; |
---|
574 | memcpy(e.first, first, len1 * sizeof(Term)); |
---|
575 | *(e.first + len1) = _term; |
---|
576 | return e; |
---|
577 | } |
---|
578 | } |
---|
579 | |
---|
580 | friend |
---|
581 | inline Expr operator + (Term const& _term, Expr const& _expr) |
---|
582 | { |
---|
583 | uintptr_t len1 = _expr.last - _expr.first; |
---|
584 | uintptr_t len = len1 + 1; |
---|
585 | if (_expr.lt_alloc(1)) { |
---|
586 | // |
---|
587 | // Copy first arg |
---|
588 | #if DEBUG |
---|
589 | lt_copy++; |
---|
590 | #endif |
---|
591 | Expr e(_expr); |
---|
592 | if (_term.is_ref()) e.flags |= REF_BIT; |
---|
593 | e.first--; |
---|
594 | *e.first = _term; |
---|
595 | return e; |
---|
596 | } else { |
---|
597 | // |
---|
598 | // Copy both args |
---|
599 | #if DEBUG |
---|
600 | both_copy++; |
---|
601 | #endif |
---|
602 | Expr e(len, -1); |
---|
603 | if (!_expr.is_flat()) { |
---|
604 | e.flags = REF_BIT; |
---|
605 | _expr.ref_childs(); |
---|
606 | } |
---|
607 | if (_term.is_ref()) e.flags |= REF_BIT; |
---|
608 | memcpy(e.first + 1, _expr.first, len1 * sizeof(Term)); |
---|
609 | *(e.first) = _term; |
---|
610 | return e; |
---|
611 | } |
---|
612 | } |
---|
613 | |
---|
614 | friend |
---|
615 | inline Expr operator + (Term const& _term1, Term const& _term2) |
---|
616 | { |
---|
617 | // |
---|
618 | // Copy both args |
---|
619 | #if DEBUG |
---|
620 | both_copy++; |
---|
621 | #endif |
---|
622 | Expr e(2, 0); |
---|
623 | if (_term1.is_ref() || _term2.is_ref()) { |
---|
624 | e.flags |= REF_BIT; |
---|
625 | } |
---|
626 | *(e.first) = _term1; |
---|
627 | *(e.first + 1) = _term2; |
---|
628 | return e; |
---|
629 | } |
---|
630 | |
---|
631 | inline bool symbol_at (uintptr_t _pos) const |
---|
632 | { |
---|
633 | return (first + _pos)->is_sym(); |
---|
634 | } |
---|
635 | |
---|
636 | inline bool is_flat () const |
---|
637 | { |
---|
638 | return flags == 0; |
---|
639 | } |
---|
640 | |
---|
641 | inline bool is_empty () const |
---|
642 | { |
---|
643 | return first == last; |
---|
644 | } |
---|
645 | |
---|
646 | inline Term* get_first () const |
---|
647 | { |
---|
648 | return first; |
---|
649 | } |
---|
650 | |
---|
651 | inline Term* get_last () const |
---|
652 | { |
---|
653 | return last; |
---|
654 | } |
---|
655 | |
---|
656 | inline uintptr_t get_len () const |
---|
657 | { |
---|
658 | return last - first; |
---|
659 | } |
---|
660 | |
---|
661 | inline uintptr_t get_flags () const |
---|
662 | { |
---|
663 | return flags; |
---|
664 | } |
---|
665 | |
---|
666 | inline void dump () const |
---|
667 | { |
---|
668 | Term* p; |
---|
669 | printf ("%p, %p, %u: ", first, last, last - first); |
---|
670 | for (p = first; p < last; p++) { |
---|
671 | printf ("[%08x %08x]", p->data1, p->data2); |
---|
672 | } |
---|
673 | printf ("\n"); |
---|
674 | } |
---|
675 | |
---|
676 | friend |
---|
677 | inline bool eq ( |
---|
678 | Term const* _f1, Term const* _l1, Term const* _f2, Term const* _l2 |
---|
679 | ) |
---|
680 | { |
---|
681 | if ((_l1 - _f1) == (_l2 - _f2)) { |
---|
682 | for (; _f1 < _l1; _f1++, _f2++) { |
---|
683 | if (*_f1 != *_f2) return false; |
---|
684 | } |
---|
685 | return true; |
---|
686 | } |
---|
687 | return false; |
---|
688 | } |
---|
689 | |
---|
690 | friend |
---|
691 | inline bool eq_expr ( |
---|
692 | const Expr &_e1, uintptr_t _pos1, uintptr_t _len1, |
---|
693 | const Expr &_e2, uintptr_t _pos2, uintptr_t _len2 |
---|
694 | ) |
---|
695 | { |
---|
696 | if (_len1 == _len2) { |
---|
697 | Term *p1 = _e1.get_first() + _pos1; |
---|
698 | Term *p2 = _e2.get_first() + _pos2; |
---|
699 | Term *l1 = p1 + _len1; |
---|
700 | for (; p1 < l1; p1++, p2++) { |
---|
701 | if (*p1 != *p2) return false; |
---|
702 | } |
---|
703 | return true; |
---|
704 | } |
---|
705 | return false; |
---|
706 | } |
---|
707 | |
---|
708 | |
---|
709 | friend |
---|
710 | inline bool flat_eq ( |
---|
711 | const Expr &_e1, uintptr_t _pos1, |
---|
712 | const Expr &_e2, uintptr_t _pos2, uintptr_t _len |
---|
713 | ) |
---|
714 | { |
---|
715 | Term *p1 = _e1.get_first() + _pos1; |
---|
716 | Term *p2 = _e2.get_first() + _pos2; |
---|
717 | Term *l1 = p1 + _len; |
---|
718 | for (; p1 < l1; p1++, p2++) { |
---|
719 | if (p1->get_type() != p2->get_type() || p1->data2 != p2->data2) |
---|
720 | return false; |
---|
721 | } |
---|
722 | return true; |
---|
723 | } |
---|
724 | |
---|
725 | friend |
---|
726 | inline bool operator == (Term const& _t1, Term const& _t2) |
---|
727 | { |
---|
728 | if (_t1.is_sym() && _t2.is_sym()) { |
---|
729 | if (_t1.get_type() == _t2.get_type()) { |
---|
730 | if (_t1.data2 == _t2.data2) { |
---|
731 | return true; |
---|
732 | } |
---|
733 | } |
---|
734 | } else if (_t1.is_ref() && _t2.is_ref()) { |
---|
735 | return |
---|
736 | eq(_t1.get_first(), _t1.get_last(), _t2.get_first(), _t2.get_last()); |
---|
737 | } |
---|
738 | return false; |
---|
739 | } |
---|
740 | |
---|
741 | // _t1.is_sym() && _t2.is_sym() |
---|
742 | // have_same_type(_t1, _t2) |
---|
743 | // _t1.data2 == _t2.data2 || (_t1.is_compound() && _t1->data2 == _t2->data2) |
---|
744 | // В принципе, компилятор мог бы знать с каким типом мы имеем дело. Тогда можно |
---|
745 | // было бы избежать лишней проверки is_compound(). |
---|
746 | // _t1.is_ref() && _t2.is_ref() |
---|
747 | |
---|
748 | friend |
---|
749 | inline bool operator != (Term const& _t1, Term const& _t2) |
---|
750 | { |
---|
751 | return !(_t1 == _t2); |
---|
752 | } |
---|
753 | |
---|
754 | inline bool operator == (Expr const& _expr) const |
---|
755 | { |
---|
756 | return eq(first, last, _expr.first, _expr.last); |
---|
757 | } |
---|
758 | |
---|
759 | inline bool operator != (Expr const& _expr) const |
---|
760 | { |
---|
761 | return !eq(first, last, _expr.first, _expr.last); |
---|
762 | } |
---|
763 | |
---|
764 | inline M_Chunk *get_mem_chunk() |
---|
765 | { |
---|
766 | return mem_chunk; |
---|
767 | } |
---|
768 | |
---|
769 | inline void set_mem_chunk( M_Chunk *_ptr ) |
---|
770 | { |
---|
771 | mem_chunk = _ptr; |
---|
772 | } |
---|
773 | |
---|
774 | class Iterator |
---|
775 | { |
---|
776 | |
---|
777 | private: |
---|
778 | |
---|
779 | Expr& expr ; |
---|
780 | Term* ptr ; |
---|
781 | |
---|
782 | public: |
---|
783 | |
---|
784 | inline Iterator (Expr& _expr) : |
---|
785 | expr (_expr), |
---|
786 | ptr (_expr.first) |
---|
787 | {} |
---|
788 | |
---|
789 | inline ~Iterator () |
---|
790 | {} |
---|
791 | |
---|
792 | inline operator bool () const |
---|
793 | { |
---|
794 | return (ptr < expr.last) && (ptr >= expr.first); |
---|
795 | } |
---|
796 | |
---|
797 | inline Term* operator -> () const |
---|
798 | { |
---|
799 | #ifdef PARANOIA |
---|
800 | if (!*this) FATAL("Attempt to obtain pointer to invalid term"); |
---|
801 | #endif |
---|
802 | return ptr; |
---|
803 | } |
---|
804 | |
---|
805 | inline Iterator& operator ++ () |
---|
806 | { |
---|
807 | ptr++; |
---|
808 | return *this; |
---|
809 | } |
---|
810 | |
---|
811 | inline Iterator& operator ++ (int) |
---|
812 | { |
---|
813 | return operator++(); |
---|
814 | } |
---|
815 | |
---|
816 | inline Iterator& operator -- () |
---|
817 | { |
---|
818 | ptr--; |
---|
819 | return *this; |
---|
820 | } |
---|
821 | |
---|
822 | inline Iterator& operator -- (int) |
---|
823 | { |
---|
824 | return operator--(); |
---|
825 | } |
---|
826 | |
---|
827 | inline Iterator& operator += (int _offset) |
---|
828 | { |
---|
829 | ptr +=_offset; |
---|
830 | return *this; |
---|
831 | } |
---|
832 | |
---|
833 | inline Iterator& operator -= (int _offset) |
---|
834 | { |
---|
835 | ptr -=_offset; |
---|
836 | return *this; |
---|
837 | } |
---|
838 | |
---|
839 | }; |
---|
840 | |
---|
841 | }; |
---|
842 | |
---|
843 | // |
---|
844 | // is needed for () operation |
---|
845 | inline Term::Term (Expr const& _expr) : |
---|
846 | data1 ((uintptr_t)_expr.first | ORDER1(_expr.mem_chunk->get_order())), |
---|
847 | data2 ((uintptr_t)_expr.last | ORDER2(_expr.mem_chunk->get_order())) |
---|
848 | { |
---|
849 | D( printf("+ term %p from expression %p(%p,%p,%p)\n", |
---|
850 | this, &_expr, _expr.first, _expr.last, _expr.mem_chunk); ) |
---|
851 | data1 |= (_expr.flags & REF_BIT); |
---|
852 | _expr.mem_chunk->inc_ref_count(); |
---|
853 | } |
---|
854 | |
---|
855 | template <Direction D> |
---|
856 | class SplitIterator |
---|
857 | { |
---|
858 | |
---|
859 | Expr lt ; |
---|
860 | Expr rt ; |
---|
861 | bool state ; |
---|
862 | |
---|
863 | public: |
---|
864 | |
---|
865 | inline SplitIterator (Expr const& _expr, uintptr_t _min_len = 0) |
---|
866 | { |
---|
867 | FATAL("Not supported yet"); |
---|
868 | } |
---|
869 | |
---|
870 | ~SplitIterator () |
---|
871 | {} |
---|
872 | |
---|
873 | inline SplitIterator& operator ++ () { |
---|
874 | if (lt.last < rt.last) { |
---|
875 | if (lt.last->is_ref()) lt.flags |= REF_BIT; |
---|
876 | lt.last++; |
---|
877 | rt.first++; |
---|
878 | } else { |
---|
879 | state = false; |
---|
880 | } |
---|
881 | return *this; |
---|
882 | } |
---|
883 | |
---|
884 | inline SplitIterator& operator -- () { |
---|
885 | if (lt.first < rt.first) { |
---|
886 | lt.last--; |
---|
887 | rt.first--; |
---|
888 | if (rt.first->is_ref()) rt.flags |= REF_BIT; |
---|
889 | } else { |
---|
890 | state = false; |
---|
891 | } |
---|
892 | return *this; |
---|
893 | } |
---|
894 | |
---|
895 | inline SplitIterator& operator ++ (int) { |
---|
896 | return operator++(); |
---|
897 | } |
---|
898 | |
---|
899 | inline SplitIterator& operator -- (int) { |
---|
900 | return operator--(); |
---|
901 | } |
---|
902 | |
---|
903 | inline operator bool () |
---|
904 | { |
---|
905 | return state; |
---|
906 | } |
---|
907 | |
---|
908 | inline Expr const& get_left () const |
---|
909 | { |
---|
910 | return lt; |
---|
911 | } |
---|
912 | |
---|
913 | inline Expr const& get_right () const |
---|
914 | { |
---|
915 | return rt; |
---|
916 | } |
---|
917 | |
---|
918 | }; |
---|
919 | |
---|
920 | template <> |
---|
921 | inline SplitIterator<d_lt>::SplitIterator ( |
---|
922 | Expr const& _expr, uintptr_t _min_len |
---|
923 | ) : |
---|
924 | lt (_expr.get_first(), _expr.get_first() + _min_len, |
---|
925 | _expr.mem_chunk, 0), |
---|
926 | rt (_expr.get_first() + _min_len, _expr.get_last(), |
---|
927 | _expr.mem_chunk, 0), |
---|
928 | state (true) |
---|
929 | {} |
---|
930 | |
---|
931 | #define iter(e) e##_iter |
---|
932 | |
---|
933 | #define lsplit(e, minlen, le, re) \ |
---|
934 | SplitIterator<d_lt> iter(e)(e, minlen); \ |
---|
935 | Expr const& le = iter(e).get_left(); \ |
---|
936 | Expr const& re = iter(e).get_right() |
---|
937 | |
---|
938 | #if 0 |
---|
939 | #define lsplit_e(e, le, re) \ |
---|
940 | SplitIterator<d_lt> iter(e)(e, 0); \ |
---|
941 | Expr const& le = iter(e).get_left(); \ |
---|
942 | Expr const& re = iter(e).get_right() |
---|
943 | |
---|
944 | #define lsplit_v(e, le, re) \ |
---|
945 | SplitIterator<d_lt> iter(e)(e, 1); \ |
---|
946 | Expr const& le = iter(e).get_left(); \ |
---|
947 | Expr const& re = iter(e).get_right() |
---|
948 | |
---|
949 | #define can_lsplit_s(e) \ |
---|
950 | (e.get_len() >= 1 && e.get_first()->is_sym()) |
---|
951 | |
---|
952 | #define lsplit_s(e, le, re) \ |
---|
953 | Expr le(e.get_first(), e.get_first() + 1, e.get_ref_count(), 0); \ |
---|
954 | Expr re(e.get_first() + 1, e.get_last(), e.get_ref_count(), e.get_flags()); \ |
---|
955 | |
---|
956 | #define can_lsplit_t(e) \ |
---|
957 | (e.get_len() >= 1) |
---|
958 | |
---|
959 | #define lsplit_t(e, le, re) \ |
---|
960 | Expr le( \ |
---|
961 | e.get_first(), e.get_first() + 1, \ |
---|
962 | e.get_ref_count(), e.get_first()->is_sym() ? 0 : REF_BIT \ |
---|
963 | ); \ |
---|
964 | Expr re(e.get_first() + 1, e.get_last(), e.get_ref_count(), e.get_flags()); \ |
---|
965 | |
---|
966 | #define can_lsplit_h(e, he) ( \ |
---|
967 | e.get_len() >= he.get_len() && \ |
---|
968 | eq( \ |
---|
969 | e.get_first(), e.get_first() + he.get_len(), \ |
---|
970 | he.get_first(), he.get_last() \ |
---|
971 | ) \ |
---|
972 | ) |
---|
973 | |
---|
974 | #define lsplit_h(e, le, re) \ |
---|
975 | Expr re( \ |
---|
976 | e.get_first() + le.get_len(), e.get_last(), \ |
---|
977 | e.get_ref_count(), e.get_flags() \ |
---|
978 | ); |
---|
979 | #endif |
---|
980 | |
---|
981 | } |
---|
982 | |
---|
983 | #endif // __rf_expr_hh__ |
---|