Revision dated 06/19/17
Educational Objectives: After completing this assignment, the student should be able to accomplish the following:
======================================================================= Rubric used in assessment ----------------------------------------------------------------------- builds student makefile [0..5]: x assess makefile [0..5]: x tests: fmap.x [OAA operations Put, Get, Retrieve, Erase] [0..8]: x fmap.x [Iterator operations, Includes] [0..8]: x fmap.x [standard traversals, Analysis] [0..8]: x wb3.x [english text only] [0..8]: x mmap.x [hammer test] [0..8]: x other: log & testing report [-50..0]: ( x) requirements and specs [-50..0]: ( x) software engineering [-50..0]: ( x) dated submission deduction [2 pts each]: ( x) -- total: [0..50]: 50 =======================================================================
Background Knowledge Required: Be sure that you have mastered the
material in these chapters before beginning the assignment:
Iterators,
Introduction to Sets,
Introduction to Maps,
Binary Search Trees,
Balanced BSTs, and
BST Iterators.
Operational Objectives: Implement class templates ConstThreadedMapIterator and ThreadedMapIterator and use these classes to complete the implementations of the class template Map_Threaded.
Deliverables:
map_bst_threaded.h # Map_BST class template mapiter_threaded.h # ConstThreadedMapIterator and ThreadedMapIterator class templates wordbench3.h # refactors wordbench2 using fsu::Map_Threaded wordbench3.cpp # " " " " wordify.cpp # same file as used for previous project - submitted for convenience makefile.wb3 # makefile builds fmap.x, mmap.x, and wb3.x log.txt # your project work log
This project explores the addition of Iterator classes associated with the Ordered Associative Array (OAA) class that was the subject of the previous project. Recall in the previous project, we did not have iterators, but nevertheless created a servicable Map-like container supporting the associative array API (Put, Get, Retrieve). We had to go to extraordinary lengths to obtain a useful traversal, and we were handicapped by the lack of equality operator among OAA objects. We had no way to make sense out of the fundamental Table operation Includes. (But Retrieve is a useful work-around.) Features we will easily obtain using iterators include the following:
And we may put aside the special methods for traverals and Display and their recursive implementations. The two tools are compared in the following table.
Associative Array API
Put(key,data) // unimodal insert of (key,data) pair; alias for Insert &data = Get(key) // returns &data stored at key; ensures key exists in table bool Retrieve(key,&data) const // if true, &data references data stored with key Remove(key) or ( Erase(key) and Rehash() ) |
Table API
Insert(key,data) // unimodal insert of (key,data); alias for Put iter = Includes(key) // returns iter to key if found, End() otherwise (const and non-const) Begin() and End() // supporting bidirectional iterators (const and non-const versions) Remove(key) or ( Erase(key) and Rehash() ) |
Both APIs equipped with the usual container boiler plate: Empty, Size, Clear, Constructors, Destructor, operator= |
In practice, one has either OAA nicknamed "Table Lite", the iterator-free associative array, or Map nicknamed "Full Table" or "Dictionary", which includes both Associative Array and Table APIs.
One may wonder about code bloat - throwing unwanted operations into the executable code. A big advantage of using templates is that a function template is not translated to object code unless it is actually called in the program. For class templates, this means that unused member functions are not compiled. This makes it sensible and convenient to have both the Associative Array API and the Table API supported by the Map container.
With a sequential structure such as a list, there is one obvious way for an iterator to go through the elements, from front to back. In a Set or Map structure, the "correct" order is neither unique nor obvious. When using any of the BST implementations, any kind of traversal might be used to define iterators, and we have at least 4: Inorder, Preorder, Postorder, and Levelorder. We will use all of these defined as external or "ADT-based" iterator classes. The native iterator class will be thread-based and have the advantage over stack-based Inorderiterator in that it requires +O(1) memory and is very fast. Please be familiar with the chapter of tree iterators before diving deeper into this project.
Map implementations also present the issue of what it means to de-reference an iterator. Sometimes we want the key, sometimes the data, and sometimes both. The solution is to package the key,data in a single object called an entry. An Entry object is similar to a Pair, except: (1) the names of the data are key_ and data_ (rather than first_ and second_), and (2) the key_ is a constant, so that it can never be changed. Mimicking the terminology in the standard library, we name the internal type to be returned by a dereferenced iterator "ValueType".
The external/ADT iterator classes are supplied for this project.
The official development/testing/assessment environment is specified in the Course Organizer.
Create and work within a separate subdirectory cop4530/proj5.
Begin by copying all files in the directory LIB/proj5 into your proj5 directory. At this point you should see these files (at least) in your directory:
deliverables.sh map_bst_threaded.start # start for map_bst_threaded.h mapiter_threaded.start # start for mapiter_threaded.h main_wb3.cpp # 3rd time's a charm for wordbench fmap_bst.cpp # functionality test harness for Map mmap_bst.cpp # hammer tester rantable.cpp # create test files to be loaded by fmap.x
Then copy these relevant executables from LIB/area51/:
fmap_bst_i.x mmap_bst_i.x wb3_i.x
Finally, you may want to copy the slave file for simpler access. (This file should not be in your project directory under its library name, nor should you attempt to modify it.)
cp ~cop4530p/LIB/tcpp/map_bst_threaded_tools.cpp ~/cop4530/proj5/map_bst_threaded_tools.info
Create the deliverables
map_bst_threaded.h mapiter_threaded.h wordbench3.h wordbench3.cpp makefile.wb3 log.txt
satisfying the requirements and specifications below.
Test thoroughly, using the area51 executables as benchmarks. (See Hints on testing.)
Submit the assignment using the command submit.sh.
Warning: Submit scripts do not work on the program and
linprog servers. Use shell.cs.fsu.edu to submit assignments. If you do
not receive the second confirmation with the contents of your assignment, there has
been a malfunction.
Design of the Map and Map Iterator classes is captured in the start files and discussed in the lecture notes. Most of the function implementations are omitted, and of course need to be supplied.
You are required to TYPE the code into the implementing bodies - code should NOT be copy/pasted. Typing the code will help you understand both the design and the implementation details.
The implementation should follow the binary search tree pattern with iterative (not recursive) implementation of the Get operation.
Map_BST must implement all of the Associative Array and Table APIs.
Map_BST must exhibit all characteristics of unimodal associative containers.
Map_BST methods Get, Put, Retrieve, Erase, Insert, and Includes must have average-case runtime O(log n), where n is the size of the table.
In general, behavior should match that of the benchmark programs in area51.
Note that the runtime constraints make it infeasible to call SetAllThreads as part of the implementation of any of the Map operations, except for those that copy the whole table - copy constructor and assignment operator.
The only difference between Wordbench2 and Wordbench3 is that Wordbench2 uses OAA<String,size_t> and Wordbench3 uses Map_Threaded<String,size_t>, plus Wordbench3 adds a way to present the tree node height distribution to the user, for visual unspection of the search efficiency.
You will have to re-implement WriteReport using a standard traversal of the underlying Map object to replace the clunky Display method of OAA. This is similar to what you did for the original WordBench.
Wordbench3 must use fsu::Map_BST and behave in a manner identical to your Wordbench2, except with the added "ShowAnalysis" feature. ShowAnalysis is implemented with this code in wordbench.cpp:
void WordBench::ShowAnalysis () const { fsu::Analysis(frequency_, std::cout, 15); }
Analysis is a stand-alone function template supplied in map_bst_threaded_tools.cpp. The idea is to provide a user of wordbench with a way to see how efficient the map is for their particular word files.
The supplied file map_bst_threaded_tools.cpp is a slave file for map_bst_threaded.h. It contains the integrity checker to verify all of the BST order properties.
Testing is fun and important. The supplied "rantable.cpp" compiles to a random generator of <string,int> data written to a file. Such data files can be "Loaded" into the table with the fmap 'L' option, and also a command file can be used to perform a sequence of commands after the data is loaded. This feature of fmap allows repeatable tests comparing the results between your executable and a benchmark.
Note also that your wb3 should perform in a manner itentical to YOUR wb2, since they use the same Wordify.cpp code.
fmap has a number of interesting tests: 4 varieties of Dump (see caution bullet), structural test with verbose and silent modes,(again see caution), and all 4 options for traversal: F = Forward, R = Reverse, L = Levelorder, and ! = reciprocity test). And of course fmap makes the AA and Table APIs accessible.
Caution. Some of the choices available from fmap may be inadvisable for large tables. Any kind of Dump or Traverse with a table of 100,000 entries is going to occupy your screen for a while, as will the level 2 output from structural testing. Try these out on modest size tables. (We have built in a "stop" below level k = 7 in the cases where a complete binary tree is output, because level k has 2^(k-1) nodes.)
/* map_bst_threaded.start <start by completing basic file header documentation!> */ #ifndef _MAP_BST_THREADED_H #define _MAP_BST_THREADED_H #include <cstddef> // size_t #include <cstdint> // uint8_t #include <iostream> #include <iomanip> #include <compare.h> // LessThan #include <queue.h> // used in Dump() #include <mapiter_adt.h> #include <mapiter_threaded.h> namespace fsu { template < typename K , typename D , class P > class Map_BST; template < typename K , typename D, class P = fsu::LessThan<K> > class Map_BST { public: // family ties friend class ConstThreadedMapIterator < fsu::Map_BST<K,D,P> >; friend class ThreadedMapIterator < fsu::Map_BST<K,D,P> >; friend class ConstInorderMapIterator < fsu::Map_BST<K,D,P> >; friend class InorderMapIterator < fsu::Map_BST<K,D,P> >; friend class PreorderMapIterator < fsu::Map_BST<K,D,P> >; friend class PostorderMapIterator < fsu::Map_BST<K,D,P> >; friend class LevelorderMapIterator < fsu::Map_BST<K,D,P> >; // terminology support typedef K KeyType; typedef D DataType; typedef P PredicateType; typedef typename fsu::Entry <K,D> ValueType; // type returned by iterator operator* typedef ThreadedMapIterator < Map_BST <K,D,P> > Iterator; // native iterator typedef ConstThreadedMapIterator < Map_BST <K,D,P> > ConstIterator; // native constiterator typedef PreorderMapIterator < Map_BST <K,D,P> > PreorderIterator; // stack-based typedef InorderMapIterator < Map_BST <K,D,P> > InorderIterator; // stack-based typedef ConstInorderMapIterator < Map_BST <K,D,P> > ConstInorderIterator; // stack-based typedef PostorderMapIterator < Map_BST <K,D,P> > PostorderIterator; // stack-based typedef LevelorderMapIterator < Map_BST <K,D,P> > LevelorderIterator; // queue-based // native iterator support (native = threaded) Iterator Begin (); Iterator End (); Iterator rBegin (); Iterator rEnd (); ConstIterator Begin () const; ConstIterator End () const; ConstIterator rBegin () const; ConstIterator rEnd () const; // external ADT iterators LevelorderIterator BeginLevelorder () const; LevelorderIterator EndLevelorder () const; InorderIterator BeginInorder (); InorderIterator EndInorder (); InorderIterator rBeginInorder (); InorderIterator rEndInorder (); ConstInorderIterator BeginInorder () const; ConstInorderIterator EndInorder () const; ConstInorderIterator rBeginInorder () const; ConstInorderIterator rEndInorder () const; PreorderIterator BeginPreorder () const; PreorderIterator EndPreorder () const; PreorderIterator rBeginPreorder () const; PreorderIterator rEndPreorder () const; PostorderIterator BeginPostorder () const; PostorderIterator EndPostorder () const; PostorderIterator rBeginPostorder () const; PostorderIterator rEndPostorder () const; // structural iterator support InorderIterator BeginStructuralInorder () const; // proper type Map_BST (); explicit Map_BST (P p); Map_BST (const Map_BST& map); ~Map_BST (); Map_BST& operator=(const Map_BST& map); // associative array API D& Get (const KeyType& k); void Put (const KeyType& k , const DataType& d); bool Retrieve (const KeyType& k, DataType& d) const; DataType& operator [] (const KeyType& k); // table API Iterator Includes (const KeyType& k); ConstIterator Includes (const KeyType& k) const; void Insert (const KeyType& k , const DataType& d); void Insert (Iterator i, const K& k, const D& d); // ordered table Iterator LowerBound (const K& k) const; Iterator UpperBound (const K& k) const; // common remove operations void Erase (const KeyType& k); void Clear (); void Rehash (); // size operations - implemented in-line with calls to private recursive methods bool Empty () const { return root_ == nullptr; } // doesn't cover case // of "nothing but // tombstones" size_t Size () const { return RSize(root_); } // counts alive nodes size_t NumNodes () const { return RNumNodes(root_); } // counts all nodes int Height () const { return RHeight(root_); } // development support void DumpBW (std::ostream& os) const; void Dump (std::ostream& os) const; void Dump (std::ostream& os, int kw) const; void Dump (std::ostream& os, int kw, char fill) const; void DepthDistribution (std::ostream& os, size_t skip) const; // diagnoistics bool CheckBST (bool verboseFlag) const; // 0,1 bool CheckAllThreads (bool verboseFlag) const; bool CheckStructure (bool verboseFlag) const { return CheckBST (verboseFlag) && CheckAllThreads(verboseFlag); } // generic name private: // types enum Flags { }; struct Node { // KeyType key_; // DataType data_; fsu::Entry<KeyType,DataType> value_; Node * lchild_, * rchild_; uint8_t flags_; // Flags flags_; Node (const KeyType& k, const DataType& d, Flags flags) : value_(k,d), lchild_(nullptr), rchild_(nullptr), flags_(flags) {} // support for color management bool IsRed () const { } // needs implementatiom bool IsBlack () const { } // needs implementatiom void SetRed () { } // needs implementatiom void SetBlack () { } // needs implementatiom // support for graveyard management bool IsDead () const { } // needs implementatiom bool IsAlive () const { } // needs implementatiom void SetDead () { } // needs implementatiom void SetAlive () { } // needs implementatiom // support for search bool HasLeftChild () const { return (lchild_ != nullptr) && !(IsLeftThreaded()); } bool HasRightChild () const { return (rchild_ != nullptr) && !(IsRightThreaded()); } // support for threaded management bool IsLeftThreaded () const { return 0 != (LEFT_THREAD & flags_); } bool IsRightThreaded () const { return 0 != (RIGHT_THREAD & flags_); } void SetLeftThread (Node* n) { lchild_ = n; flags_ |= LEFT_THREAD; } void SetRightThread (Node* n) { rchild_ = n; flags_ |= RIGHT_THREAD; } void SetLeftChild (Node* n) { lchild_ = n; flags_ &= ~LEFT_THREAD; } void SetRightChild (Node* n) { rchild_ = n; flags_ &= ~RIGHT_THREAD; } static const char* ColorMap (uint8_t flags) { flags &= 0x03; // last 2 bits only switch(flags) { case 0x00: return ANSI_BOLD_BLUE; // bits 00 = !RED | ALIVE case 0x01: return ANSI_BOLD_BLUE_SHADED; // bits 01 = !RED | !ALIVE case 0x02: return ANSI_BOLD_RED; // bits 10 = RED | ALIVE case 0x03: return ANSI_BOLD_RED_SHADED; // bits 11 = RED | !ALIVE default: return "unknown color"; // unknown flags } } static char BWMap (uint8_t flags) { switch(flags) { case 0x00: return 'B'; // bits 00 black alive case 0x01: return 'b'; // bits 01 black dead case 0x02: return 'R'; // bits 10 red alive case 0x03: return 'r'; // bits 11 red dead default: return 'U'; // unknown flags } } // node dump - may be used during development void Dump (std::ostream& os = std::cout) const { os << " Node data:\n" << " value: " << value_ << '\n' << " color: " << (size_t)IsRed() << '\n' << " alive: " << (size_t)IsAlive() << '\n' << " left_threaded: " << (size_t)IsLeftThreaded() << '\n' << " right_threaded: " << (size_t)IsRightThreaded() << '\n'; os << " lchild: "; if (lchild_ != nullptr) { if (IsLeftThreaded()) os << lchild_->value_ << " (predecessor)\n"; else os << lchild_->value_ << " (left child)\n"; } else os << "NULL\n"; os << " rchild: "; if (rchild_ != nullptr) { if (IsRightThreaded()) os << rchild_->value_ << " (succecessor)\n"; else os << rchild_->value_ << " (right child)\n"; } else os << "NULL\n"; os << std::flush; } }; // end struct Node private: // class data Node * root_; PredicateType pred_; private: // methods void SetAllThreads (); static Node * NewNode (const K& k, const D& d, Flags flags = ZERO); static void RRelease (Node* n); // deletes all descendants of n static Node * RClone (const Node* n); // returns deep copy of n static size_t RSize (Node * n); static size_t RNumNodes (Node * n); static int RHeight (Node * n); }; // end class Map_BST<> // define equality using class iterator type template < typename K , typename D , class P > bool operator == (const Map_BST<K,D,P>& map1, const Map_BST<K,D,P>& map2) { } template < typename K , typename D , class P > bool operator != (const Map_BST<K,D,P>& b1, const Map_BST<K,D,P>& b2) { } // Iterator support methods template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::Begin() { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::End() { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::rBegin() { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::rEnd() { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstIterator Map_BST<K,D,P>::Begin() const { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstIterator Map_BST<K,D,P>::End() const { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstIterator Map_BST<K,D,P>::rBegin() const { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstIterator Map_BST<K,D,P>::rEnd() const { } // the Iterator locator methods template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::Includes ( const K& k ) { } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstIterator Map_BST<K,D,P>::Includes ( const K& k ) const { } template < typename K , typename D , class P > void Map_BST<K,D,P>::Put (const K& k, const D& d) { } template < typename K , typename D , class P > void Map_BST<K,D,P>::Insert (const K& k, const D& d) { } template < typename K , typename D , class P > D& Map_BST<K,D,P>::Get (const K& k) { } template < typename K , typename D , class P > bool Map_BST<K,D,P>::Retrieve (const K& k, D& d) const { } template < typename K , typename D , class P > void Map_BST<K,D,P>::Erase ( const K& k ) { } template < typename K , typename D , class P > void Map_BST<K,D,P>::Clear() { } // recursive support methods template < typename K , typename D , class P > size_t Map_BST<K,D,P>::RSize(Node * n) { } template < typename K , typename D , class P > size_t Map_BST<K,D,P>::RNumNodes(Node * n) { } template < typename K , typename D , class P > int Map_BST<K,D,P>::RHeight(Node * n) { } template < typename K , typename D , class P > void Map_BST<K,D,P>::RRelease(Node* n) // post: all descendants of n have been deleted { } /***********************************************/ /* below here all implementations are provided */ /***********************************************/ template < typename K , typename D , class P > void Map_BST<K,D,P>::Insert (Iterator i, const K& k, const D& d) { if (i.Valid() && k == (*i).value_.key_) { i.node_->value_.data_ = d; i.node_->SetAlive(); return; } Map_BST<K,D,P>::Insert(k,d); } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::LowerBound ( const K& k ) const { if (this->root_ == nullptr) return End(); Iterator l = End(); Node * n = this->root_; bool finished = 0; while (! finished) { if (!this->pred_(n->value_.key_,k)) // t <= n { l.node_ = n; if (n->HasLeftChild()) n = n->lchild_; else finished = 1; } else // t > n { if (n->HasRightChild()) n = n->rchild_; else finished = 1; } } // take care of dead node case if (l.Valid() && l.node_->IsDead()) ++l; return l; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Iterator Map_BST<K,D,P>::UpperBound ( const K& k ) const { if (this->root_ == nullptr) return End(); Iterator u = End(); Node * n = this->root_; bool finished = 0; while (! finished) { if (this->pred_(k,n->value_.key_)) // t < n { u.node_ = n; if (n->HasLeftChild()) n = n->lchild_; else finished = 1; } else // t >= n { if (n->HasRightChild()) n = n->rchild_; else finished = 1; } } // take care of dead node case if (u.Valid() && u.node_->IsDead()) ++u; return u; } template < typename K , typename D , class P > void Map_BST<K,D,P>::Rehash() // restructure with no tombstones { Map_BST<K,D,P> newtree; for (PreorderIterator i = this->BeginPreorder(); i != this->EndPreorder(); ++i) // for (LevelorderIterator i = this->BeginLevelorder(); i != this->EndLevelorder(); ++i) { newtree.Insert((*i).key_, (*i).data_); } fsu::Swap(this->root_,newtree.root_); } template < typename K , typename D , class P > typename Map_BST<K,D,P>::Node* Map_BST<K,D,P>::RClone(const Map_BST<K,D,P>::Node* n) // returns a pointer to a deep copy of n // parentless version // does NOT set threads! { if (n == nullptr) return nullptr; Node* newN = NewNode (n->value_.key_, n->value_.data_, (Flags)n->flags_); if (n->HasLeftChild()) newN->lchild_ = RClone(n->lchild_); else newN->lchild_ = nullptr; if (n->HasRightChild()) newN->rchild_ = RClone(n->rchild_); else newN->rchild_ = nullptr; return newN; } // end RClone() */ template < typename K , typename D , class P > typename Map_BST<K,D,P>::Node * Map_BST<K,D,P>::NewNode(const K& k, const D& d, Flags flags) { Node * nPtr = new(std::nothrow) Node(k,d,flags); if (nPtr == nullptr) { std::cerr << "** Map_BST memory allocation failure\n"; // handle exception in-class here } return nPtr; } // proper type template < typename K , typename D , class P > Map_BST<K,D,P>::Map_BST () : root_(nullptr), pred_() {} template < typename K , typename D , class P > Map_BST<K,D,P>::Map_BST (P p) : root_(nullptr), pred_(p) {} template < typename K , typename D , class P > Map_BST<K,D,P>::~Map_BST () { this->Clear(); } template < typename K , typename D , class P > Map_BST<K,D,P>::Map_BST( const Map_BST<K,D,P>& tree ) { root_ = RClone(tree.root_); this->SetAllThreads(); } template < typename K , typename D , class P > Map_BST<K,D,P>& Map_BST<K,D,P>::operator=( const Map_BST<K,D,P>& that ) { if (this != &that) { Clear(); root_ = RClone(that.root_); this->SetAllThreads(); } return *this; } // "Structural" iteration goes over the tree (not the represented set) // stopping at ALL nodes, dead or alive. // A structural traversal is used by the SetAllThreads method, a critical step // in copying a threaded BST. template < typename K , typename D , class P > typename Map_BST<K,D,P>::InorderIterator Map_BST<K,D,P>::BeginStructuralInorder () const { InorderIterator i; i.sInit(root_); return i; } // protected helper method prototyped in base class template < typename K , typename D , class P > void Map_BST<K,D,P>::SetAllThreads () { // fsu::Debug("SetAllThreads"); InorderIterator i = BeginStructuralInorder(); if (i == EndInorder()) return; Node * n1, * n2; n1 = i.stk_.Top(); n1->SetLeftThread(nullptr); i.Increment(); while (i != EndInorder()) { n2 = i.stk_.Top(); if (!n1->HasRightChild()) { n1->SetRightThread(n2); } if (!n2->HasLeftChild()) { n2->SetLeftThread(n1); } n1 = n2; i.Increment(); } n1->SetRightThread(nullptr); } // ADT-based iterator support template < typename K , typename D , class P > typename Map_BST<K,D,P>::InorderIterator Map_BST<K,D,P>::BeginInorder() { InorderIterator i; i.Init(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::InorderIterator Map_BST<K,D,P>::EndInorder() { InorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::InorderIterator Map_BST<K,D,P>::rBeginInorder() { InorderIterator i; i.rInit(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::InorderIterator Map_BST<K,D,P>::rEndInorder() { InorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstInorderIterator Map_BST<K,D,P>::BeginInorder() const { ConstInorderIterator i; i.Init(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstInorderIterator Map_BST<K,D,P>::EndInorder() const { ConstInorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstInorderIterator Map_BST<K,D,P>::rBeginInorder() const { ConstInorderIterator i; i.rInit(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::ConstInorderIterator Map_BST<K,D,P>::rEndInorder() const { ConstInorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::LevelorderIterator Map_BST<K,D,P>::BeginLevelorder() const { LevelorderIterator i; i.Init(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::LevelorderIterator Map_BST<K,D,P>::EndLevelorder() const { LevelorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PreorderIterator Map_BST<K,D,P>::BeginPreorder() const { PreorderIterator i; i.Init(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PreorderIterator Map_BST<K,D,P>::EndPreorder() const { PreorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PreorderIterator Map_BST<K,D,P>::rBeginPreorder() const { PreorderIterator i; i.rInit(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PreorderIterator Map_BST<K,D,P>::rEndPreorder() const { PreorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PostorderIterator Map_BST<K,D,P>::BeginPostorder() const { PostorderIterator i; i.Init(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PostorderIterator Map_BST<K,D,P>::EndPostorder() const { PostorderIterator i; return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PostorderIterator Map_BST<K,D,P>::rBeginPostorder() const { PostorderIterator i; i.rInit(this->root_); return i; } template < typename K , typename D , class P > typename Map_BST<K,D,P>::PostorderIterator Map_BST<K,D,P>::rEndPostorder() const { PostorderIterator i; return i; } #include <map_bst_threaded_tools.cpp> } // namespace fsu #endif
/* mapiter_threaded.start <make your bed first thing!> */ #include <cstddef> // size_t #include <cstdint> // uint8_t #include <ansicodes.h> #include <iostream> #include <iomanip> #ifndef _MAPITER_THREADED_H #define _MAPITER_THREADED_H namespace fsu { template < class C > class ConstThreadedMapIterator; // patterns: ConstIterator, BidirectionalIterator template < class C > class ThreadedMapIterator; // patterns: Iterator, BidirectionalIterator /*****************************************************/ /* class ConstThreadedMapIterator < C > */ /*****************************************************/ template < class C > class ConstThreadedMapIterator // a ConstIterator pattern { protected: friend C; typename C::Node* node_; public: // terminology support typedef typename C::ValueType ValueType; typedef typename C::Node Node; typedef ConstThreadedMapIterator<C> ConstIterator; typedef ThreadedMapIterator<C> Iterator; // constructors ConstThreadedMapIterator (); virtual ~ConstThreadedMapIterator (); ConstThreadedMapIterator (Node* n); // type converter ConstThreadedMapIterator (const ConstThreadedMapIterator& i); // copy ctor // information/access bool Valid () const; // cursor is valid element // various operators bool operator == (const ConstThreadedMapIterator& i2) const; bool operator != (const ConstThreadedMapIterator& i2) const; const ValueType& operator * () const; // const version // ValueType& operator * (); // non-const version ConstThreadedMapIterator<C>& operator = (const ConstThreadedMapIterator& i); ConstThreadedMapIterator<C>& operator ++ (); // prefix ConstThreadedMapIterator<C> operator ++ (int); // postfix ConstThreadedMapIterator<C>& operator -- (); // prefix ConstThreadedMapIterator<C> operator -- (int); // postfix // developers helper void Dump ( std::ostream& os = std::cout , char = '\0' ); private: void Init (Node*); void rInit (Node*); void Increment (); // moves to next inorder node void Decrement (); // moves to previous inorder node }; // protected increment/decrement template < class C > void ConstThreadedMapIterator<C>::Init(Node* n) { } template < class C > void ConstThreadedMapIterator<C>::rInit(Node* n) { } template < class C > void ConstThreadedMapIterator<C>::Increment () { } template < class C > void ConstThreadedMapIterator<C>::Decrement () { } template < class C > bool ConstThreadedMapIterator<C>::Valid() const { } // other operators template < class C > ConstThreadedMapIterator<C> & ConstThreadedMapIterator<C>::operator ++() { } template < class C > ConstThreadedMapIterator<C> ConstThreadedMapIterator<C>::operator ++(int) { } template < class C > ConstThreadedMapIterator<C> & ConstThreadedMapIterator<C>::operator --() { } template < class C > ConstThreadedMapIterator<C> ConstThreadedMapIterator<C>::operator --(int) { } template < class C > const typename C::ValueType& ConstThreadedMapIterator<C>::operator *() const { } template < class C > bool ConstThreadedMapIterator<C>::operator == (const ConstThreadedMapIterator<C>& i2) const { } template < class C > bool ConstThreadedMapIterator<C>::operator != (const ConstThreadedMapIterator<C>& i2) const { } /*****************************************************/ /* class ThreadedMapIterator < C > */ /*****************************************************/ template < class C > class ThreadedMapIterator : public ConstThreadedMapIterator <C> { private: friend C; // typename C::Node* node_; public: // terminology support typedef typename C::ValueType ValueType; typedef typename C::Node Node; typedef ThreadedMapIterator<C> ConstIterator; typedef ThreadedMapIterator<C> Iterator; // constructors ThreadedMapIterator (); virtual ~ThreadedMapIterator (); ThreadedMapIterator (Node* n); // type converter ThreadedMapIterator (const ThreadedMapIterator& i); // copy ctor // information/access // bool Valid () const; // cursor is valid element // various operators bool operator == (const ThreadedMapIterator& i2) const; bool operator != (const ThreadedMapIterator& i2) const; const ValueType& operator * () const; // const version ValueType& operator * (); // non-const version ThreadedMapIterator<C>& operator = (const ThreadedMapIterator& i); ThreadedMapIterator<C>& operator ++ (); // prefix ThreadedMapIterator<C> operator ++ (int); // postfix ThreadedMapIterator<C>& operator -- (); // prefix ThreadedMapIterator<C> operator -- (int); // postfix // developers helper // void Dump ( std::ostream& os = std::cout , char = '\0' ); private: // void Init (Node*); // void rInit (Node*); // void Increment (); // moves to next inorder node // void Decrement (); // moves to previous inorder node }; template < class C > bool ThreadedMapIterator<C>::operator == (const ThreadedMapIterator<C>& i2) const { } template < class C > bool ThreadedMapIterator<C>::operator != (const ThreadedMapIterator<C>& i2) const { } /**************************************************/ /* below here everything is implemented correctly */ /**************************************************/ // proper types template < class C > ConstThreadedMapIterator<C>::ConstThreadedMapIterator () : node_() {} template < class C > ConstThreadedMapIterator<C>::~ConstThreadedMapIterator () {} template < class C > ConstThreadedMapIterator<C>::ConstThreadedMapIterator (const ConstThreadedMapIterator<C>& i) : node_(i.node_) {} template < class C > ConstThreadedMapIterator<C>::ConstThreadedMapIterator (Node * n) : node_(n) {} template < class C > ConstThreadedMapIterator<C> & ConstThreadedMapIterator<C>::operator = (const ConstThreadedMapIterator<C>& i) { node_ = i.node_; return *this; } template < class C > ThreadedMapIterator<C>::ThreadedMapIterator () : ConstThreadedMapIterator<C>() {} template < class C > ThreadedMapIterator<C>::~ThreadedMapIterator () {} template < class C > ThreadedMapIterator<C>::ThreadedMapIterator (const ThreadedMapIterator<C>& i) : ConstThreadedMapIterator<C>(i) {} template < class C > ThreadedMapIterator<C>::ThreadedMapIterator (Node * n) : ConstThreadedMapIterator<C>(n) {} // derived class operators implemented with calls to base class versions template < class C > ThreadedMapIterator<C> & ThreadedMapIterator<C>::operator = (const ThreadedMapIterator<C>& i) { ConstThreadedMapIterator<C>::operator=(i); return *this; } template < class C > ThreadedMapIterator<C> & ThreadedMapIterator<C>::operator ++() { ConstThreadedMapIterator<C>::operator++(); return *this; } template < class C > ThreadedMapIterator<C> ThreadedMapIterator<C>::operator ++(int) { ThreadedMapIterator<C> i = *this; operator ++(); return i; } template < class C > ThreadedMapIterator<C> & ThreadedMapIterator<C>::operator --() { ConstThreadedMapIterator<C>::operator--(); return *this; } template < class C > ThreadedMapIterator<C> ThreadedMapIterator<C>::operator --(int) { ThreadedMapIterator<C> i = *this; operator --(); return i; } template < class C > const typename C::ValueType& ThreadedMapIterator<C>::operator *() const { return this->node_->value_; } template < class C > typename C::ValueType& ThreadedMapIterator<C>::operator *() { return this->node_->value_; } // the iterator dump method is completely implemented here: template < class C > void ConstThreadedMapIterator<C>::Dump(std::ostream& os , char) { os << "node: " << node_->value_ << " , "; if (node_->IsRightThreaded()) { if (node_->rchild_ == nullptr) os << "++: null , "; else os << "++: " << node_->rchild_->value_ << " , "; } else { if (node_->rchild_ == nullptr) os << "rchild: null , "; else os << "rchild: " << node_->rchild_->value_ << " , "; } if (node_->IsLeftThreaded()) { if (node_->lchild_ == nullptr) os << "--: null\n"; else os << "--: " << node_->lchild_->value_ << '\n'; } else { if (node_->lchild_ == nullptr) os << "lchild: null\n"; else os << "lchild: " << node_->lchild_->value_ << '\n'; } } } // namespace fsu #endif