Writing STL containers from scratch is a good way to dig deeper into C++. Refering to the API's, literature and the source code (which are easily accessible), it is helpful to tune out thought process for leaning effective C++. BST is not available as the part of STL but std::set is implemented as red-black tree which is very simple. Note: This code base is incomplete and at best represents a way to get started with writing the containers. There are known bugs and issue both related to design and visibility which are to be fixed. The thought process which led to this design and the learnings from this project are also shared.
- Install bazel
- Build the code:
bazel build //test:bst-test
- Run the tests:
bazel run //test:bst-test
- (OPTIONAL READ): Configuring google tests: https://docs.bazel.build/versions/master/cpp-use-cases.html https://docs.bazel.build/versions/master/test-encyclopedia.html
-
OS: Ubuntu 14.04
-
GCC version: 6.3.0-18
-
C++ version: > 11
-
More of gtest and bazel:
- APIS' are based is based on [c++ set implementation][http://en.cppreference.com/w/cpp/container/set)
template<class Key_, class Compare_ = std::less<Key_>, class Allocator_ = std::allocator<Key_>>
In this case we'll need to declare pointer to node like :
using node_pointer = bst_node<key_type, key_compare, allocator_type>*;
But we don't need compare type here
template<class Key_, class VoidPtr_>
I went ahead with the option 2 way as used in the llvm implementation. C++17 has node_handle which is very similar to the Option1 implementation
- Use bidiectional iterators (for ++ and -- operator)
- Two option to implement ++ operator with iterator (a. use of queue b. use parent pointer). In this code parent pointer approach has been used as the other takes in extra memory of order O(N) where N are the number of elements
- The allocator templete parameter is the allocator for the type Key_ but we need to allocate the node. So, we rebind the allocator the the node. ''' rebind_alloc Alloc::rebind::other if present, otherwise Alloc<T, Args> if this Alloc is Alloc<U, Args>''' http://en.cppreference.com/w/cpp/memory/allocator_traits
Two seperate functions for inserting lvalue and rvalue are required.
//for lvaue
std::pair<iterator,bool> insert( const value_type& value );
for rvalue
std::pair<iterator,bool> insert( value_type&& value );
See the comments in the code for more details. More resources on lvalue and rvalue: https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11
https://stackoverflow.com/questions/16216043/passing-r-value-as-non-const-reference-vs-warning-c4239
https://stackoverflow.com/questions/2762568/c-c-include-file-order-best-practices
Order of calling the constructors matters and the performance related to it
- Implement --
- Implement remove, erase
- Implement find
- Fix rvalue insert
- copy, move, swap constructors
- operators like ==
- Destruct the elements
- Test and fix const iterators
- Apache implementation of red black tree: https://github.com/apache/stdcxx/blob/trunk/include/rw/_tree.h
- GCC implementation: https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.1/stl__tree_8h-source.html
- LLVM: https://github.com/google/libcxx/blob/27c836ff3a9c505deb9fd1616012924de8ff9279/include/__tree