home *** CD-ROM | disk | FTP | other *** search
- // This may look like C code, but it is really -*- C++ -*-
- /*
- Copyright (C) 1988 Free Software Foundation
- written by Doug Lea (dl@rocky.oswego.edu)
- based on code by Marc Shapiro (shapiro@sor.inria.fr)
-
- This file is part of GNU CC.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies.
- */
-
- #include "<T>.MPlex.h"
-
- // <T>MChunk support
-
-
- <T>MChunk::<T>MChunk(<T>* d,
- int baseidx,
- int lowidx,
- int fenceidx,
- int topidx)
- : <T>IChunk(d, baseidx, lowidx, fenceidx, topidx)
- {
- unused = fence - low;
- unsigned msize = (top - base)/_MAP_BITS + 1;
- map = (unsigned long *) (new long[msize]);
- bzero((void*)map, msize * sizeof(long));
- }
-
- void <T>MChunk:: shrink_high ()
- {
- if (fence <= low) empty_error();
- --fence;
- if (!valid(fence))
- --unused;
- else
- free(fence);
- reset_high();
- }
-
- void <T>MChunk:: shrink_low ()
- {
- if (fence <= low) empty_error();
- if (!valid(low))
- --unused;
- else
- free(low);
- ++low;
- reset_low();
- }
-
- void <T>MChunk::clear(int lo)
- {
- int s = top - base;
- low = base = fence = lo;
- top = base + s;
- unused = 0;
- bzero((void*)map, ((top - base)/_MAP_BITS + 1) * sizeof(long));
- }
-
- int <T>MChunk::del(int idx)
- {
- if (idx < low || idx >= fence) index_error();
- int v = valid(idx);
- if (v)
- {
- free(idx);
- ++unused;
- }
- return v;
- }
-
-
- int <T>MChunk::undel(int idx)
- {
- if (idx < low || idx >= fence) index_error();
- int v = valid(idx);
- if (!v)
- {
- mark(idx);
- --unused;
- }
- return v;
- }
-
- int <T>MChunk::unused_index()
- {
- if (unused_indices() == 0) index_error();
- int slot;
- if (low == base) // can traverse 32 slots at a time
- {
- int blk = 0;
- while (map[blk] == ~0L) ++blk;
- slot = blk * _MAP_BITS + base;
- }
- else
- slot = low;
-
- while(valid(slot)) ++slot;
- return slot;
- }
-
- int <T>MChunk::first_index()
- {
- if (empty()) return fence;
- int slot;
- if (low == base)
- {
- int blk = 0;
- while (map[blk] == 0) ++blk;
- slot = blk * _MAP_BITS + base;
- }
- else
- slot = low;
-
- while(!valid(slot)) ++slot;
- return slot;
- }
-
- int <T>MChunk::last_index()
- {
- if (empty()) return low - 1;
- int slot;
- if (top == fence)
- {
- int blk = (top - base) / _MAP_BITS;
- while (map[blk] == 0) --blk;
- slot = blk * _MAP_BITS + base + _MAP_BITS - 1;
- }
- else
- slot = fence - 1;
-
- while(!valid(slot)) --slot;
- return slot;
- }
-
-
- int <T>MChunk:: OK()
- {
- int v = data != 0; // have some data
- v &= map != 0; // and a map
- v &= base <= low; // ok, index-wise
- v &= low <= fence;
- v &= fence <= top;
-
- v &= nxt->prev() == this; // and links are OK
- v &= prv->next() == this;
-
- int bitcount = 0; // and unused count correct
- for (int i = low; i < fence; ++i) if (!valid(i)) ++bitcount;
- v &= unused == bitcount;
-
- if (!v) error("invariant failure");
- return(v);
- }
-
- <T>* <T>MChunk::succ(<T>* p)
- {
- int i = ((int) p - (int) data) / sizeof(<T>) + base + 1;
- if (p == 0 || i < low) return 0;
- while (i < fence && !valid(i)) ++i;
- if (i >= fence) return 0;
- return pointer_to(i);
- }
-
- <T>* <T>MChunk::pred(<T>* p)
- {
- int i = ((int) p - (int) data) / sizeof(<T>) + base - 1;
- if (p == 0 || i >= fence) return 0;
- while (i >= low && !valid(i)) --i;
- if (i < low) return 0;
- return pointer_to(i);
- }
-
- <T>* <T>MChunk::first_pointer()
- {
- if (empty()) return 0;
- int slot;
- if (low == base)
- {
- int blk = 0;
- while (map[blk] == 0) ++blk;
- slot = blk * _MAP_BITS + base;
- }
- else
- slot = low;
-
- while(!valid(slot)) ++slot;
- return pointer_to(slot);
- }
-
- <T>* <T>MChunk::last_pointer()
- {
- if (empty()) return 0;
- int slot;
- if (top == fence)
- {
- int blk = (top - base) / _MAP_BITS;
- while (map[blk] == 0) --blk;
- slot = blk * _MAP_BITS + base + _MAP_BITS - 1;
- }
- else
- slot = fence - 1;
-
- while(!valid(slot)) --slot;
- return pointer_to(slot);
- }
-
- <T>MPlex:: <T>MPlex()
- {
- mods = unused = 0;
- lo = fnc = 0;
- csize = DEFAULT_INITIAL_CAPACITY;
- <T>* data = new <T>[csize];
- hd = ch = new <T>MChunk(data, lo, lo, fnc, lo+csize);
- }
-
- <T>MPlex:: <T>MPlex(int chunksize)
- {
- if (chunksize == 0) error("invalid constructor specification");
- mods = unused = 0;
- lo = fnc = 0;
- if (chunksize > 0)
- {
- csize = chunksize;
- <T>* data = new <T>[csize];
- hd = ch = new <T>MChunk(data, lo, lo, fnc, csize);
- }
- else
- {
- csize = -chunksize;
- <T>* data = new <T>[csize];
- hd = ch = new <T>MChunk(data, chunksize, lo, fnc, fnc);
- }
- }
-
-
- <T>MPlex:: <T>MPlex(int l, int chunksize)
- {
- if (chunksize == 0) error("invalid constructor specification");
- mods = unused = 0;
- lo = fnc = l;
- if (chunksize > 0)
- {
- csize = chunksize;
- <T>* data = new <T>[csize];
- hd = ch = new <T>MChunk(data, lo, lo, fnc, csize+lo);
- }
- else
- {
- csize = -chunksize;
- <T>* data = new <T>[csize];
- hd = ch = new <T>MChunk(data, chunksize+lo, lo, fnc, fnc);
- }
- }
-
-
- void <T>MPlex::make_initial_chunks(int up = 1)
- {
- int need = fnc - lo;
- hd = 0;
- if (up)
- {
- int l = lo;
- do
- {
- int sz;
- if (need >= csize)
- sz = csize;
- else
- sz = need;
- <T>* data = new <T> [csize];
- <T>MChunk* h = new <T>MChunk(data, l, l, l+sz, l+csize);
- if (hd != 0)
- h->link_to_next(hd);
- else
- hd = h;
- l += sz;
- need -= sz;
- } while (need > 0);
- }
- else
- {
- int hi = fnc;
- do
- {
- int sz;
- if (need >= csize)
- sz = csize;
- else
- sz = need;
- <T>* data = new <T> [csize];
- <T>MChunk* h = new <T>MChunk(data, hi-csize, hi-sz, hi, hi);
- if (hd != 0)
- h->link_to_next(hd);
- hd = h;
- hi -= sz;
- need -= sz;
- } while (need > 0);
- }
- ch = (<T>MChunk*) hd;
- }
-
- <T>MPlex:: <T>MPlex(int l, int hi, const <T&> initval, int chunksize = 0)
- {
- mods = unused = 0;
- lo = l;
- fnc = hi + 1;
- if (chunksize == 0)
- {
- csize = fnc - l;
- make_initial_chunks(1);
- }
- else if (chunksize < 0)
- {
- csize = -chunksize;
- make_initial_chunks(0);
- }
- else
- {
- csize = chunksize;
- make_initial_chunks(1);
- }
- fill(initval);
- }
-
- <T>MPlex::<T>MPlex(const <T>MPlex& a)
- {
- mods = 0;
- lo = a.lo;
- fnc = a.fnc;
- csize = a.csize;
- unused = fnc - lo;
- hd = 0;
- <T>IChunk* p = a.hd;
- do
- {
- <T>* data = new <T> [p->size()];
- <T>MChunk* h = new <T>MChunk(data, p->base_index(),
- p->low_index(), p->fence_index(), p->top_index());
- if (hd != 0)
- h->link_to_next(hd);
- else
- hd = h;
- p = p->next();
- } while (p != a.hd);
- ch = (<T>MChunk*) hd;
- for (int i = a.low(); i < a.fence(); a.next(i))
- {
- undel_index(i);
- (*this)[i] = a[i];
- }
- }
-
- void <T>MPlex::operator= (const <T>MPlex& a)
- {
- if (&a != this)
- {
- invalidate();
- record_change();
- lo = a.lo;
- fnc = a.fnc;
- csize = a.csize;
- unused = fnc - lo;
- hd = 0;
- <T>IChunk* p = a.hd;
- do
- {
- <T>* data = new <T> [p->size()];
- <T>MChunk* h = new <T>MChunk(data, p->base_index(),
- p->low_index(), p->fence_index(), p->top_index());
- if (hd != 0)
- h->link_to_next(hd);
- else
- hd = h;
- p = p->next();
- } while (p != a.hd);
- ch = (<T>MChunk*) hd;
- for (int i = a.low(); i < a.fence(); a.next(i))
- {
- undel_index(i);
- (*this)[i] = a[i];
- }
- }
- }
-
- int <T>MPlex::valid(int idx)
- {
- <T>MChunk* tail = (<T>MChunk*)tl();
- while (idx >= ch->fence_index())
- {
- if (ch == tail) return 0;
- ch = (<T>MChunk*)(ch->next());
- }
- while (idx < ch->low_index())
- {
- if (ch == hd) return 0;
- ch = (<T>MChunk*)(ch->prev());
- }
- return ch-><T>MChunk::valid_index(idx);
- }
-
- void <T>MPlex::cache(int idx)
- {
- <T>MChunk* tail = (<T>MChunk*)tl();
- while (idx >= ch->fence_index())
- {
- if (ch == tail) index_error();
- ch = (<T>MChunk*)(ch->next());
- }
- while (idx < ch->low_index())
- {
- if (ch == hd) index_error();
- ch = (<T>MChunk*)(ch->prev());
- }
- if (!ch-><T>MChunk::valid_index(idx)) index_error();
- }
-
- void <T>MPlex::cache(const <T>* p)
- {
- <T>MChunk* old = ch;
- while (!ch->actual_pointer(p))
- {
- ch = (<T>MChunk*)(ch->next());
- if (ch == old) index_error();
- }
- if (!ch-><T>MChunk::valid_pointer(p)) index_error();
- }
-
- int <T>MPlex::owns(Pix p)
- {
- <T>MChunk* old = ch;
- while (!ch->actual_pointer(p))
- {
- ch = (<T>MChunk*)(ch->next());
- if (ch == old) return 0;
- }
- return ch-><T>MChunk::valid_pointer(p);
- }
-
- int <T>MPlex::add_high(const <T&> elem)
- {
- record_change();
- ch = (<T>MChunk*) tl();
-
- if (!ch->can_grow_high())
- {
- <T>* data = new <T> [csize];
- ch = new <T>MChunk(data, fnc,fnc,fnc,fnc+csize);
- ch->link_to_prev(tl());
- }
-
- *((ch-><T>MChunk::grow_high())) = elem;
- return fnc++;
- }
-
- int <T>MPlex::add_low (const <T&> elem)
- {
- record_change();
- ch = (<T>MChunk*) hd;
- if (!ch->can_grow_low())
- {
- <T>* data = new <T> [csize];
- hd = new <T>MChunk(data, lo-csize, lo, lo, lo);
- hd->link_to_next(ch);
- ch = (<T>MChunk*) hd;
- }
-
- *((ch-><T>MChunk::grow_low())) = elem;
- return --lo;
- }
-
- void <T>MPlex::adjust_bounds()
- {
- ch = (<T>MChunk*) tl();
- while (ch-><T>MChunk::empty() && !one_chunk())
- {
- <T>MChunk* pred = (<T>MChunk*)(ch->prev());
- del_chunk(ch);
- pred->reset_high();
- ch = pred;
- }
- int oldfnc = fnc;
- fnc = ch->fence_index();
- unused -= oldfnc - fnc - 1;
-
- ch = (<T>MChunk*) hd;
- while (ch-><T>MChunk::empty() && !one_chunk())
- {
- hd = (<T>MChunk*)(ch->next());
- del_chunk(ch);
- ch = (<T>MChunk*) hd;
- ch->reset_low();
- }
- int oldlo = lo;
- lo = ch->low_index();
- unused -= lo - oldlo - 1;
- }
-
- int <T>MPlex::del_high ()
- {
- if (empty()) empty_error();
- record_change();
- ch = (<T>MChunk*) tl();
- ch-><T>MChunk::shrink_high();
- while (ch-><T>MChunk::empty() && !one_chunk())
- {
- <T>MChunk* pred = (<T>MChunk*)(ch->prev());
- del_chunk(ch);
- pred->reset_high();
- ch = pred;
- }
- int oldfnc = fnc;
- fnc = ch->fence_index();
- unused -= oldfnc - fnc - 1;
- return fnc - 1;
- }
-
- int <T>MPlex::del_low ()
- {
- if (empty()) empty_error();
- record_change();
- ch = (<T>MChunk*) hd;
- ch-><T>MChunk::shrink_low();
- while (ch-><T>MChunk::empty() && !one_chunk())
- {
- hd = (<T>MChunk*)(ch->next());
- del_chunk(ch);
- ch = (<T>MChunk*) hd;
- ch->reset_low();
- }
- int oldlo = lo;
- lo = ch->low_index();
- unused -= lo - oldlo - 1;
- return lo;
- }
-
- int <T>MPlex::add(const <T&> elem)
- {
- if (unused == 0)
- return add_high(elem);
- for(;;)
- {
- if (ch->unused_indices() != 0)
- {
- int i = ch->unused_index();
- undel_index(i);
- (*this)[i] = elem;
- return i;
- }
- ch = (<T>MChunk*)(ch->prev());
- }
- }
-
- int <T>MPlex::unused_index()
- {
- if (unused == 0) index_error();
- for(;;)
- {
- if (ch->unused_indices() != 0) return ch->unused_index();
- ch = (<T>MChunk*)(ch->prev());
- }
- }
-
- Pix <T>MPlex::unused_Pix()
- {
- if (unused == 0) return 0;
- for (;;)
- {
- if (ch->unused_indices() != 0) return ch->pointer_to(ch->unused_index());
- ch = (<T>MChunk*)(ch->prev());
- }
- }
-
- int <T>MPlex::del_index(int idx)
- {
- if (idx < lo || idx >= fnc) index_error();
- if (<T>MPlex::valid(idx))
- {
- ++unused;
- record_change();
- ch-><T>MChunk::del(idx);
- return 1;
- }
- else
- return 0;
- }
-
- int <T>MPlex::dopred(int idx)
- {
-
- if (idx >= fnc) idx = fnc;
- if (idx <= lo) return lo - 1;
-
- while (idx > ch->fence_index())
- {
- ch = (<T>MChunk*)(ch->next());
- }
- while (idx <= ch->low_index())
- {
- ch = (<T>MChunk*)(ch->prev());
- }
- int i = ch-><T>MChunk::pred(idx);
- if (i >= ch->low_index() || i < lo)
- return i;
- for (;;)
- {
- ch = (<T>MChunk*)(ch->prev());
- i = ch-><T>MChunk::last_index();
- if (i >= ch->low_index() || i < lo)
- return i;
- }
- }
-
-
- int <T>MPlex::dosucc(int idx)
- {
-
- if (idx < lo) idx = lo;
- if (idx >= fnc - 1) return fnc;
-
- while (idx >= ch->fence_index())
- {
- ch = (<T>MChunk*)(ch->next());
- }
- while (idx < ch->low_index())
- {
- ch = (<T>MChunk*)(ch->prev());
- }
- int i = ch-><T>MChunk::succ(idx);
- if (i < ch->fence_index() || i >= fnc)
- return i;
- for (;;)
- {
- ch = (<T>MChunk*)(ch->next());
- i = ch-><T>MChunk::first_index();
- if (i < ch->fence_index() || i >= fnc)
- return i;
- }
- }
-
- void <T>MPlex::prev(Pix& i)
- {
- if (i == 0) return;
- <T>* p = (<T>*) i;
- <T>MChunk* old = ch;
- while (!ch->actual_pointer(p))
- {
- ch = (<T>MChunk*)(ch->prev());
- if (ch == old) { i = 0; return; }
- }
- <T>* q = ch-><T>MChunk::pred(p);
- if (q != 0 || ch == hd)
- { i = Pix(q); return; }
- else
- {
- for(;;)
- {
- ch = (<T>MChunk*)(ch->prev());
- q = ch-><T>MChunk::last_pointer();
- if (q != 0 || ch == hd)
- { i = Pix(q); return; }
- }
- }
- }
-
- void <T>MPlex::next(Pix& i)
- {
- if (i == 0) return;
- <T>* p = (<T>*) i;
- <T>MChunk* tail = (<T>MChunk*)(tl());
- <T>MChunk* old = ch;
- while (!ch->actual_pointer(p))
- {
- ch = (<T>MChunk*)(ch->next());
- if (ch == old) { i = 0; return; }
- }
- <T>* q = ch-><T>MChunk::succ(p);
- if (q != 0 || ch == tail)
- { i = Pix(q); return; }
- else
- {
- for(;;)
- {
- ch = (<T>MChunk*)(ch->next());
- q = ch-><T>MChunk::first_pointer();
- if (q != 0 || ch == tail)
- { i = Pix(q); return; }
- }
- }
- }
-
-
- void <T>MPlex::undel_index(int idx)
- {
- if (idx < lo || idx >= fnc) index_error();
- while (idx >= ch->fence_index())
- {
- ch = (<T>MChunk*)(ch->next());
- }
- while (idx < ch->low_index())
- {
- ch = (<T>MChunk*)(ch->prev());
- }
- int was_present = ch-><T>MChunk::undel(idx);
- if (!was_present)
- {
- record_change();
- --unused;
- }
- return;
- }
-
- void <T>MPlex::clear()
- {
- if (fnc != lo)
- {
- record_change();
- ch = (<T>MChunk*)tl();
- while (ch != hd)
- {
- <T>MChunk* prv = (<T>MChunk*)(ch->prev());
- del_chunk(ch);
- ch = prv;
- }
- ch-><T>MChunk::clear(lo);
- fnc = lo;
- unused = 0;
- }
- }
-
- int <T>MPlex::OK ()
- {
- int v = hd != 0; // at least one chunk
-
- int found_ch = 0; // to make sure ch is in list;
-
- int count = 0; // to count unused slots
-
- <T>MChunk* t = (<T>MChunk*)(hd);
-
- int gap = t->low_index() - lo;
- v &= gap == 0; // hd lo not less than lo.
- count += gap;
-
- for (;;)
- {
- if (t == ch) ++found_ch;
- v &= t-><T>MChunk::OK(); // each chunk is OK
- count += t->unused_indices();
- if (t == tl())
- break;
- else // and has indices less than succ
- {
- gap = t->next()->base_index() - t->top_index();
- v &= gap == 0;
- count += gap;
-
- if (t != hd) // internal chunks can't grow
- v &= !t->can_grow_low() && !t->can_grow_high();
-
- t = (<T>MChunk*)(t->next());
- }
- }
- gap = fnc - t->fence_index();
- v &= gap == 0;
- count += gap;
-
- v &= count == unused; // chunk counts agree with plex
-
- v &= found_ch == 1;
- if (!v) error("invariant failure");
- return v;
- }
-
-