Answers/Solutions to Exercises in Chapter 9, Exercise 6
E6: Redo exercise 4 to obtain a compacted version of the tree.
S6: A sample program is below. Points to focus on: ARENA was changed a bit to provide some info like how many segments used, of what size, and total number of bytes allocated. Another change concerns the problem mention in Exercise 4 --- only trees allocated from the same arena were possible. So here we can have several arenas and each tree can be allocated in its own arena. For that end some changes must be made (like not having the arena as a static object of the classes CHILD, NODE, and TREE), and arenas are passed along, so every CHILD, or NODE, or TREE object knows its arena. Care must be taken that all elements of a tree are within the same arena. Now the compactification is achieved by creating the tree (as in Exercise 4), then finding out the total of bytes allocated, creating a new arena with the size of segment being the total size of bytes, and a copy of the tree is created in that new arena (simple statistics should show that the new arena has only 1 segment). Then the tree is relativized, and that provides the compacted version of the tree. We copy it as is to yet another arena, absolutize it there, and see if we got our tree back, as certainly we did.
#include <iostream.h> #include <stdlib.h> class ARENA { public: ARENA(int ss,int a) { arena = 0; last_segment = -1; segment_size = ss; //arena segment size align = a; //memory alignment boundary } ~ARENA() { for(int i = 0; i <= last_segment; i++) delete[] arena[i]; delete[] arena; } ARENA& operator= (const ARENA& ar) { int i, j; for(i = 0; i <= last_segment; i++) // destroy old data delete[] arena[i]; delete[] arena; arena = 0; segment_size = ar.segment_size; // copy new data next_ind = ar.next_ind; last_segment = ar.last_segment; align = ar.align; arena = new char* [last_segment+1]; for(i = 0; i <= last_segment; i++) { arena[i] = new char[segment_size]; for(j = 0; j < segment_size; j++) arena[i][j] = ar.arena[i][j]; } return *this; } void* Alloc(size_t s) { //alloc. memory of size s from its segment char** a; //obtains a new segment if need be int i; void* ret; if (arena == 0) { //alloc 1st segment arena = new char*[1]; last_segment = 0; arena[0] = new char[segment_size]; last_segment = 0; next_ind = 0; }else if (s > (size_t) segment_size-next_ind) { last_segment++; a = new char*[last_segment+1]; for(i = 0; i < last_segment; i++) a[i] = arena[i]; delete[] arena; arena = a; arena[last_segment] = new char[segment_size]; next_ind = 0; } ret = (void*) &arena[last_segment][next_ind]; next_ind += s; // align next_ind for future use while(((long)&arena[last_segment][next_ind]%align) != 0) if (next_ind >= segment_size) break; // if next_ind runs to the end of the segment, no problem // on next Alloc() a new segment will be enforced return ret; } void* Relativize(void* s) { //relativizes address s with respect short segment, offset, *ip; //to the segment that s belongs to void* res; if (s == 0) return 0; for(segment = 0; segment <= last_segment; segment++) { if (s < arena[segment]) continue; if (s >= arena[segment]+segment_size) continue; // so we have the right segment offset = (short) ((long)s - (long)arena[segment]); segment++; // shift segment by 1 so the beginning does ip = (short*)&res; // not get relativized to 0 *ip++ = segment; *ip = offset; return res; } return 0; } void* Absolutize(void* s) { //absolutize relative address s short *ip, segment, offset; void* r; if (s == 0) return 0; r = s; ip = (short*) &r; segment = *ip++; segment--; // undo the shift offset = *ip; return (void*)&arena[segment][offset]; } int TotalSize() { int res; if (last_segment < 0) return 0; res = last_segment*segment_size + next_ind; return res; } short NumberOfSegments() { return last_segment+1; } short SegmentSize() { return segment_size; } protected: char** arena; short last_segment; short segment_size; short next_ind; short align; };//end class ARENA class TREE; class NODE; class CHILDREN; class CHILD { friend class NODE; friend class TREE; friend class CHILDREN; public: CHILD(NODE* n,ARENA* a) { arena=a; node=n; next=0; } CHILD* Attach(NODE* n) { next = new(arena) CHILD(n,arena); return next; } protected: NODE* node; CHILD* next; ARENA* arena; //the following methods are only for arena allocation void* operator new(size_t s,ARENA* a) { return a->Alloc(s); } // we will deallocate the whole arena instead void operator delete(void* s,ARENA* a) { return; } // the implementation of these three functions must be postponed after // the definition of NODE void* Relativize(); static CHILD* Absolutize(void* c,ARENA* a); CHILD* Copy(ARENA*); // make a copy ofyourself in a different arena };//end class CHILD class NODE { friend class CHILD; friend class TREE; public: NODE(char v,ARENA* a) { arena=a; value=v; first=0; } void Attach(NODE *n) { if (first==0) first=new(arena) CHILD(n,arena); else{ for(CHILD* p=first; p->next!=0; p=p->next); p->Attach(n); } } protected: char value; CHILD* first; ARENA *arena; //the following methods are only for arena allocation void* operator new(size_t s,ARENA* a) { return a->Alloc(s); } // we will deallocate the whole arena instead void operator delete(void* s,ARENA* a) { return; } void Show() { CHILD* p; for(p=first; p!=0; p=p->next) p->node->Show(); cout << ' ' << value; } void ShowAddresses() { CHILD* p; int i; cout << value << " [" << this << "]\n"; for(i=1,p=first; p!=0; p=p->next,i++) { cout << p << " [child " << i << " of " << value << "]\n"; p->node->ShowAddresses(); } } void* Relativize() { if (first!=0) first=(CHILD*)first->Relativize(); return arena->Relativize(this); } static NODE* Absolutize(void* n,ARENA* a) { NODE* node; node=(NODE*)a->Absolutize(n); if (node->first!=0) node->first=CHILD::Absolutize((void*)node->first,a); return node; } NODE* Copy(ARENA* a) { // make a copy of yourself in a different arena NODE* n = new(a) NODE(value,a); if (first!=0) n->first=first->Copy(a); return n; } };//end class NODE // the implementation of this function must have been postponed after // NODE has been defined // function CHILD::Relativize ------------------------------------ void* CHILD::Relativize() { if (node!=0) node=(NODE*)node->Relativize(); if (next!=0) next=(CHILD*) next->Relativize(); return arena->Relativize(this); }// end CHILD::Relativize // the implementation of this static function must have been postponed // after NODE has been defined // function CHILD::Absolutize ------------------------------------ CHILD* CHILD::Absolutize(void* c,ARENA *a) { CHILD* child; child=(CHILD*)a->Absolutize(c); if (child->node!=0) child->node=NODE::Absolutize((void*)child->node,a); if (child->next!=0) child->next=CHILD::Absolutize((void*)child->next,a); return child; }// end CHILD::Absolutize // the implementation of this function must have been postponed after // NODE has been defined CHILD* CHILD::Copy(ARENA* a) { // make a copy of yourself in a different arena NODE* n = node->Copy(a); CHILD* c = new(a) CHILD(n,a); if (next!=0) c->next=next->Copy(a); return c; }//end CHILD::Copy class TREE { public: TREE(ARENA *a) { arena=a; root = 0; } void Show() { if (root == 0) return; root->Show(); cout << '\n' << flush; } void ShowAddresses() { if (root==0) return; root->ShowAddresses(); } void SetRoot(char c) { root = new(arena) NODE(c,arena); } void SetRoot(NODE* r) { root=r; } NODE* GetRoot() { return root; } void Attach(char c,char v) { if (root==0) return; // traverse the tree and find the node with value v if (root->value==v) { NODE* n = new(arena) NODE(c,arena); root->Attach(n); return; }else Attach1(root,c,v); } void* Relativize() { if (root!=0) root=(NODE*)root->Relativize(); return root; } void Absolutize(void* r) { if (r == 0) return; root = NODE::Absolutize(r,arena); } TREE* Copy(ARENA* a) { // make a copy of yourself in a different arena if (arena==0) return 0; // fail, not ready for copying if (root==0) return 0; // fail, not ready for copying NODE* root1 = root->Copy(a); TREE* t = new TREE(a); t->SetRoot(root1); return t; } protected: NODE* root; ARENA* arena; void Attach1(NODE* p,char c,char v) { if (p==0) return; for(CHILD* q=p->first; q!=0; q=q->next) { if (q->node->value==v) { NODE* t=new(arena) NODE(c,arena); q->node->Attach(t); return; }else Attach1(q->node,c,v); } } };//end class TREE // function main ----------------------------------------------- int main() { ARENA arena(24,4); // create arena TREE t(&arena); // create empty tree with arena // create the body of the tree t.SetRoot('d'); t.Attach('a','d'); t.Attach('b','d'); t.Attach('c','d'); t.Attach('e','c'); t.Attach('g','c'); t.Attach('h','e'); t.ShowAddresses(); // show the nodes and address of the tree cout << "\n\narena has " << arena.NumberOfSegments() << " segments of size " << arena.SegmentSize() << " with " << arena.TotalSize() << " bytes used in total\n\n" << flush; // create a new arena that will accommodate a copy of the tree, but with just // one segment int total = arena.TotalSize(); ARENA arena1(total,4); TREE* t1 = t.Copy(&arena1); if (t1!=0) t1->ShowAddresses(); cout << "\n\narena has " << arena1.NumberOfSegments() << " segments of size " << arena1.SegmentSize() << " with " << arena1.TotalSize() << " bytes used in total\n\n" << flush; void* root = t1->Relativize(); // now tree is compacted in one segment // create a different arena ARENA arena2(0,0); arena2=arena1; // copy the data to arena2 from arena1 TREE t2(&arena2); // create a tree with serialized body in arena2 t2.Absolutize(root);// absolutize the tree in arena2 t2.ShowAddresses(); // show the nodes and addresses of the tree t1->Absolutize(root); t1->ShowAddresses(); return 0; }//end main
Back to Answers/Solutions Index Back to Answers/Solutions for Chapter 9 Index