diff --git a/doc/_doxygen/vtr.dox b/doc/_doxygen/vtr.dox new file mode 100644 index 00000000000..0521a5c3693 --- /dev/null +++ b/doc/_doxygen/vtr.dox @@ -0,0 +1,17 @@ +PROJECT_NAME = "Verilog to Routing - VTR" +OUTPUT_DIRECTORY = ../_build/doxygen/vtr +FULL_PATH_NAMES = NO +OPTIMIZE_OUTPUT_FOR_C = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +WARN_IF_UNDOCUMENTED = NO +INPUT = ../../libs/libvtrutil +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +RECURSIVE = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES diff --git a/doc/src/api/vtrutil/container_utils.rst b/doc/src/api/vtrutil/container_utils.rst new file mode 100644 index 00000000000..03d9a8130b0 --- /dev/null +++ b/doc/src/api/vtrutil/container_utils.rst @@ -0,0 +1,26 @@ +=============== +Container Utils +=============== + +vtr_hash +-------- +.. doxygenfile:: vtr_hash.h + :project: vtr + +vtr_memory +---------- +.. doxygenfile:: vtr_memory.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass func + +vtr_pair_util +------------- +.. doxygenfile:: vtr_pair_util.h + :project: vtr + :sections: innernamespace innerclass briefdescription detaileddescription user-defined public-func typedef + +vtr_map_util +------------ +.. doxygenfile:: vtr_map_util.h + :project: vtr + diff --git a/doc/src/api/vtrutil/containers.rst b/doc/src/api/vtrutil/containers.rst new file mode 100644 index 00000000000..879e01a4ca2 --- /dev/null +++ b/doc/src/api/vtrutil/containers.rst @@ -0,0 +1,112 @@ +========== +Containers +========== + +vtr_vector +---------- +.. doxygenfile:: vtr_vector.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass public-func typedef func + +vtr_small_vector +---------------- +.. doxygenclass:: vtr::small_vector + :project: vtr + :members: + +vtr_vector_map +-------------- +.. doxygenfile:: vtr_vector_map.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass public-func typedef func + +vtr_linear_map +-------------- +.. doxygenfile:: vtr_linear_map.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func innerclass user-defined public-func typedef + +vtr_flat_map +------------ +.. doxygenclass:: vtr::flat_map + :project: vtr + :members: + +.. doxygenclass:: vtr::flat_map2 + :project: vtr + :members: + +.. doxygenfile:: vtr_flat_map.h + :project: vtr + :sections: innernamespace func + +vtr_bimap +--------- +.. doxygenfile:: vtr_bimap.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass user-defined public-func derivedcompoundref typedef + +vtr_vec_id_set +-------------- +.. doxygenfile:: vtr_vec_id_set.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass public-func + +vtr_list +-------- +.. doxygenfile:: vtr_list.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace struct innerclass user-defined public-func typedef + +.. doxygenfunction:: insert_in_vptr_list + :project: vtr + + +.. doxygenfunction:: delete_in_vptr_list + :project: vtr + +vtr_ragged_matrix +----------------- +.. doxygenclass:: vtr::FlatRaggedMatrix + :project: vtr + :members: + +vtr_ndmatrix +------------ +.. doxygenfile:: vtr_ndmatrix.h + :project: vtr + :sections: innernamespace innerclass briefdescription detaileddescription user-defined public-func typedef + +vtr_ndoffsetmatrix +------------------ +.. doxygenfile:: vtr_ndoffsetmatrix.h + :project: vtr + :sections: innernamespace innerclass briefdescription detaileddescription user-defined public-func typedef + +vtr_array_view +-------------- +.. doxygenclass:: vtr::array_view_id + :project: vtr + :members: + +.. doxygenclass:: vtr::array_view + :project: vtr + :members: + +vtr_string_view +--------------- +.. doxygenclass:: vtr::string_view + :project: vtr + :members: + +vtr_cache +--------- +.. doxygenclass:: vtr::Cache + :project: vtr + :members: + +vtr_dynamic_bitset +------------------ +.. doxygenclass:: vtr::dynamic_bitset + :project: vtr + :members: diff --git a/doc/src/api/vtrutil/geometry.rst b/doc/src/api/vtrutil/geometry.rst new file mode 100644 index 00000000000..739317e3d67 --- /dev/null +++ b/doc/src/api/vtrutil/geometry.rst @@ -0,0 +1,25 @@ +======== +Geometry +======== + +vtr_geometry +------------ +.. doxygenfile:: vtr_geometry.h + :project: vtr + :sections: briefdescription + +.. doxygenclass:: vtr::Point + :project: vtr + :members: + +.. doxygenclass:: vtr::Rect + :project: vtr + :members: + +.. doxygenclass:: vtr::Line + :project: vtr + :members: + +.. doxygenclass:: vtr::RectUnion + :project: vtr + :members: diff --git a/doc/src/api/vtrutil/ids.rst b/doc/src/api/vtrutil/ids.rst new file mode 100644 index 00000000000..ba7bc68049b --- /dev/null +++ b/doc/src/api/vtrutil/ids.rst @@ -0,0 +1,26 @@ +============ +IDs - Ranges +============ + +vtr_range +--------- +.. doxygenfile:: vtr_range.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func innerclass public-func typedef + +vtr_strong_id +------------- +.. doxygenfile:: vtr_strong_id.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace + +.. doxygenclass:: vtr::StrongId + :project: vtr + :members: + +vtr_strong_id_range +------------------- +.. doxygenfile:: vtr_strong_id_range.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func innerclass user-defined public-func + diff --git a/doc/src/api/vtrutil/index.rst b/doc/src/api/vtrutil/index.rst new file mode 100644 index 00000000000..6d44b381a2a --- /dev/null +++ b/doc/src/api/vtrutil/index.rst @@ -0,0 +1,14 @@ +.. _vtrutil_api: + +VTRUTIL API +============ + +.. toctree:: + :maxdepth: 1 + + ids + containers + container_utils + logging + geometry + other diff --git a/doc/src/api/vtrutil/logging.rst b/doc/src/api/vtrutil/logging.rst new file mode 100644 index 00000000000..5145173bf9c --- /dev/null +++ b/doc/src/api/vtrutil/logging.rst @@ -0,0 +1,39 @@ +============================= +Logging - Errors - Assertions +============================= + +vtr_log +------- +.. doxygenfile:: vtr_log.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func + +vtr_error +--------- +.. doxygenfile:: vtr_error.h + :project: vtr + :sections: innernamespace innerclass briefdescription detaileddescription user-defined public-func + +vtr_assertion +------------- +.. doxygenfile:: vtr_assert.h + :project: vtr + :sections: briefdescription detaileddescription + +vtr_time +-------- +.. doxygenfile:: vtr_time.h + :project: vtr + :sections: briefdescription detaileddescription + +.. doxygenclass:: vtr::ScopedStartFinishTimer + :project: vtr + +.. doxygenclass:: vtr::ScopedFinishTimer + :project: vtr + +.. doxygenclass:: vtr::ScopedActionTimer + :project: vtr + +.. doxygenclass:: vtr::Timer + :project: vtr diff --git a/doc/src/api/vtrutil/other.rst b/doc/src/api/vtrutil/other.rst new file mode 100644 index 00000000000..3a4c45aa3b0 --- /dev/null +++ b/doc/src/api/vtrutil/other.rst @@ -0,0 +1,138 @@ +===== +Other +===== + +vtr_expr_eval +------------- +.. doxygenfile:: vtr_expr_eval.h + :project: vtr + :sections: briefdescription detaileddescription func innernamespace enum + +.. doxygenclass:: vtr::Formula_Object + :project: vtr + :members: + +.. doxygenclass:: vtr::FormulaParser + :project: vtr + :members: + +.. doxygenclass:: vtr::t_formula_data + :project: vtr + :members: + + +vtr_color_map +------------- +.. doxygenfile:: vtr_color_map.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass user-defined public-func + +vtr_digest +---------- +.. doxygenfunction:: secure_digest_file + :project: vtr + +.. doxygenfunction:: secure_digest_stream + :project: vtr + +vtr_logic +--------- +.. doxygenfile:: vtr_logic.h + :project: vtr + :sections: innernamespace enum + +vtr_math +-------- +.. doxygenfile:: vtr_math.h + :project: vtr + :sections: briefdescription innernamespace func prototype + +.. doxygenfile:: vtr_math.cpp + :project: vtr + :sections: briefdescription innernamespace func prototype + + +vtr_ostream_guard +----------------- +.. doxygenfile:: vtr_ostream_guard.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func innerclass user-defined public-func + +vtr_path +-------- +.. doxygenfile:: vtr_path.h + :project: vtr + :sections: briefdescription + +.. doxygenfunction:: split_ext + :project: vtr + +.. doxygenfunction:: basename + :project: vtr + +.. doxygenfunction:: dirname + :project: vtr + +.. doxygenfunction:: getcwd + :project: vtr + + +vtr_random +---------- +.. doxygenfile:: vtr_random.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func prototype + +.. doxygenfile:: vtr_random.cpp + :project: vtr + :sections: briefdescription detaileddescription innernamespace func prototype + +vtr_rusage +---------- +.. doxygenfile:: vtr_rusage.cpp + :project: vtr + :sections: innernamespace func + +vtr_sentinels +------------- +.. doxygenfile:: vtr_sentinels.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace innerclass + +vtr_string_interning +-------------------- +.. doxygenfile:: vtr_string_interning.h + :project: vtr + :sections: briefdescription detaileddescription + +.. doxygenclass:: vtr::string_internment + :project: vtr + :members: + +.. doxygenclass:: vtr::interned_string + :project: vtr + :members: + +.. doxygenclass:: vtr::bound_interned_string + :project: vtr + :members: + +.. doxygenclass:: vtr::interned_string_iterator + :project: vtr + :members: + +vtr_token +--------- +.. doxygenfile:: vtr_token.h + :project: vtr + +vtr_util +-------- +.. doxygenfile:: vtr_util.h + :project: vtr + :sections: briefdescription detaileddescription innernamespace func + +.. doxygenfile:: vtr_util.cpp + :project: vtr + :sections: briefdescription detaileddescription innernamespace func + diff --git a/doc/src/conf.py b/doc/src/conf.py index 66cc9a057c0..efd1f03057d 100644 --- a/doc/src/conf.py +++ b/doc/src/conf.py @@ -360,6 +360,7 @@ if shutil.which("doxygen"): breathe_projects = { "vpr": "../_build/doxygen/vpr/xml", + "vtr": "../_build/doxygen/vtr/xml", "abc": "../_build/doxygen/abc/xml", "ace2": "../_build/doxygen/ace2/xml", "ODIN_II": "../_build/doxygen/ODIN_II/xml", diff --git a/doc/src/index.rst b/doc/src/index.rst index cf120bae51c..98f5610b39e 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -61,6 +61,7 @@ For more specific documentation about VPR see :ref:`vpr`. :caption: API Reference api/vpr/index + api/vtrutil/index Indices and tables ================== diff --git a/libs/libvtrutil/src/vtr_array_view.h b/libs/libvtrutil/src/vtr_array_view.h index d1c9f77f37e..3383263e040 100644 --- a/libs/libvtrutil/src/vtr_array_view.h +++ b/libs/libvtrutil/src/vtr_array_view.h @@ -8,13 +8,18 @@ namespace vtr { -// Implements a fixed length view to an array. +/** + * @brief An array view class to avoid copying data + */ template class array_view { public: + ///@brief default constructor explicit constexpr array_view() : data_(nullptr) , size_(0) {} + + ///@brief A constructor with data initialization explicit constexpr array_view(T* str, size_t size) : data_(str) , size_(size) {} @@ -26,13 +31,17 @@ class array_view { return *this; } + ///@brief [] operator constexpr T& operator[](size_t pos) { return data_[pos]; } + + ///@brief constant [] operator constexpr const T& operator[](size_t pos) const { return data_[pos]; } + ///@brief at() operator T& at(size_t pos) { if (pos >= size()) { throw std::out_of_range("Pos is out of range."); @@ -41,6 +50,7 @@ class array_view { return data_[pos]; } + ///@brief const at() operator const T& at(size_t pos) const { if (pos >= size()) { throw std::out_of_range("Pos is out of range."); @@ -49,54 +59,77 @@ class array_view { return data_[pos]; } + ///@brief get the first element of the array constexpr T& front() { return data_[0]; } + + ///@brief get the first element of the array (can't update it) constexpr const T& front() const { return data_[0]; } + ///@brief get the last element of the array constexpr T& back() { return data_[size() - 1]; } + + ///@brief get the last element of the array (can't update it) constexpr const T& back() const { return data_[size() - 1]; } + ///@brief return the underlying pointer constexpr T* data() { return data_; } + + ///@brief return the underlying pointer (constant pointer) constexpr const T* data() const { return data_; } + ///@brief return thr array size constexpr size_t size() const noexcept { return size_; } + + ///@brief return the array size constexpr size_t length() const noexcept { return size_; } + ///@brief check if the array is empty constexpr bool empty() const noexcept { return size_ != 0; } + ///@brief return a pointer to the first element of the array constexpr T* begin() noexcept { return data_; } + + ///@brief return a constant pointer to the first element of the array constexpr const T* begin() const noexcept { return data_; } + + ///@brief return a constant pointer to the first element of the array constexpr const T* cbegin() const noexcept { return data_; } + ///@brief return a pointer to the last element of the array constexpr T* end() noexcept { return data_ + size_; } + + ///@brief return a constant pointer to the last element of the array constexpr const T* end() const noexcept { return data_ + size_; } + + ///@brief return a constant pointer to the last element of the array constexpr const T* cend() const noexcept { return data_ + size_; } @@ -106,11 +139,14 @@ class array_view { size_t size_; }; -//A array_view container which is indexed by K (instead of size_t). -// -//The main use of this container is to behave like a vtr::array_view which is -//indexed by a vtr::StrongId. It assumes that K is explicitly convertable to size_t -//(i.e. via operator size_t()), and can be explicitly constructed from a size_t. +/** + * @brief Implements a fixed length view to an array which is indexed by vtr::StrongId + * + * The main use of this container is to behave like a std::span which is + * indexed by a vtr::StrongId instead of size_t. It assumes that K is explicitly + * convertable to size_t + * (i.e. via operator size_t()), and can be explicitly constructed from a size_t. + */ template class array_view_id : private array_view { using storage = array_view; @@ -124,26 +160,29 @@ class array_view_id : private array_view { class key_iterator; typedef vtr::Range key_range; - //Don't include operator[] and at() from std::vector, - //since we redine them to take key_type instead of size_t + // Don't include operator[] and at() from std::vector, since we redine them to take key_type instead of size_t + ///@brief [] operator V& operator[](const key_type id) { auto i = size_t(id); return storage::operator[](i); } + ///@brief constant [] operator const V& operator[](const key_type id) const { auto i = size_t(id); return storage::operator[](i); } + ///@brief at() operator V& at(const key_type id) { auto i = size_t(id); return storage::at(i); } + ///@brief constant at() operator const V& at(const key_type id) const { auto i = size_t(id); return storage::at(i); } - //Returns a range containing the keys + ///@brief Returns a range containing the keys key_range keys() const { return vtr::make_range(key_begin(), key_end()); } @@ -161,13 +200,21 @@ class array_view_id : private array_view { using storage::front; public: - //Iterator class which is convertable to the key_type - //This allows end-users to call the parent class's keys() member - //to iterate through the keys with a range-based for loop + /** + * @brief Iterator class which is convertable to the key_type + * + * This allows end-users to call the parent class's keys() member + * to iterate through the keys with a range-based for loop + * + */ class key_iterator : public std::iterator { public: - //We use the intermediate type my_iter to avoid a potential ambiguity for which - //clang generates errors and warnings + /** + * @brief Intermediate type my_iter + * + * We use the intermediate type my_iter to avoid a potential ambiguity for which + * clang generates errors and warnings + */ using my_iter = typename std::iterator; using typename my_iter::iterator; using typename my_iter::pointer; @@ -177,18 +224,30 @@ class array_view_id : private array_view { key_iterator(key_iterator::value_type init) : value_(init) {} - //vtr::vector assumes that the key time is convertable to size_t and - //that all the underlying IDs are zero-based and contiguous. That means - //we can just increment the underlying Id to build the next key. + /** + * @brief Note + * + * vtr::vector assumes that the key time is convertable to size_t and + * that all the underlying IDs are zero-based and contiguous. That means + * we can just increment the underlying Id to build the next key. + */ + + ///@brief increment the iterator key_iterator operator++() { value_ = value_type(size_t(value_) + 1); return *this; } + + ///@brief decrement the iterator key_iterator operator--() { value_ = value_type(size_t(value_) - 1); return *this; } + + ///@brief dereference operator (*) reference operator*() { return value_; } + + ///@brief -> operator pointer operator->() { return &value_; } friend bool operator==(const key_iterator lhs, const key_iterator rhs) { return lhs.value_ == rhs.value_; } diff --git a/libs/libvtrutil/src/vtr_assert.h b/libs/libvtrutil/src/vtr_assert.h index 882fe08c741..ba63a4bb573 100644 --- a/libs/libvtrutil/src/vtr_assert.h +++ b/libs/libvtrutil/src/vtr_assert.h @@ -1,9 +1,12 @@ #ifndef VTR_ASSERT_H #define VTR_ASSERT_H -/* - * The header defines useful assertion macros for VTR projects. + +/** + * @file + * @brief The header vtr_assert.h defines useful assertion macros for VTR projects. + * + * Four types of assertions are defined: * - * Three types of assertions are defined: * VTR_ASSERT_OPT - low overhead assertions that should always be enabled * VTR_ASSERT - medium overhead assertions that are usually be enabled * VTR_ASSERT_SAFE - high overhead assertions typically enabled only for debugging @@ -13,22 +16,23 @@ * By convention the message should state the condition *being checked* (and not the failure condition), * since that the condition failed is obvious from the assertion failure itself. * - * The macro VTR_ASSERT_LEVEL specifies the level of assertion checking desired: + * The macro VTR_ASSERT_LEVEL specifies the level of assertion checking desired and is updated in CMAKE compilation: * * VTR_ASSERT_LEVEL == 4: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE, VTR_ASSERT_DEBUG enabled * VTR_ASSERT_LEVEL == 3: VTR_ASSERT_OPT, VTR_ASSERT, VTR_ASSERT_SAFE enabled * VTR_ASSERT_LEVEL == 2: VTR_ASSERT_OPT, VTR_ASSERT enabled * VTR_ASSERT_LEVEL == 1: VTR_ASSERT_OPT enabled * VTR_ASSERT_LEVEL == 0: No assertion checking enabled - * Note that an assertion levels beyond 4 are currently treated the same as level 4 + * + * @Note that an assertion levels beyond 4 are currently treated the same as level 4 and the default assertion level is 2 */ -//Set a default assertion level if none is specified +// Set a default assertion level if none is specified #ifndef VTR_ASSERT_LEVEL # define VTR_ASSERT_LEVEL 2 #endif -//Enable the assertions based on the specified level +// Enable the assertions based on the specified level #if VTR_ASSERT_LEVEL >= 4 # define VTR_ASSERT_DEBUG_ENABLED #endif @@ -45,7 +49,7 @@ # define VTR_ASSERT_OPT_ENABLED #endif -//Define the user assertion macros +// Define the user assertion macros #ifdef VTR_ASSERT_DEBUG_ENABLED # define VTR_ASSERT_DEBUG(expr) VTR_ASSERT_IMPL(expr, nullptr) # define VTR_ASSERT_DEBUG_MSG(expr, msg) VTR_ASSERT_IMPL(expr, msg) @@ -78,9 +82,12 @@ # define VTR_ASSERT_OPT_MSG(expr, msg) VTR_ASSERT_IMPL_NOP(expr, msg) #endif -//Define the assertion implementation macro -// We wrap the check in a do {} while() to ensure the function-like -// macro can be always be followed by a ';' +/** + * @brief Define the assertion implementation macro + * + * We wrap the check in a do {} while() to ensure the function-like + * macro can be always be followed by a ';' + */ #define VTR_ASSERT_IMPL(expr, msg) \ do { \ if (!(expr)) { \ @@ -88,27 +95,33 @@ } \ } while (false) -//Define the no-op assertion implementation macro -// We wrap the check in a do {} while() to ensure the function-like -// macro can be always be followed by a ';' -// -// Note that to avoid 'unused' variable warnings when assertions are -// disabled, we pass the expr and msg to sizeof(). We use sizeof specifically -// since it accepts expressions, and the C++ standard gaurentees sizeof's arguments -// are never evaluated (ensuring any expensive expressions are not evaluated when -// assertions are disabled). To avoid warnings about the unused result of sizeof() -// we cast it to void. +/** + * @brief Define the no-op assertion implementation macro + * + * We wrap the check in a do {} while() to ensure the function-like + * macro can be always be followed by a ';' + * + * Note that to avoid 'unused' variable warnings when assertions are + * disabled, we pass the expr and msg to sizeof(). We use sizeof specifically + * since it accepts expressions, and the C++ standard gaurentees sizeof's arguments + * are never evaluated (ensuring any expensive expressions are not evaluated when + * assertions are disabled). To avoid warnings about the unused result of sizeof() + * we cast it to void. + */ #define VTR_ASSERT_IMPL_NOP(expr, msg) \ do { \ static_cast(sizeof(expr)); \ static_cast(sizeof(msg)); \ } while (false) -//Figure out what macro to use to get the name of the current function -// We default to __func__ which is defined in C99 -// -// g++ > 2.6 define __PRETTY_FUNC__ which includes class/namespace/overload -// information, so we prefer to use it if possible +/** + * @brief Figure out what macro to use to get the name of the current function + * + * We default to __func__ which is defined in C99 + * + * g++ > 2.6 define __PRETTY_FUNC__ which includes class/namespace/overload + * information, so we prefer to use it if possible + */ #define VTR_ASSERT_FUNCTION __func__ #ifdef __GNUC__ # ifdef __GNUC_MINOR__ @@ -121,14 +134,16 @@ namespace vtr { namespace assert { -//Assertion handling routine -// -//Note that we mark the routine with the standard C++11 -//attribute 'noreturn' which tells the compiler this -//function will never return. This should ensure the -//compiler won't warn about detected conditions such as -//dead-code or potential null pointer dereferences -//which are gaurded against by assertions. +/** + * @brief Assertion handling routine + * + * Note that we mark the routine with the standard C++11 + * attribute 'noreturn' which tells the compiler this + * function will never return. This should ensure the + * compiler won't warn about detected conditions such as + * dead-code or potential null pointer dereferences + * which are gaurded against by assertions. + */ [[noreturn]] void handle_assert(const char* expr, const char* file, unsigned int line, const char* function, const char* msg); } // namespace assert } // namespace vtr diff --git a/libs/libvtrutil/src/vtr_bimap.h b/libs/libvtrutil/src/vtr_bimap.h index 5cc90f89d4e..59bc19b42d0 100644 --- a/libs/libvtrutil/src/vtr_bimap.h +++ b/libs/libvtrutil/src/vtr_bimap.h @@ -1,5 +1,18 @@ #ifndef VTR_BIMAP #define VTR_BIMAP + +/** + * @file + * @brief The vtr_bimap.h header provides a bi-directonal mapping between key and value which means that it can be addressed by either the key or the value + * + * It provides this bi-directional feature for all the map-like containers defined in vtr: + * - unordered map + * - flat map + * - linear map + * + * One example where this container might be so useful is the mapping between the atom and clustered net Id. See atom_lookup.h + */ + #include #include #include "vtr_flat_map.h" @@ -9,8 +22,8 @@ namespace vtr { -/* - * A map-like class which provides a bi-directonal mapping between key and value +/** + * @brief A map-like class which provides a bi-directonal mapping between key and value * * Keys and values can be looked up directly by passing either the key or value. * the indexing operator will throw if the key/value does not exist. @@ -23,23 +36,30 @@ class bimap { public: //Accessors //Iterators + + ///@brief Return an iterator to the begin of the map iterator begin() const { return map_.begin(); } + + ///@brief Return an iterator to the end of the map iterator end() const { return map_.end(); } + + ///@brief Return an iterator to the begin of the inverse map inverse_iterator inverse_begin() const { return inverse_map_.begin(); } + + ///@brief Return an iterator to the end of the inverse map inverse_iterator inverse_end() const { return inverse_map_.end(); } - //Return an iterator to the key-value pair matching key, or end() if not found + ///@brief Return an iterator to the key-value pair matching key, or end() if not found iterator find(const K key) const { return map_.find(key); } - //Return an iterator to the value-key pair matching value, or inverse_end() if not found + ///@brief Return an iterator to the value-key pair matching value, or inverse_end() if not found inverse_iterator find(const V value) const { return inverse_map_.find(value); } - //Return an immutable reference to the value matching key - //Will throw an exception if key is not found + ///@brief Return an immutable reference to the value matching key (throw an exception if key is not found) const V& operator[](const K key) const { auto iter = find(key); if (iter == end()) { @@ -48,8 +68,7 @@ class bimap { return iter->second; } - //Return an immutable reference to the key matching value - //Will throw an exception if value is not found + ///@brief Return an immutable reference to the key matching value (throw an exception if value is not found) const K& operator[](const V value) const { auto iter = find(value); if (iter == inverse_end()) { @@ -58,46 +77,46 @@ class bimap { return iter->second; } - //Return the number of key-value pairs stored + ///@brief Return the number of key-value pairs stored std::size_t size() const { VTR_ASSERT(map_.size() == inverse_map_.size()); return map_.size(); } - //Return true if there are no key-value pairs stored + ///@brief Return true if there are no key-value pairs stored bool empty() const { return (size() == 0); } - //Return true if the specified key exists + ///@brief Return true if the specified key exists bool contains(const K key) const { return find(key) != end(); } - //Return true if the specified value exists + ///@brief Return true if the specified value exists bool contains(const V value) const { return find(value) != inverse_end(); } public: //Mutators - //Drop all stored key-values + ///@brief Drop all stored key-values void clear() { map_.clear(); inverse_map_.clear(); } - //Insert a key-value pair, if not already in map + ///@brief Insert a key-value pair, if not already in map std::pair insert(const K key, const V value) { auto ret1 = map_.insert({key, value}); auto ret2 = inverse_map_.insert({value, key}); VTR_ASSERT(ret1.second == ret2.second); - //Return true if inserted + // Return true if inserted return ret1; } - //Update a key-value pair, will insert if not already in map + ///@brief Update a key-value pair, will insert if not already in map void update(const K key, const V value) { map_[key] = value; inverse_map_[value] = key; } - //Remove the specified key (and it's associated value) + ///@brief Remove the specified key (and it's associated value) void erase(const K key) { auto iter = map_.find(key); if (iter != map_.end()) { @@ -110,7 +129,7 @@ class bimap { } } - //Remove the specified value (and it's associated key) + ///@brief Remove the specified value (and it's associated key) void erase(const V val) { auto inv_iter = inverse_map_.find(val); if (inv_iter != inverse_map_.end()) { @@ -123,7 +142,7 @@ class bimap { } } - //Swap (this enables std::swap via ADL) + ///@brief Swap (this enables std::swap via ADL) friend void swap(bimap& x, bimap& y) { std::swap(x.map_, y.map_); std::swap(x.inverse_map_, y.inverse_map_); diff --git a/libs/libvtrutil/src/vtr_cache.h b/libs/libvtrutil/src/vtr_cache.h index d1496d2f906..30871cd44ca 100644 --- a/libs/libvtrutil/src/vtr_cache.h +++ b/libs/libvtrutil/src/vtr_cache.h @@ -5,19 +5,21 @@ namespace vtr { -// Simple cache +///@brief An implementation of a simple cache template class Cache { public: - // Clear cache. + ///@brief Clear cache. void clear() { key_ = CacheKey(); value_.reset(); } - - // Check if the cache is valid, and return the cached value if present and valid. - // - // Returns nullptr if the cache is invalid. + /** + * @brief Check if the cache is valid. + * + * Returns the cached value if present and valid. + * Returns nullptr if the cache is invalid. + */ const CacheValue* get(const CacheKey& key) const { if (key == key_ && value_) { return value_.get(); @@ -26,7 +28,7 @@ class Cache { } } - // Update the cache. + ///@brief Update the cache. const CacheValue* set(const CacheKey& key, std::unique_ptr value) { key_ = key; value_ = std::move(value); diff --git a/libs/libvtrutil/src/vtr_color_map.h b/libs/libvtrutil/src/vtr_color_map.h index 310ecd1841c..f313999caf2 100644 --- a/libs/libvtrutil/src/vtr_color_map.h +++ b/libs/libvtrutil/src/vtr_color_map.h @@ -4,6 +4,7 @@ namespace vtr { +///@brief A container to save the rgb components of a color template struct Color { T r; @@ -11,13 +12,25 @@ struct Color { T b; }; +///@brief A class that holds a complete color map class ColorMap { public: + ///@brief color map constructor ColorMap(float min, float max, const std::vector>& color_data); + + ///@brief color map destructor virtual ~ColorMap() = default; + + ///@brief Returns the full color corresponding to the input value Color color(float value) const; + + ///@brief Return the min Color of this color map float min() const; + + ///@brief Return the max color of this color map float max() const; + + ///@brief Return the range of the color map float range() const; private: diff --git a/libs/libvtrutil/src/vtr_digest.h b/libs/libvtrutil/src/vtr_digest.h index ae8ab388e4f..4d67f8f6acd 100644 --- a/libs/libvtrutil/src/vtr_digest.h +++ b/libs/libvtrutil/src/vtr_digest.h @@ -5,10 +5,10 @@ namespace vtr { -//Generate a secure hash of the file at filepath +///@brief Generate a secure hash of the file at filepath std::string secure_digest_file(const std::string& filepath); -//Generate a secure hash of a stream +///@brief Generate a secure hash of a stream std::string secure_digest_stream(std::istream& is); } // namespace vtr diff --git a/libs/libvtrutil/src/vtr_dynamic_bitset.h b/libs/libvtrutil/src/vtr_dynamic_bitset.h index 3500fbba526..291ddd2396c 100644 --- a/libs/libvtrutil/src/vtr_dynamic_bitset.h +++ b/libs/libvtrutil/src/vtr_dynamic_bitset.h @@ -5,30 +5,38 @@ #include namespace vtr { - +/** + * @brief A container to represent a set of flags either they are set or reset + * + * It allocates any required length of bit at runtime. It is very useful in bit manipulation + */ template class dynamic_bitset { public: - // Bits in underlying storage. + ///@brief Bits in underlying storage. static constexpr size_t kWidth = std::numeric_limits::digits; static_assert(!std::numeric_limits::is_signed, "dynamic_bitset storage must be unsigned!"); static_assert(std::numeric_limits::is_integer, "dynamic_bitset storage must be integer!"); + ///@brief Reize to the determined size void resize(size_t size) { array_.resize((size + kWidth - 1) / kWidth); } + ///@brief Clear all the bits void clear() { array_.clear(); array_.shrink_to_fit(); } + ///@brief Return the size of the bitset (total number of bits) size_t size() const { return array_.size() * kWidth; } + ///@brief Fill the whole bitset with a specific value (0 or 1) void fill(bool set) { if (set) { std::fill(array_.begin(), array_.end(), std::numeric_limits::max()); @@ -37,6 +45,7 @@ class dynamic_bitset { } } + ///@brief Set a specific bit in the bit set to a specific value (0 or 1) void set(Index index, bool val) { size_t index_value(index); VTR_ASSERT_SAFE(index_value < size()); @@ -47,6 +56,7 @@ class dynamic_bitset { } } + ///@brief Return the value of a specific bit in the bitset bool get(Index index) const { size_t index_value(index); VTR_ASSERT_SAFE(index_value < size()); diff --git a/libs/libvtrutil/src/vtr_error.h b/libs/libvtrutil/src/vtr_error.h index a8b77c52f3b..82f1793a9fa 100644 --- a/libs/libvtrutil/src/vtr_error.h +++ b/libs/libvtrutil/src/vtr_error.h @@ -6,20 +6,39 @@ namespace vtr { +/** + * @brief Contriner that holds informations related to an error + * + * It holds different info related to a VTR error: + * - error message + * - file name associated with the error + * - line number associated with the error + */ class VtrError : public std::runtime_error { public: + ///@brief VtrError constructor VtrError(std::string msg = "", std::string new_filename = "", size_t new_linenumber = -1) : std::runtime_error(msg) , filename_(new_filename) , linenumber_(new_linenumber) {} - //Returns the filename associated with this error - //returns an empty string if none is specified + /** + * @brief gets the filename + * + * Returns the filename associated with this error. + * Returns an empty string if none is specified. + */ std::string filename() const { return filename_; } + + ///@brief same as filename() but returns in c style string const char* filename_c_str() const { return filename_.c_str(); } - //Returns the line number associated with this error - //returns zero if none is specified + /** + * @brief get the line number + * + * Returns the line number associated with this error. + * Returns zero if none is specified. + */ size_t line() const { return linenumber_; } private: diff --git a/libs/libvtrutil/src/vtr_expr_eval.h b/libs/libvtrutil/src/vtr_expr_eval.h index 1d940492387..0671bf92f7e 100644 --- a/libs/libvtrutil/src/vtr_expr_eval.h +++ b/libs/libvtrutil/src/vtr_expr_eval.h @@ -13,29 +13,50 @@ #include "vtr_flat_map.h" #include "../../../vpr/src/draw/breakpoint_state_globals.h" -/**The expression evaluator is capable of performing many operations on given variables, after parsing the expression. The parser goes character by character and identifies the type of char or chars. (e.g bracket, comma, number, operator, variable). The supported operations include addition, subtraction, multiplication, division, finding max, min, gcd, lcm, as well as boolean operators such as &&, ||, ==, >=, <= etc. The result is returned as an int value and operation precedance is taken into account. (e.g given 3-2*4, the result will be -5). This class is also used to parse expressions indicating breakpoints. The breakpoint expressions consist of variable names such as move_num, temp_num, from_block etc, and boolean operators (e.g move_num == 3). Multiple breakpoints can be expressed in one expression**/ +/** + * @file + * @brief This file implements an expressopn evaluator + * + * The expression evaluator is capable of performing many operations on given variables, + * after parsing the expression. The parser goes character by character and identifies + * the type of char or chars. (e.g bracket, comma, number, operator, variable). + * The supported operations include addition, subtraction, multiplication, division, + * finding max, min, gcd, lcm, as well as boolean operators such as &&, ||, ==, >=, <= etc. + * The result is returned as an int value and operation precedance is taken into account. + * (e.g given 3-2*4, the result will be -5). This class is also used to parse expressions + * indicating breakpoints. The breakpoint expressions consist of variable names such as + * move_num, temp_num, from_block etc, and boolean operators (e.g move_num == 3). + * Multiple breakpoints can be expressed in one expression + */ //function declarations -//returns the global variable that holds all values that can trigger a breakpoint and are updated by the router and placer +///@brief returns the global variable that holds all values that can trigger a breakpoint and are updated by the router and placer BreakpointStateGlobals* get_bp_state_globals(); namespace vtr { /**** Structs ****/ +///@brief a class to hold the formula data class t_formula_data { public: + ///@brief clears all the formula data void clear() { vars_.clear(); } + ///@brief set the value of a specific part of the formula void set_var_value(vtr::string_view var, int value) { vars_[var] = value; } + + ///@brief set the value of a specific part of the formula (the var can be c-style string) void set_var_value(const char* var, int value) { vars_[vtr::string_view(var)] = value; } + ///@brief get the value of a specific part of the formula int get_var_value(const std::string& var) const { return get_var_value(vtr::string_view(var.data(), var.size())); } + ///@brief get the value of a specific part of the formula (the var can be c-style string) int get_var_value(vtr::string_view var) const { auto iter = vars_.find(var); if (iter == vars_.end()) { @@ -51,7 +72,7 @@ class t_formula_data { }; /**** Enums ****/ -/* Used to identify the type of symbolic formula object */ +///@brief Used to identify the type of symbolic formula object typedef enum e_formula_obj { E_FML_UNDEFINED = 0, E_FML_NUMBER, @@ -62,7 +83,7 @@ typedef enum e_formula_obj { E_FML_NUM_FORMULA_OBJS } t_formula_obj; -/* Used to identify an operator in a formula */ +///@brief Used to identify an operator in a formula typedef enum e_operator { E_OP_UNDEFINED = 0, E_OP_ADD, @@ -85,7 +106,7 @@ typedef enum e_operator { E_OP_NUM_OPS } t_operator; -/* Used to identify operators with more than one character */ +///@brief Used to identify operators with more than one character typedef enum e_compound_operator { E_COM_OP_UNDEFINED = 0, E_COM_OP_AND, @@ -98,27 +119,38 @@ typedef enum e_compound_operator { } t_compound_operator; /**** Class Definitions ****/ -/* This class is used to represent an object in a formula, such as - * a number, a bracket, an operator, or a variable */ +/** + * @brief A class represents an object in a formula + * + * This object can be any of the following: + * - a number + * - a bracket + * - an operator + * - a variable + */ class Formula_Object { public: - /* indicates the type of formula object this is */ + ///@brief indicates the type of formula object this is t_formula_obj type; - /* object data, accessed based on what kind of object this is */ + /** + * @brief object data, accessed based on what kind of object this is + */ union u_Data { - int num; /*for number objects*/ - t_operator op; /*for operator objects*/ - bool left_bracket; /*for bracket objects -- specifies if this is a left bracket*/ + int num; ///< for number objects + t_operator op; ///< for operator objects + bool left_bracket; ///< for bracket objects -- specifies if this is a left bracket //std::string variable; u_Data() { memset(this, 0, sizeof(u_Data)); } } data; + ///@brief constructor Formula_Object() { this->type = E_FML_UNDEFINED; } + ///@brief convert enum to string std::string to_string() const { if (type == E_FML_NUMBER || type == E_FML_VARIABLE) { return std::to_string(data.num); @@ -174,24 +206,27 @@ class Formula_Object { } }; +///@brief A class to parse formula class FormulaParser { public: FormulaParser() = default; FormulaParser(const FormulaParser&) = delete; FormulaParser& operator=(const FormulaParser&) = delete; - /* returns integer result according to specified formula and data */ + ///@brief returns integer result according to specified formula and data int parse_formula(std::string formula, const t_formula_data& mydata, bool is_breakpoint = false); - /* returns integer result according to specified piece-wise formula and data */ + ///@brief returns integer result according to specified piece-wise formula and data int parse_piecewise_formula(const char* formula, const t_formula_data& mydata); - /* checks if the specified formula is piece-wise defined */ + ///@brief checks if the specified formula is piece-wise defined static bool is_piecewise_formula(const char* formula); private: std::vector rpn_output_; - std::stack op_stack_; /* stack for handling operators and brackets in formula */ + + // stack for handling operators and brackets in formula + std::stack op_stack_; }; } // namespace vtr diff --git a/libs/libvtrutil/src/vtr_flat_map.h b/libs/libvtrutil/src/vtr_flat_map.h index 1d1f0331d2b..90a7caefb3a 100644 --- a/libs/libvtrutil/src/vtr_flat_map.h +++ b/libs/libvtrutil/src/vtr_flat_map.h @@ -16,38 +16,46 @@ class flat_map; template, class Storage = std::vector>> class flat_map2; -//Helper function to create a flat map from a vector of pairs -//without haveing to explicity specify the key and value types +/** + * @brief A function to create a flat map + * + * Helper function to create a flat map from a vector of pairs + * without haveing to explicity specify the key and value types + */ template flat_map make_flat_map(std::vector>&& vec) { return flat_map(std::move(vec)); } + +///@brief Same as make_flat_map but for flat_map2 template flat_map2 make_flat_map2(std::vector>&& vec) { return flat_map2(std::move(vec)); } -// -// flat_map is a (nearly) std::map compatible container which uses a vector -// as it's underlying storage. Internally the stored elements are kept sorted -// allowing efficient look-up in O(logN) time via binary search. -// -// This container is typically useful in the following scenarios: -// * Reduced memory usage if key/value are small (std::map needs to store pointers to -// other BST nodes which can add substantial overhead for small keys/values) -// * Faster search/iteration by exploiting data locality (all elments are in continguous -// memory enabling better spatial locality) -// -// The container deviates from the behaviour of std::map in the following important ways: -// * Insertion/erase takes O(N) instead of O(logN) time -// * Iterators may be invalidated on insertion/erase (i.e. if the vector is reallocated) -// -// The slow insertion/erase performance makes this container poorly suited to maps that -// frequently add/remove new keys. If this is required you likely want std::map or -// std::unordered_map. However if the map is constructed once and then repeatedly quieried, -// consider using the range or vector-based constructors which initializes the flat_map in -// O(NlogN) time. -// +/** + * @brief flat_map is a (nearly) std::map compatible container + * + * It uses a vector as it's underlying storage. Internally the stored elements + * are kept sorted allowing efficient look-up in O(logN) time via binary search. + * + * + * This container is typically useful in the following scenarios: + * - Reduced memory usage if key/value are small (std::map needs to store pointers to + * other BST nodes which can add substantial overhead for small keys/values) + * - Faster search/iteration by exploiting data locality (all elments are in continguous + * memory enabling better spatial locality) + * + * The container deviates from the behaviour of std::map in the following important ways: + * - Insertion/erase takes O(N) instead of O(logN) time + * - Iterators may be invalidated on insertion/erase (i.e. if the vector is reallocated) + * + * The slow insertion/erase performance makes this container poorly suited to maps that + * frequently add/remove new keys. If this is required you likely want std::map or + * std::unordered_map. However if the map is constructed once and then repeatedly quieried, + * consider using the range or vector-based constructors which initializes the flat_map in + * O(NlogN) time. + */ template class flat_map { public: @@ -67,40 +75,43 @@ class flat_map { class value_compare; public: - //Standard big 5 + ///@brief Standard constructors flat_map() = default; flat_map(const flat_map&) = default; flat_map(flat_map&&) = default; flat_map& operator=(const flat_map&) = default; flat_map& operator=(flat_map&&) = default; - //range constructor + ///@brief range constructor template flat_map(InputIterator first, InputIterator last) { - //Copy the values + // Copy the values std::copy(first, last, std::back_inserter(vec_)); sort(); uniquify(); } - //direct vector constructor + ///@brief direct vector constructor explicit flat_map(Storage&& values) { assign(std::move(values)); } + /** + * @brief Move the values + * + * Should be more efficient than the range constructor which + * must copy each element + */ void assign(Storage&& values) { - //By moving the values this should be more efficient - //than the range constructor which must copy each element vec_ = std::move(values); sort(); uniquify(); } + ///@brief By moving the values this should be more efficient than the range constructor which must copy each element void assign_sorted(Storage&& values) { - //By moving the values this should be more efficient - //than the range constructor which must copy each element vec_ = std::move(values); if (vec_.size() > 1) { for (size_t i = 0; i < vec_.size() - 1; ++i) { @@ -109,23 +120,52 @@ class flat_map { } } + ///@brief Return an iterator pointing to the first element in the sequence: iterator begin() { return vec_.begin(); } + + ///@brief Return a constant iterator pointing to the first element in the sequence: const_iterator begin() const { return vec_.begin(); } + + ///@brief Returns an iterator referring to the past-the-end element in the vector container. iterator end() { return vec_.end(); } + + ///@brief Returns a constant iterator referring to the past-the-end element in the vector container. const_iterator end() const { return vec_.end(); } + + ///@brief Returns a reverse iterator which points to the last element of the map. reverse_iterator rbegin() { return vec_.rbegin(); } + + ///@brief Returns a constant reverse iterator which points to the last element of the map. const_reverse_iterator rbegin() const { return vec_.rbegin(); } + + ///@brief Returns a reverse iterator pointing to the theoretical element preceding the first element in the vector (which is considered its reverse end). reverse_iterator rend() { return vec_.rend(); } + + ///@brief Returns a constant reverse iterator pointing to the theoretical element preceding the first element in the vector (which is considered its reverse end). const_reverse_iterator rend() const { return vec_.rend(); } + + ///@brief Returns a constant_iterator to the first element in the underlying vector const_iterator cbegin() const { return vec_.begin(); } + + ///@brief Returns a const_iterator pointing to the past-the-end element in the container. const_iterator cend() const { return vec_.end(); } + + ///@brief Returns a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). const_reverse_iterator crbegin() const { return vec_.rbegin(); } + + ///@brief Returns a const_reverse_iterator pointing to the theoretical element preceding the first element in the container (which is considered its reverse end). const_reverse_iterator crend() const { return vec_.rend(); } + ///@brief Return true if the underlying vector is empty bool empty() const { return vec_.empty(); } + + ///@brief Return the container size size_type size() const { return vec_.size(); } + + ///@brief Return the underlying vector's max size size_type max_size() const { return vec_.max_size(); } + ///@brief The constant version of operator [] const mapped_type& operator[](const key_type& key) const { auto iter = find(key); if (iter == end()) { @@ -136,6 +176,7 @@ class flat_map { return iter->second; } + ///@brief operator [] mapped_type& operator[](const key_type& key) { auto iter = std::lower_bound(begin(), end(), key, value_comp()); if (iter == end()) { @@ -155,10 +196,12 @@ class flat_map { } } + ///@brief operator at() mapped_type& at(const key_type& key) { return const_cast(const_cast(this)->at(key)); } + ///@brief The constant version of at() operator const mapped_type& at(const key_type& key) const { auto iter = find(key); if (iter == end()) { @@ -167,7 +210,7 @@ class flat_map { return iter->second; } - //Insert value + ///@brief Insert value std::pair insert(const value_type& value) { auto iter = lower_bound(value.first); if (iter != end() && keys_equivalent(iter->first, value.first)) { @@ -181,6 +224,7 @@ class flat_map { } } + ///@brief Emplace function std::pair emplace(const value_type&& value) { auto iter = lower_bound(value.first); if (iter != end() && keys_equivalent(iter->first, value.first)) { @@ -194,7 +238,7 @@ class flat_map { } } - //Insert value with position hint + ///@brief Insert value with position hint iterator insert(const_iterator position, const value_type& value) { //In a legal position VTR_ASSERT(position == begin() || value_comp()(*(position - 1), value)); @@ -205,7 +249,7 @@ class flat_map { return iter; } - //Emplace value with position hint + ///@brief Emplace value with position hint iterator emplace(const_iterator position, const value_type& value) { //In a legal position VTR_ASSERT(position == begin() || value_comp()(*(position - 1), value)); @@ -216,7 +260,7 @@ class flat_map { return iter; } - //Insert range + ///@brief Insert range template void insert(InputIterator first, InputIterator last) { vec_.insert(vec_.end(), first, last); @@ -226,7 +270,7 @@ class flat_map { uniquify(); } - //Erase by key + ///@brief Erase by key void erase(const key_type& key) { auto iter = find(key); if (iter != end()) { @@ -234,20 +278,23 @@ class flat_map { } } - //Erase at iterator + ///@brief Erase at iterator void erase(const_iterator position) { vec_.erase(position); } - //Erase range + ///@brief Erase range void erase(const_iterator first, const_iterator last) { vec_.erase(first, last); } + ///@brief swap two flat maps void swap(flat_map& other) { std::swap(*this, other); } + ///@brief clear the flat map void clear() { vec_.clear(); } + ///@brief templated emplace function template iterator emplace(const key_type& key, Args&&... args) { auto iter = lower_bound(key); @@ -261,22 +308,31 @@ class flat_map { } } + ///@brief templated emplace_hint function template iterator emplace_hint(const_iterator position, Args&&... args) { return vec_.emplace(position, std::forward(args)...); } + ///@brief Reserve a minimum capacity for the underlying vector void reserve(size_type n) { vec_.reserve(n); } + + ///@brief Reduce the capacity of the underlying vector to fit its size void shrink_to_fit() { vec_.shrink_to_fit(); } + ///@brief key_compare key_comp() const { return key_compare(); } + + ///@brief value_compare value_comp() const { return value_compare(key_comp()); } + ///@brief Find a key and return an iterator to the found key iterator find(const key_type& key) { const_iterator const_iter = const_cast(this)->find(key); return convert_to_iterator(const_iter); } + ///@brief Find a key and return a constant iterator to the found key const_iterator find(const key_type& key) const { auto iter = lower_bound(key); if (iter != end() && keys_equivalent(iter->first, key)) { @@ -286,38 +342,46 @@ class flat_map { return end(); } + ///@brief Return the count of occurances of a key size_type count(const key_type& key) const { return (find(key) == end()) ? 0 : 1; } + ///@brief lower bound function iterator lower_bound(const key_type& key) { const_iterator const_iter = const_cast(this)->lower_bound(key); return convert_to_iterator(const_iter); } + ///@brief Return a constant iterator to the lower bound const_iterator lower_bound(const key_type& key) const { return std::lower_bound(begin(), end(), key, value_comp()); } + ///@brief upper bound function iterator upper_bound(const key_type& key) { const_iterator const_iter = const_cast(this)->upper_bound(key); return convert_to_iterator(const_iter); } + ///@brief Return a constant iterator to the upper bound const_iterator upper_bound(const key_type& key) const { return std::upper_bound(begin(), end(), key, value_comp()); } + ///@brief Returns a range containing all elements equivalent to "key" std::pair equal_range(const key_type& key) { auto const_iter_pair = const_cast(this)->equal_range(key); return std::pair(iterator(const_iter_pair.first), iterator(const_iter_pair.second)); } + ///@brief Returns a constant range containing all elements equivalent to "key" std::pair equal_range(const key_type& key) const { return std::equal_range(begin(), end(), key); } public: + ///@brief Swaps 2 flat maps friend void swap(flat_map& lhs, flat_map& rhs) { std::swap(lhs.vec_, rhs.vec_); } private: @@ -338,19 +402,20 @@ class flat_map { } iterator convert_to_iterator(const_iterator const_iter) { - //This is a work around for the fact that there is no conversion between - //a const_iterator and iterator. - // - //We intiailize i to the start of the container and then advance it by - //the distance to const_iter. The resulting i points to the same element - //as const_iter - // - //Note that to be able to call std::distance with an iterator and - //const_iterator we need to specify the type as const_iterator (relying - //on the implicit conversion from iterator to const_iterator for i) - // - //Since the iterators are really vector (i.e. random-access) iterators - //this takes constant time + /* + * A work around as there is no conversion betweena const_iterator and iterator. + * + * We intiailize i to the start of the container and then advance it by + * the distance to const_iter. The resulting i points to the same element + * as const_iter + * + * Note that to be able to call std::distance with an iterator and + * const_iterator we need to specify the type as const_iterator (relying + * on the implicit conversion from iterator to const_iterator for i) + * + * Since the iterators are really vector (i.e. random-access) iterators + * this takes constant time + */ iterator i = begin(); std::advance(i, std::distance(i, const_iter)); return i; @@ -360,14 +425,20 @@ class flat_map { Storage vec_; }; -//Like flat_map, but operator[] never inserts and directly returns the mapped value +/** + * @brief Another flat_map container + * + * Like flat_map, but operator[] never inserts and directly returns the mapped value + */ template class flat_map2 : public flat_map { public: + ///@brief Constructor flat_map2() {} explicit flat_map2(std::vector::value_type>&& values) : flat_map(std::move(values)) {} + ///@brief const [] operator const T& operator[](const K& key) const { auto itr = this->find(key); if (itr == this->end()) { @@ -376,11 +447,13 @@ class flat_map2 : public flat_map { return itr->second; } + ///@brief [] operator T& operator[](const K& key) { return const_cast(const_cast(this)->operator[](key)); } }; +///@brief A class to perform the comparison operation for the flat map template class flat_map::value_compare { friend class flat_map; @@ -390,7 +463,7 @@ class flat_map::value_compare { return comp(x.first, y.first); } - //For std::lower_bound/std::upper_bound + //For std::lower_bound, std::upper_bound bool operator()(const value_type& x, const key_type& y) const { return comp(x.first, y); } diff --git a/libs/libvtrutil/src/vtr_geometry.h b/libs/libvtrutil/src/vtr_geometry.h index 73d774b09d6..c15a794b8fb 100644 --- a/libs/libvtrutil/src/vtr_geometry.h +++ b/libs/libvtrutil/src/vtr_geometry.h @@ -8,6 +8,11 @@ #include #include +/** + * @file + * @brief This file include differents different geometry classes + */ + namespace vtr { /* @@ -45,27 +50,44 @@ bool operator!=(const RectUnion& lhs, const RectUnion& rhs); * Class Definitions */ -//A point in 2D space +/** + * @brief A point in 2D space + * + * This class represents a point in 2D space. Hence, it holds both + * x and y components of the point. + */ template class Point { public: //Constructors Point(T x_val, T y_val) noexcept; public: //Accessors - //Coordinates + ///@brief x coordinate T x() const; + + ///@brief y coordinate T y() const; + ///@brief == operator friend bool operator== <>(Point lhs, Point rhs); + + ///@brief != operator friend bool operator!= <>(Point lhs, Point rhs); + + ///@brief < operator friend bool operator< <>(Point lhs, Point rhs); public: //Mutators - /* Set x and y values */ + ///@brief Set x and y values void set(T x_val, T y_val); + + ///@brief set x value void set_x(T x_val); + + ///@brief set y value void set_y(T y_val); - /* Swap x and y values */ + + ///@brief Swap x and y values void swap(); private: @@ -73,62 +95,100 @@ class Point { T y_; }; -//A 2D rectangle +/** + * @brief A 2D rectangle + * + * This class represents a 2D rectangle. It can be created with + * its 4 points or using the bottom left and the top rights ones only + */ template class Rect { public: //Constructors + ///@brief default constructor Rect(); + + ///@brief construct using 4 vertex Rect(T left_val, T bottom_val, T right_val, T top_val); + + ///@brief construct using the bottom left and the top right vertex Rect(Point bottom_left_val, Point top_right_val); - //Constructs a rectangle that only contains the given point - // Rect(p1).contains(p2) => p1 == p2 - //It is only enabled for integral types, because making this work for floating point types would be difficult and brittle. - //The following line only enables the constructor if std::is_integral::value == true + /** + * @brief Constructs a rectangle that only contains the given point + * + * Rect(p1).contains(p2) => p1 == p2 + * It is only enabled for integral types, because making this work for floating point types would be difficult and brittle. + * The following line only enables the constructor if std::is_integral::value == true + */ template::value>::type...> Rect(Point point); public: //Accessors - //Co-ordinates + ///@brief xmin coordinate T xmin() const; + + ///@brief xmax coordinate T xmax() const; + + ///@brief ymin coodrinate T ymin() const; + + ///@brief ymax coordinate T ymax() const; + ///@brief Return the bottom left point Point bottom_left() const; + + ///@brief Return the top right point Point top_right() const; + ///@brief Return the rectangle width T width() const; + + ///@brief Return the rectangle height T height() const; - //Returns true if the point is fully contained within the rectangle (excluding the top-right edges) + ///@brief Returns true if the point is fully contained within the rectangle (excluding the top-right edges) bool contains(Point point) const; - //Returns true if the point is strictly contained within the region (excluding all edges) + ///@brief Returns true if the point is strictly contained within the region (excluding all edges) bool strictly_contains(Point point) const; - //Returns true if the point is coincident with the rectangle (including the top-right edges) + ///@brief Returns true if the point is coincident with the rectangle (including the top-right edges) bool coincident(Point point) const; - //Returns true if other is contained within the rectangle (including all edges) + ///@brief Returns true if other is contained within the rectangle (including all edges) bool contains(const Rect& other) const; - //Returns true if no points are contained in the rectangle - // rect.empty() => not exists p. rect.contains(p) - // This also implies either the width or height is 0. + /** + * @brief Checks whether the rectangle is empty + * + * Returns true if no points are contained in the rectangle + * rect.empty() => not exists p. rect.contains(p) + * This also implies either the width or height is 0. + */ bool empty() const; + ///@brief == operator friend bool operator== <>(const Rect& lhs, const Rect& rhs); + + ///@brief != operator friend bool operator!= <>(const Rect& lhs, const Rect& rhs); public: //Mutators - //Co-ordinates + ///@brief set xmin to a point void set_xmin(T xmin_val); + + ///@brief set ymin to a point void set_ymin(T ymin_val); + + ///@brief set xmax to a point void set_xmax(T xmax_val); + + ///@brief set ymax to a point void set_ymax(T ymax_val); - //Equivalent to `*this = bounding_box(*this, other)` + ///@brief Equivalent to `*this = bounding_box(*this, other)` Rect& expand_bounding_box(const Rect& other); private: @@ -136,30 +196,40 @@ class Rect { Point top_right_; }; -//Return the smallest rectangle containing both given rectangles -//Note that this isn't a union and the resulting rectangle may include points not in either given rectangle +/** + * @brief Return the smallest rectangle containing both given rectangles + * + * Note that this isn't a union and the resulting rectangle may include points not in either given rectangle + */ template Rect bounding_box(const Rect& lhs, const Rect& rhs); -//Return the intersection of two given rectangles +///@brief Return the intersection of two given rectangles template Rect intersection(const Rect& lhs, const Rect& rhs); -//Sample on a uniformly spaced grid within a rectangle -// sample(vtr::Rect(l, h), 0, 0, M) == l -// sample(vtr::Rect(l, h), M, M, M) == h -//To avoid the edges, use `sample(r, x+1, y+1, N+1) for x, y, in 0..N-1 -//Only defined for integral types +/** + * @brief Sample on a uniformly spaced grid within a rectangle + * + * sample(vtr::Rect(l, h), 0, 0, M) == l + * sample(vtr::Rect(l, h), M, M, M) == h + * To avoid the edges, use `sample(r, x+1, y+1, N+1) for x, y, in 0..N-1 + * Only defined for integral types + */ template::value>::type...> Point sample(const vtr::Rect& r, T x, T y, T d); -// clamps v to be between low (lo) and high (hi), inclusive. +///@brief clamps v to be between low (lo) and high (hi), inclusive. template static constexpr const T& clamp(const T& v, const T& lo, const T& hi) { return std::min(std::max(v, lo), hi); } -//A 2D line +/** + * @brief A 2D line + * + * It is constructed using a vector of the line points + */ template class Line { public: //Types @@ -167,20 +237,21 @@ class Line { typedef vtr::Range point_range; public: //Constructors + ///@brief contructor Line(std::vector> line_points); public: //Accessors - //Returns the bounding box + ///@brief Returns the bounding box Rect bounding_box() const; - //Returns a range of constituent points + ///@brief Returns a range of constituent points point_range points() const; private: std::vector> points_; }; -//A union of 2d rectangles +///@brief A union of 2d rectangles template class RectUnion { public: //Types @@ -188,32 +259,37 @@ class RectUnion { typedef vtr::Range rect_range; public: //Constructors - //Construct from a set of rectangles + ///@brief Construct from a set of rectangles RectUnion(std::vector> rects); public: //Accessors - //Returns the bounding box of all rectangles in the union + ///@brief Returns the bounding box of all rectangles in the union Rect bounding_box() const; - //Returns true if the point is fully contained within the region (excluding top-right edges) + ///@brief Returns true if the point is fully contained within the region (excluding top-right edges) bool contains(Point point) const; - //Returns true if the point is strictly contained within the region (excluding all edges) + ///@brief Returns true if the point is strictly contained within the region (excluding all edges) bool strictly_contains(Point point) const; - //Returns true if the point is coincident with the region (including the top-right edges) + ///@brief Returns true if the point is coincident with the region (including the top-right edges) bool coincident(Point point) const; - //Returns a range of all constituent rectangles + ///@brief Returns a range of all constituent rectangles rect_range rects() const; - //Checks whether two RectUnions have identical representations - // Note: does not check whether the representations they are equivalent + /** + * @brief Checks whether two RectUnions have identical representations + * + * Note: does not check whether the representations they are equivalent + */ friend bool operator== <>(const RectUnion& lhs, const RectUnion& rhs); + + ///@brief != operator friend bool operator!= <>(const RectUnion& lhs, const RectUnion& rhs); private: - //Note that a union of rectanges may have holes and may not be contiguous + // Note that a union of rectanges may have holes and may not be contiguous std::vector> rects_; }; diff --git a/libs/libvtrutil/src/vtr_hash.h b/libs/libvtrutil/src/vtr_hash.h index b71939c22e1..99fd55807ac 100644 --- a/libs/libvtrutil/src/vtr_hash.h +++ b/libs/libvtrutil/src/vtr_hash.h @@ -4,9 +4,11 @@ namespace vtr { -//Hashes v and combines it with seed (as in boost) -// -//This is typically used to implement std::hash for composite types. +/** + * @brief Hashes v and combines it with seed (as in boost) + * + * This is typically used to implement std::hash for composite types. + */ template inline void hash_combine(std::size_t& seed, const T& v) { std::hash hasher; diff --git a/libs/libvtrutil/src/vtr_linear_map.h b/libs/libvtrutil/src/vtr_linear_map.h index bf3055a08d3..c0ef38cfca2 100644 --- a/libs/libvtrutil/src/vtr_linear_map.h +++ b/libs/libvtrutil/src/vtr_linear_map.h @@ -6,26 +6,27 @@ #include "vtr_sentinels.h" namespace vtr { - -//A std::map-like container which is indexed by K -// -//The main use of this container is to behave like a std::map which is optimized to hold -//mappings between a dense linear range of keys (e.g. vtr::StrongId). -// -//Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and -//that the conversion results in a linearly increasing index into the underlying vector. -//Also requires that K() return the sentinel value used to mark invalid entries. -// -//If you only need to access the value associated with the key consider using vtr::vector_map -//instead, which provides a similar but more std::vector-like interface. -// -//Note that it is possible to use linear_map with sparse/non-contiguous keys, but this is typically -//memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1], -//where max_key is the largest key that has been inserted. -// -//As with a std::vector, it is the caller's responsibility to ensure there is sufficient space -//when a given index/key before it is accessed. The exception to this are the find() and insert() -//methods which handle non-existing keys gracefully. +/** + * @brief A std::map-like container which is indexed by K + * + * The main use of this container is to behave like a std::map which is optimized to hold + * mappings between a dense linear range of keys (e.g. vtr::StrongId). + * + * Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and + * that the conversion results in a linearly increasing index into the underlying vector. + * Also requires that K() return the sentinel value used to mark invalid entries. + * + * If you only need to access the value associated with the key consider using vtr::vector_map + * instead, which provides a similar but more std::vector-like interface. + * + * Note that it is possible to use linear_map with sparse/non-contiguous keys, but this is typically + * memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1], + * where max_key is the largest key that has been inserted. + * + * As with a std::vector, it is the caller's responsibility to ensure there is sufficient space + * when a given index/key before it is accessed. The exception to this are the find() and insert() + * methods which handle non-existing keys gracefully. + */ template> class linear_map { public: @@ -42,7 +43,7 @@ class linear_map { typedef typename std::vector::size_type size_type; public: - //Standard big 5 + ///@brief Standard big 5 constructors linear_map() = default; linear_map(const linear_map&) = default; linear_map(linear_map&&) = default; @@ -53,23 +54,52 @@ class linear_map { : vec_(num_keys, std::make_pair(sentinel(), T())) //Initialize all with sentinel values {} + ///@brief Return an iterator to the first element iterator begin() { return vec_.begin(); } + + ///@brief Return a constant iterator to the first element const_iterator begin() const { return vec_.begin(); } + + ///@brief Return an iterator to the last element iterator end() { return vec_.end(); } + + ///@brief Return a constant iterator to the last element const_iterator end() const { return vec_.end(); } + + ///@brief Return a reverse iterator to the last element reverse_iterator rbegin() { return vec_.rbegin(); } + + ///@brief Return a constant reverse iterator to the last element const_reverse_iterator rbegin() const { return vec_.rbegin(); } + + ///@brief Return a reverse iterator pointing to the theoretical element preceding the first element reverse_iterator rend() { return vec_.rend(); } + + ///@brief Return a constant reverse iterator pointing to the theoretical element preceding the first element const_reverse_iterator rend() const { return vec_.rend(); } + + ///@brief Return a const iterator to the first element const_iterator cbegin() const { return vec_.begin(); } + + ///@brief Return a const_iterator pointing to the past-the-end element in the container const_iterator cend() const { return vec_.end(); } + + ///@brief Return a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). const_reverse_iterator crbegin() const { return vec_.rbegin(); } + + ///@brief Return a const_reverse_iterator pointing to the theoretical element preceding the first element in the container (which is considered its reverse end). const_reverse_iterator crend() const { return vec_.rend(); } + ///@brief Return true if the container is empty bool empty() const { return vec_.empty(); } + + ///@brief Return the size of the container size_type size() const { return vec_.size(); } + + ///@brief Return the maximum size of the container size_type max_size() const { return vec_.max_size(); } + ///@brief [] operator mapped_type& operator[](const key_type& key) { auto iter = find(key); if (iter == end()) { @@ -80,10 +110,12 @@ class linear_map { return iter->second; } + ///@brief at() operator mapped_type& at(const key_type& key) { return const_cast(const_cast(this)->at(key)); } + ///@brief constant at() operator const mapped_type& at(const key_type& key) const { auto iter = find(key); if (iter == end()) { @@ -92,7 +124,7 @@ class linear_map { return iter->second; } - //Insert value + ///@brief Insert value std::pair insert(const value_type& value) { auto iter = find(value.first); if (iter != end()) { @@ -113,7 +145,7 @@ class linear_map { } } - //Insert range + ///@brief Insert range template void insert(InputIterator first, InputIterator last) { for (InputIterator iter = first; iter != last; ++iter) { @@ -121,7 +153,7 @@ class linear_map { } } - //Erase by key + ///@brief Erase by key void erase(const key_type& key) { auto iter = find(key); if (iter != end()) { @@ -129,23 +161,26 @@ class linear_map { } } - //Erase at iterator + ///@brief Erase at iterator void erase(const_iterator position) { iterator pos = convert_to_iterator(position); pos->first = sentinel(); //Mark invalid } - //Erase range + ///@brief Erase range void erase(const_iterator first, const_iterator last) { for (auto iter = first; iter != last; ++iter) { erase(iter); } } + ///@brief Swap two linear maps void swap(linear_map& other) { std::swap(vec_, other.vec_); } + ///@brief Clear the container void clear() { vec_.clear(); } + ///@brief Emplace template std::pair emplace(const key_type& key, Args&&... args) { auto iter = find(key); @@ -167,14 +202,19 @@ class linear_map { } } + ///@brief Requests that the underlying vector capacity be at least enough to contain n elements. void reserve(size_type n) { vec_.reserve(n); } + + ///@brief Reduces the capacity of the container to fit its size and destroys all elements beyond the capacity. void shrink_to_fit() { vec_.shrink_to_fit(); } + ///@brief Returns an iterator to the first element in the range [first,last) that compares equal to val. If no such element is found, the function returns last. iterator find(const key_type& key) { const_iterator const_iter = const_cast(this)->find(key); return convert_to_iterator(const_iter); } + ///@brief Returns a constant iterator to the first element in the range [first,last) that compares equal to val. If no such element is found, the function returns last. const_iterator find(const key_type& key) const { size_t index = size_t(key); @@ -184,40 +224,48 @@ class linear_map { return end(); } + ///@brief Returns the number of elements in the range [first,last) that compare equal to val. size_type count(const key_type& key) const { return (find(key) == end()) ? 0 : 1; } + ///@brief Returns an iterator pointing to the first element in the range [first,last) which does not compare less than val. iterator lower_bound(const key_type& key) { const_iterator const_iter = const_cast(this)->lower_bound(key); return convert_to_iterator(const_iter); } + ///@brief Returns a constant iterator pointing to the first element in the range [first,last) which does not compare less than val. const_iterator lower_bound(const key_type& key) const { return find(key); } + ///@brief Returns an iterator pointing to the first element in the range [first,last) which compares greater than val. iterator upper_bound(const key_type& key) { const_iterator const_iter = const_cast(this)->upper_bound(key); return convert_to_iterator(const_iter); } + ///@brief Returns a constant iterator pointing to the first element in the range [first,last) which compares greater than val. const_iterator upper_bound(const key_type& key) const { auto iter = find(key); return (iter != end()) ? iter + 1 : end(); } + ///@brief Returns the bounds of the subrange that includes all the elements of the range [first,last) with values equivalent to val. std::pair equal_range(const key_type& key) { auto const_iter_pair = const_cast(this)->equal_range(key); return std::pair(iterator(const_iter_pair.first), iterator(const_iter_pair.second)); } + ///@brief Returns constant bounds of the subrange that includes all the elements of the range [first,last) with values equivalent to val. std::pair equal_range(const key_type& key) const { auto lb_iter = lower_bound(key); auto ub_iter = upper_bound(key); return (lb_iter != end()) ? std::make_pair(lb_iter, ub_iter) : std::make_pair(ub_iter, ub_iter); } + ///@brief Return the size of valid elements size_type valid_size() const { size_t valid_cnt = 0; for (const auto& kv : vec_) { @@ -235,19 +283,20 @@ class linear_map { private: iterator convert_to_iterator(const_iterator const_iter) { - //This is a work around for the fact that there is no conversion between - //a const_iterator and iterator. - // - //We intiailize i to the start of the container and then advance it by - //the distance to const_iter. The resulting i points to the same element - //as const_iter - // - //Note that to be able to call std::distance with an iterator and - //const_iterator we need to specify the type as const_iterator (relying - //on the implicit conversion from iterator to const_iterator for i) - // - //Since the iterators are really vector (i.e. random-access) iterators - //both distance and advance take constant time + /* + * This is a work around for the fact that there is no conversion between a const_iterator and iterator. + * + * We intiailize i to the start of the container and then advance it by + * the distance to const_iter. The resulting i points to the same element + * as const_iter + * + * Note that to be able to call std::distance with an iterator and + * const_iterator we need to specify the type as const_iterator (relying + * on the implicit conversion from iterator to const_iterator for i) + * + * Since the iterators are really vector (i.e. random-access) iterators + * both distance and advance take constant time + */ iterator i = begin(); std::advance(i, std::distance(i, const_iter)); return i; diff --git a/libs/libvtrutil/src/vtr_list.h b/libs/libvtrutil/src/vtr_list.h index 0835d07bcb9..3f188493c5b 100644 --- a/libs/libvtrutil/src/vtr_list.h +++ b/libs/libvtrutil/src/vtr_list.h @@ -1,16 +1,24 @@ #ifndef VTR_LIST_H #define VTR_LIST_H +/** + * @file + * @brief Linked lists of void pointers and integers, respectively. + */ + namespace vtr { -/* Linked lists of void pointers and integers, respectively. */ +///@brief Lindek list node struct struct t_linked_vptr { void* data_vptr; struct t_linked_vptr* next; }; +///@brief Inserts a node to a list t_linked_vptr* insert_in_vptr_list(t_linked_vptr* head, void* vptr_to_add); + +///@brief Delete a list t_linked_vptr* delete_in_vptr_list(t_linked_vptr* head); } // namespace vtr #endif diff --git a/libs/libvtrutil/src/vtr_log.h b/libs/libvtrutil/src/vtr_log.h index a0458629aec..cb86ab2d111 100644 --- a/libs/libvtrutil/src/vtr_log.h +++ b/libs/libvtrutil/src/vtr_log.h @@ -4,16 +4,17 @@ #include #include -/* - * This header defines useful logging macros for VTR projects. +/** + * @file + * @brief This header defines useful logging macros for VTR projects. * * Message Type * ============ * * Three types of log message types are defined: - * VTR_LOG - The standard 'info' type log message - * VTR_LOG_WARN - A warning log message - * VTR_LOG_ERROR - An error log message + * - VTR_LOG : The standard 'info' type log message + * - VTR_LOG_WARN : A warning log message. This represents unusual condition that may indicate an issue but executiom continues + * - VTR_LOG_ERROR : An error log message. This represents a clear issue that will result in stopping the program execution * * For example: * @@ -39,11 +40,10 @@ * * Each of the three message types also have a VTR_LOGF_* variant, * which will cause the message to be logged for a custom file and - * line loation. * * For example: * - * VTR_LOGF("my_file.txt", 42 "This message will be logged from file 'my_file.txt' line %d\n", 42); + * VTR_LOGF("my_file.txt", "This message will be logged from file 'my_file.txt' line %d\n", 42); * * Debug Logging * ============= @@ -55,28 +55,28 @@ * is defined (disabled by default). */ -//Unconditional logging macros +// Unconditional logging macros #define VTR_LOG(...) VTR_LOGV(true, __VA_ARGS__) #define VTR_LOG_WARN(...) VTR_LOGV_WARN(true, __VA_ARGS__) #define VTR_LOG_ERROR(...) VTR_LOGV_ERROR(true, __VA_ARGS__) #define VTR_LOG_NOP(...) VTR_LOGV_NOP(true, __VA_ARGS__) -//Conditional logging macros +// Conditional logging macros #define VTR_LOGV(expr, ...) VTR_LOGVF(expr, __FILE__, __LINE__, __VA_ARGS__) #define VTR_LOGV_WARN(expr, ...) VTR_LOGVF_WARN(expr, __FILE__, __LINE__, __VA_ARGS__) #define VTR_LOGV_ERROR(expr, ...) VTR_LOGVF_ERROR(expr, __FILE__, __LINE__, __VA_ARGS__) #define VTR_LOGV_NOP(expr, ...) VTR_LOGVF_NOP(expr, __FILE__, __LINE__, __VA_ARGS__) -//Custom file-line location logging macros +// Custom file-line location logging macros #define VTR_LOGF(file, line, ...) VTR_LOGVF(true, file, line, __VA_ARGS__) #define VTR_LOGF_WARN(file, line, ...) VTR_LOGVF_WARN(true, file, line, __VA_ARGS__) #define VTR_LOGF_ERROR(file, line, ...) VTR_LOGVF_ERROR(true, file, line, __VA_ARGS__) #define VTR_LOGF_NOP(file, line, ...) VTR_LOGVF_NOP(true, file, line, __VA_ARGS__) -//Custom file-line-func location logging macros +// Custom file-line-func location logging macros #define VTR_LOGFF_WARN(file, line, func, ...) VTR_LOGVFF_WARN(true, file, line, func, __VA_ARGS__) -//Conditional logging and custom file-line location macros +// Conditional logging and custom file-line location macros #define VTR_LOGVF(expr, file, line, ...) \ do { \ if (expr) vtr::printf(__VA_ARGS__); \ @@ -98,14 +98,16 @@ if (expr) print_or_suppress_warning(file, line, func, __VA_ARGS__); \ } while (false) -//No-op version of logging macro which avoids unused parameter warnings. -// -//Note that to avoid unused parameter warnings we call sizeof() and cast -//the result to void. sizeof is evaluated at compile time so there is no -//run-time overhead. -// -//Also note the use of std::make_tuple to ensure all arguments in VA_ARGS -//are used. +/* + * No-op version of logging macro which avoids unused parameter warnings. + * + * Note that to avoid unused parameter warnings we call sizeof() and cast + * the result to void. sizeof is evaluated at compile time so there is no + * run-time overhead. + * + * Also note the use of std::make_tuple to ensure all arguments in VA_ARGS + * are used. + */ #define VTR_LOGVF_NOP(expr, file, line, ...) \ do { \ static_cast(sizeof(expr)); \ @@ -114,7 +116,7 @@ static_cast(sizeof(std::make_tuple(__VA_ARGS__))); \ } while (false) -//Debug logging macros +// Debug logging macros #ifdef VTR_ENABLE_DEBUG_LOGGING //Enable # define VTR_LOG_DEBUG(...) VTR_LOG(__VA_ARGS__) # define VTR_LOGV_DEBUG(expr, ...) VTR_LOGV(expr, __VA_ARGS__) @@ -140,20 +142,26 @@ void set_log_file(const char* filename); } // namespace vtr -// The following data structure and functions allow to suppress noisy warnings -// and direct them into an external file, if specified. static std::unordered_set warnings_to_suppress; static std::string noisy_warn_log_file; +/** + * @brief The following data structure and functions allow to suppress noisy warnings and direct them into an external file, if specified. + */ void add_warnings_to_suppress(std::string function_name); -// This function creates a new log file to hold the suppressed warnings. -// If the file already exists, it is cleared out first. +/** + * @brief This function creates a new log file to hold the suppressed warnings. If the file already exists, it is cleared out first. + */ void set_noisy_warn_log_file(std::string log_file_name); -// This function checks whether the function from which the warning has been called -// is in the set of warnings_to_suppress. If so, the warning is printed on the -// noisy_warn_log_file, otherwise it is printed on stdout (or the regular log file) +/** + * @brief This function checks whether to print or to suppress warning + * + * This function checks whether the function from which the warning has been called + * is in the set of warnings_to_suppress. If so, the warning is printed on the + * noisy_warn_log_file, otherwise it is printed on stdout (or the regular log file) + */ void print_or_suppress_warning(const char* pszFileName, unsigned int lineNum, const char* pszFuncName, const char* pszMessage, ...); #endif diff --git a/libs/libvtrutil/src/vtr_logic.h b/libs/libvtrutil/src/vtr_logic.h index 9a6765f7494..30d44c4a6b9 100644 --- a/libs/libvtrutil/src/vtr_logic.h +++ b/libs/libvtrutil/src/vtr_logic.h @@ -18,6 +18,9 @@ constexpr int TRUE = 1; namespace vtr { +/** + * @brief This class represents the different supported logic values + */ enum class LogicValue { FALSE = 0, TRUE = 1, diff --git a/libs/libvtrutil/src/vtr_map_util.h b/libs/libvtrutil/src/vtr_map_util.h index 4b0a7883044..fd1cdd4f88e 100644 --- a/libs/libvtrutil/src/vtr_map_util.h +++ b/libs/libvtrutil/src/vtr_map_util.h @@ -6,35 +6,35 @@ namespace vtr { -//An iterator who wraps a std::map iterator to return it's key +///@brief An iterator who wraps a std::map iterator to return it's key template using map_key_iter = pair_first_iter; -//An iterator who wraps a std::map iterator to return it's value +///@brief An iterator who wraps a std::map iterator to return it's value template using map_value_iter = pair_second_iter; -//Returns a range iterating over a std::map's keys +///@brief Returns a range iterating over a std::map's keys template auto make_key_range(T b, T e) { using key_iter = map_key_iter; return vtr::make_range(key_iter(b), key_iter(e)); } -//Returns a range iterating over a std::map's keys +///@brief Returns a range iterating over a std::map's keys template auto make_key_range(const Container& c) { return make_key_range(std::begin(c), std::end(c)); } -//Returns a range iterating over a std::map's values +///@brief Returns a range iterating over a std::map's values template auto make_value_range(T b, T e) { using value_iter = map_value_iter; return vtr::make_range(value_iter(b), value_iter(e)); } -//Returns a range iterating over a std::map's values +///@brief Returns a range iterating over a std::map's values template auto make_value_range(const Container& c) { return make_value_range(std::begin(c), std::end(c)); diff --git a/libs/libvtrutil/src/vtr_math.cpp b/libs/libvtrutil/src/vtr_math.cpp index 17536eac688..32594753c4c 100644 --- a/libs/libvtrutil/src/vtr_math.cpp +++ b/libs/libvtrutil/src/vtr_math.cpp @@ -7,6 +7,7 @@ namespace vtr { +///@brief Calculates the value pow(base, exp) int ipow(int base, int exp) { int result = 1; @@ -34,11 +35,15 @@ float median(std::vector vector) { return (float)vector[size / 2]; } -/* Performs linear interpolation or extrapolation on the set of (x,y) values specified by the xy_map. +/** + * @brief Linear interpolation/Extrapolation + * + * Performs linear interpolation or extrapolation on the set of (x,y) values specified by the xy_map. * A requested x value is passed in, and we return the interpolated/extrapolated y value at this requested value of x. * Meant for maps where both key and element are numbers. * This is specifically enforced by the explicit instantiations below this function. i.e. only templates - * using those types listed in the explicit instantiations below are allowed */ + * using those types listed in the explicit instantiations below are allowed + */ template Y linear_interpolate_or_extrapolate(const std::map* xy_map, X requested_x) { Y result; diff --git a/libs/libvtrutil/src/vtr_math.h b/libs/libvtrutil/src/vtr_math.h index a8d6f524c99..74b4ccebf58 100644 --- a/libs/libvtrutil/src/vtr_math.h +++ b/libs/libvtrutil/src/vtr_math.h @@ -7,19 +7,29 @@ #include "vtr_assert.h" +/** + * @file + * + * @brief This file defines some math operations + */ + namespace vtr { /*********************** Math operations *************************************/ + +///@brief Calculates the value pow(base, exp) int ipow(int base, int exp); -//Returns the median of an input vector. +///@brief Returns the median of an input vector. float median(std::vector vector); +///@brief Linear interpolation/Extrapolation template Y linear_interpolate_or_extrapolate(const std::map* xy_map, X requested_x); +///@brief Integer rounding conversion for floats constexpr int nint(float val) { return static_cast(val + 0.5); } -//Returns a 'safe' ratio which evaluates to zero if the denominator is zero +///@brief Returns a 'safe' ratio which evaluates to zero if the denominator is zero template T safe_ratio(T numerator, T denominator) { if (denominator == T(0)) { @@ -28,6 +38,7 @@ T safe_ratio(T numerator, T denominator) { return numerator / denominator; } +///@brief Returns the median of the elements in range [first, last] template double median(InputIterator first, InputIterator last) { auto len = std::distance(first, last); @@ -40,23 +51,25 @@ double median(InputIterator first, InputIterator last) { } } +///@brief Returns the median of a whole container template double median(Container c) { return median(std::begin(c), std::end(c)); } +/** + * @brief Returns the geometric mean of the elments in range [first, last) + * + * To avoid potential round-off issues we transform the standard formula: + * + * geomean = ( v_1 * v_2 * ... * v_n) ^ (1/n) + * + * by taking the log: + * + * geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n))) + */ template double geomean(InputIterator first, InputIterator last, double init = 1.) { - //Compute the geometric mean of the elments in range [first, last) - // - //To avoid potential round-off issues we transform the standard formula: - // - // geomean = ( v_1 * v_2 * ... * v_n) ^ (1/n) - // - //by taking the log: - // - // geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n))) - double log_sum = std::log(init); size_t n = 0; for (auto iter = first; iter != last; ++iter) { @@ -71,11 +84,13 @@ double geomean(InputIterator first, InputIterator last, double init = 1.) { } } +///@brief Returns the geometric mean of a whole container template double geomean(Container c) { return geomean(std::begin(c), std::end(c)); } +///@brief Returns the arithmatic mean of the elements in range [first, last] template double arithmean(InputIterator first, InputIterator last, double init = 0.) { double sum = init; @@ -92,25 +107,32 @@ double arithmean(InputIterator first, InputIterator last, double init = 0.) { } } +///@brief Returns the aritmatic mean of a whole container template double arithmean(Container c) { return arithmean(std::begin(c), std::end(c)); } -//Return the greatest common divisor of x and y -// Note that T should be an integral type +/** + * @brief Returns the greatest common divisor of x and y + * + * Note that T should be an integral type + */ template static T gcd(T x, T y) { static_assert(std::is_integral::value, "T must be integral"); - //Euclidean algorithm + // Euclidean algorithm if (y == 0) { return x; } return gcd(y, x % y); } -//Return the least common multiple of x and y -// Note that T should be an integral type +/** + * @brief Return the least common multiple of x and y + * + * Note that T should be an integral type + */ template T lcm(T x, T y) { static_assert(std::is_integral::value, "T must be integral"); @@ -125,6 +147,7 @@ T lcm(T x, T y) { constexpr double DEFAULT_REL_TOL = 1e-9; constexpr double DEFAULT_ABS_TOL = 0; +///@brief Return true if a and b values are close to each other template bool isclose(T a, T b, T rel_tol, T abs_tol) { if (std::isinf(a) && std::isinf(b)) return (std::signbit(a) == std::signbit(b)); @@ -134,6 +157,7 @@ bool isclose(T a, T b, T rel_tol, T abs_tol) { return std::abs(a - b) <= std::max(rel_tol * abs_largest, abs_tol); } +///@brief Return true if a and b values are close to each other (using the default tolerances) template bool isclose(T a, T b) { return isclose(a, b, DEFAULT_REL_TOL, DEFAULT_ABS_TOL); diff --git a/libs/libvtrutil/src/vtr_memory.h b/libs/libvtrutil/src/vtr_memory.h index a4e67bbf765..316e7b5d984 100644 --- a/libs/libvtrutil/src/vtr_memory.h +++ b/libs/libvtrutil/src/vtr_memory.h @@ -11,32 +11,37 @@ namespace vtr { -//For efficiency, STL containers usually don't -//release their actual heap-allocated memory until -//destruction (even if Container::clear() is called). -// -//This function will force the container to be cleared -//and release it's held memory. +/** + * @brief This function will force the container to be cleared + * + * It release it's held memory. + * For efficiency, STL containers usually don't + * release their actual heap-allocated memory until + * destruction (even if Container::clear() is called). + */ template void release_memory(Container& container) { - //Force a re-allocation to happen by - //swapping in a new (empty) container. + ///@brief Force a re-allocation to happen by swapping in a new (empty) container. Container().swap(container); } struct t_linked_vptr; //Forward declaration -/* This structure is to keep track of chunks of memory that is being * - * allocated to save overhead when allocating very small memory pieces. * - * For a complete description, please see the comment in chunk_malloc*/ +/** + * This structure keeps track to chenks of memory + * + * This structure is to keep track of chunks of memory that is being + * allocated to save overhead when allocating very small memory pieces. + * For a complete description, please see the comment in chunk_malloc + */ struct t_chunk { t_linked_vptr* chunk_ptr_head = nullptr; - /* chunk_ptr_head->data_vptr: head of the entire linked - * list of allocated "chunk" memory; - * chunk_ptr_head->next: pointer to the next chunk on the linked list*/ - int mem_avail = 0; /* number of bytes left in the current chunk */ - char* next_mem_loc_ptr = nullptr; /* pointer to the first available (free) * - * byte in the current chunk */ + + //chunk_ptr_head->data_vptr: head of the entire linked + //list of allocated "chunk" memory; + //chunk_ptr_head->next: pointer to the next chunk on the linked list + int mem_avail = 0; ///< number of bytes left in the current chunk + char* next_mem_loc_ptr = nullptr; ///< pointer to the first available (free) byte in the current chunk }; void* free(void* some); @@ -47,7 +52,7 @@ void* realloc(void* ptr, size_t size); void* chunk_malloc(size_t size, t_chunk* chunk_info); void free_chunk_memory(t_chunk* chunk_info); -//Like chunk_malloc, but with proper C++ object initialization +///@brief Like chunk_malloc, but with proper C++ object initialization template T* chunk_new(t_chunk* chunk_info) { void* block = chunk_malloc(sizeof(T), chunk_info); @@ -55,17 +60,20 @@ T* chunk_new(t_chunk* chunk_info) { return new (block) T(); //Placement new } -//Call the destructor of an obj which must have been allocated in the specified chunk +///@brief Call the destructor of an obj which must have been allocated in the specified chunk template void chunk_delete(T* obj, t_chunk* /*chunk_info*/) { if (obj) { - obj->~T(); //Manually call destructor - //Currently we don't mark the unused memory as free + obj->~T(); // Manually call destructor + // Currently we don't mark the unused memory as free } } -//Cross platform wrapper around GNU's malloc_trim() -// TODO: This is only used in one place within VPR, consider removing it +/** + * @brief Cross platform wrapper around GNU's malloc_trim() + * + * TODO: This is only used in one place within VPR, consider removing it + */ int malloc_trim(size_t pad); inline int memalign(void** ptr_out, size_t align, size_t size) { @@ -82,21 +90,24 @@ inline int memalign(void** ptr_out, size_t align, size_t size) { #endif } -// This is a macro because it has to be. rw and locality must be constants, -// not just constexpr. -// -// This generates a prefetch instruction on all architectures that include it. -// This is all modern x86 and ARM64 platforms. -// -// rw = 0, locality = 0 is the least intrusive software prefetch. Higher -// locality results in more CPU effort, and needs evidence for higher locality. +/** + * @brief A macro generates a prefetch instruction on all architectures that include it. + * + * This is all modern x86 and ARM64 platforms. + * + * This is a macro because it has to be. rw and locality must be constants, + * not just constexpr. + */ #define VTR_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality) -// aligned_allocator is a STL allocator that allocates memory in an aligned -// fashion (if supported by the platform). -// -// It is worth noting the C++20 std::allocator does aligned allocations, but -// C++20 has poor support. +/** + * @brief aligned_allocator is a STL allocator that allocates memory in an aligned fashion + * + * works if supported by the platform + * + * It is worth noting the C++20 std::allocator does aligned allocations, but + * C++20 has poor support. + */ template struct aligned_allocator { using value_type = T; diff --git a/libs/libvtrutil/src/vtr_ndmatrix.h b/libs/libvtrutil/src/vtr_ndmatrix.h index 58e4ac2dfc9..b2a27f80068 100644 --- a/libs/libvtrutil/src/vtr_ndmatrix.h +++ b/libs/libvtrutil/src/vtr_ndmatrix.h @@ -7,27 +7,32 @@ namespace vtr { -//Proxy class for a sub-matrix of a NdMatrix class. -//This is used to allow chaining of array indexing [] operators in a natural way. -// -//Each instance of this class peels off one-dimension and returns a NdMatrixProxy representing -//the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case. -// -//Since this expansion happens at compiler time all the proxy classes get optimized away, -//yielding both high performance and generality. -// -//Recursive case: N-dimensional array +/** + * @brief Proxy class for a sub-matrix of a NdMatrix class. + * + * This is used to allow chaining of array indexing [] operators in a natural way. + * + * Each instance of this class peels off one-dimension and returns a NdMatrixProxy representing + * the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case. + * + * Since this expansion happens at compiler time all the proxy classes get optimized away, + * yielding both high performance and generality. + * + * Recursive case: N-dimensional array + */ template class NdMatrixProxy { public: static_assert(N > 0, "Must have at least one dimension"); - //Construct a matrix proxy object - // - // dim_sizes: Array of dimension sizes - // idim: The dimension associated with this proxy - // dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) - // start: Pointer to the start of the sub-matrix this proxy represents + /** + * @brief Construct a matrix proxy object + * + * @param dim_sizes: Array of dimension sizes + * @param idim: The dimension associated with this proxy + * @param dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) + * @param start: Pointer to the start of the sub-matrix this proxy represents + */ NdMatrixProxy(const size_t* dim_sizes, const size_t* dim_strides, T* start) : dim_sizes_(dim_sizes) , dim_strides_(dim_strides) @@ -35,19 +40,21 @@ class NdMatrixProxy { NdMatrixProxy& operator=(const NdMatrixProxy& other) = delete; + ///@brief const [] operator const NdMatrixProxy operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(index < dim_sizes_[0], "Index out of range (above dimension maximum)"); VTR_ASSERT_SAFE_MSG(dim_sizes_[1] > 0, "Can not index into zero-sized dimension"); - //Strip off one dimension + // Strip off one dimension return NdMatrixProxy( - dim_sizes_ + 1, //Pass the dimension information - dim_strides_ + 1, //Pass the stride for the next dimension - start_ + dim_strides_[0] * index); //Advance to index in this dimension + dim_sizes_ + 1, // Pass the dimension information + dim_strides_ + 1, // Pass the stride for the next dimension + start_ + dim_strides_[0] * index); // Advance to index in this dimension } + ///@brief [] operator NdMatrixProxy operator[](size_t index) { - //Call the const version and cast-away constness + // Call the const version and cast-away constness return const_cast*>(this)->operator[](index); } @@ -57,10 +64,17 @@ class NdMatrixProxy { T* start_; }; -//Base case: 1-dimensional array +///@brief Base case: 1-dimensional array template class NdMatrixProxy { public: + /** + * @brief Construct a 1-d matrix proxy object + * + * @param dim_sizes: Array of dimension sizes + * @param dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) + * @param start: Pointer to the start of the sub-matrix this proxy represents + */ NdMatrixProxy(const size_t* dim_sizes, const size_t* dim_stride, T* start) : dim_sizes_(dim_sizes) , dim_strides_(dim_stride) @@ -68,6 +82,7 @@ class NdMatrixProxy { NdMatrixProxy& operator=(const NdMatrixProxy& other) = delete; + ///@brief const [] operator const T& operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(dim_strides_[0] == 1, "Final dimension must have stride 1"); VTR_ASSERT_SAFE_MSG(index < dim_sizes_[0], "Index out of range (above dimension maximum)"); @@ -76,22 +91,28 @@ class NdMatrixProxy { return start_[index]; } + ///@brief [] operator T& operator[](size_t index) { - //Call the const version and cast-away constness + // Call the const version and cast-away constness return const_cast(const_cast*>(this)->operator[](index)); } - //For legacy compatibility (i.e. code expecting a pointer) we allow this base dimension - //case to retrieve a raw pointer to the last dimension elements. - // - //Note that it is the caller's responsibility to use this correctly; care must be taken - //not to clobber elements in other dimensions + /** + * @brief Backward compitability + * + * For legacy compatibility (i.e. code expecting a pointer) we allow this base dimension + * case to retrieve a raw pointer to the last dimension elements. + * + * Note that it is the caller's responsibility to use this correctly; care must be taken + * not to clobber elements in other dimensions + */ const T* data() const { return start_; } + ///@brief same as above but allow update the value T* data() { - //Call the const version and cast-away constness + // Call the const version and cast-away constness return const_cast(const_cast*>(this)->data()); } @@ -101,100 +122,110 @@ class NdMatrixProxy { T* start_; }; -//Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension. -//This class implements all of the matrix handling (lifetime etc.) except for indexing -//(which is implemented in the NdMatrix class). Indexing is split out to allows specialization -//of indexing for N = 1. -// -//Implementation: -// -//This class uses a single linear array to store the matrix in c-style (row major) -//order. That is, the right-most index is laid out contiguous memory. -// -//This should improve memory usage (no extra pointers to store for each dimension), -//and cache locality (less indirection via pointers, predictable strides). -// -//The indicies are calculated based on the dimensions to access the appropriate elements. -//Since the indexing calculations are visible to the compiler at compile time they can be -//optimized to be efficient. +/** + * @brief Base class for an N-dimensional matrix + * + * Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension. + * This class implements all of the matrix handling (lifetime etc.) except for indexing + * (which is implemented in the NdMatrix class). Indexing is split out to allows specialization + * (of indexing for N = 1. + * + * Implementation: + * + * This class uses a single linear array to store the matrix in c-style (row major) + * order. That is, the right-most index is laid out contiguous memory. + * + * This should improve memory usage (no extra pointers to store for each dimension), + * and cache locality (less indirection via pointers, predictable strides). + * + * The indicies are calculated based on the dimensions to access the appropriate elements. + * Since the indexing calculations are visible to the compiler at compile time they can be + * optimized to be efficient. + */ template class NdMatrixBase { public: static_assert(N >= 1, "Minimum dimension 1"); - //An empty matrix (all dimensions size zero) + ///@brief An empty matrix (all dimensions size zero) NdMatrixBase() { clear(); } - //Specified dimension sizes: - // [0..dim_sizes[0]) - // [0..dim_sizes[1]) - // ... - //with optional fill value + /** + * @brief Specified dimension sizes: + * + * [0..dim_sizes[0]) + * [0..dim_sizes[1]) + * ... + * with optional fill value + */ NdMatrixBase(std::array dim_sizes, T value = T()) { resize(dim_sizes, value); } public: //Accessors - //Returns the size of the matrix (number of elements) + ///@brief Returns the size of the matrix (number of elements) size_t size() const { VTR_ASSERT_DEBUG_MSG(calc_size() == size_, "Calculated and current matrix size must be consistent"); return size_; } - //Returns true if there are no elements in the matrix + ///@brief Returns true if there are no elements in the matrix bool empty() const { return size() == 0; } - //Returns the number of dimensions (i.e. N) + ///@brief Returns the number of dimensions (i.e. N) size_t ndims() const { return dim_sizes_.size(); } - //Returns the size of the ith dimension + ///@brief Returns the size of the ith dimension size_t dim_size(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); return dim_sizes_[i]; } - //Returns the starting index of ith dimension + ///@brief Returns the starting index of ith dimension size_t begin_index(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); return 0; } - //Returns the one-past-the-end index of the ith dimension + ///@brief Returns the one-past-the-end index of the ith dimension size_t end_index(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); return dim_sizes_[i]; } - // Flat accessors of NdMatrix + ///@brief const Flat accessors of NdMatrix const T& get(size_t i) const { VTR_ASSERT_SAFE(i < size_); return data_[i]; } + ///@brief Flat accessors of NdMatrix T& get(size_t i) { VTR_ASSERT_SAFE(i < size_); return data_[i]; } public: //Mutators - //Set all elements to 'value' + ///@brief Set all elements to 'value' void fill(T value) { std::fill(data_.get(), data_.get() + size(), value); } - //Resize the matrix to the specified dimension ranges - // - //If 'value' is specified all elements will be initialized to it, - //otherwise they will be default constructed. + /** + * @brief Resize the matrix to the specified dimension ranges + * + * If 'value' is specified all elements will be initialized to it, + * otherwise they will be default constructed. + */ void resize(std::array dim_sizes, T value = T()) { dim_sizes_ = dim_sizes; size_ = calc_size(); @@ -210,7 +241,7 @@ class NdMatrixBase { } } - //Reset the matrix to size zero + ///@brief Reset the matrix to size zero void clear() { data_.reset(nullptr); dim_sizes_.fill(0); @@ -219,27 +250,29 @@ class NdMatrixBase { } public: //Lifetime management - //Copy constructor + ///@brief Copy constructor NdMatrixBase(const NdMatrixBase& other) : NdMatrixBase(other.dim_sizes_) { std::copy(other.data_.get(), other.data_.get() + other.size(), data_.get()); } - //Move constructor + ///@brief Move constructor NdMatrixBase(NdMatrixBase&& other) : NdMatrixBase() { swap(*this, other); } - //Copy/move assignment - // - //Note that rhs is taken by value (copy-swap idiom) + /** + * @brief Copy/move assignment + * + * Note that rhs is taken by value (copy-swap idiom) + */ NdMatrixBase& operator=(NdMatrixBase rhs) { swap(*this, rhs); return *this; } - //Swap two NdMatrixBase objects + ///@brief Swap two NdMatrixBase objects friend void swap(NdMatrixBase& m1, NdMatrixBase& m2) { using std::swap; swap(m1.size_, m2.size_); @@ -249,15 +282,14 @@ class NdMatrixBase { } private: - //Allocate space for all the elements + ///@brief Allocate space for all the elements void alloc() { data_ = std::make_unique(size()); } - //Returns the size of the matrix (number of elements) calucated - //from the current dimensions + ///@brief Returns the size of the matrix (number of elements) calucated from the current dimensions size_t calc_size() const { - //Size is the product of all dimension sizes + ///@brief Size is the product of all dimension sizes size_t cnt = dim_size(0); for (size_t idim = 1; idim < ndims(); ++idim) { cnt *= dim_size(idim); @@ -272,78 +304,87 @@ class NdMatrixBase { std::unique_ptr data_ = nullptr; }; -//An N-dimensional matrix supporting arbitrary (continuous) index ranges -//per dimension. -// -//Examples: -// -// //A 2-dimensional matrix with indicies [0..4][0..9] -// NdMatrix m1({5,10}); -// -// //Accessing an element -// int i = m1[3][5]; -// -// //Setting an element -// m1[2][8] = 0; -// -// //A 3-dimensional matrix with indicies [0..4][0..9][0..19] -// NdMatrix m2({5,10,20}); -// -// //A 2-dimensional matrix with indicies [0..4][0..9], with all entries -// //initialized to 42 -// NdMatrix m3({5,10}, 42); -// -// //Filling all entries with value 101 -// m3.fill(101); -// -// //Resizing an existing matrix (all values reset to default constucted value) -// m3.resize({5,5}) -// -// //Resizing an existing matrix (all elements set to value 88) -// m3.resize({15,55}, 88) +/** + * @brief An N-dimensional matrix supporting arbitrary (continuous) index ranges per dimension. + * + * Examples: + * + * //A 2-dimensional matrix with indicies [0..4][0..9] + * NdMatrix m1({5,10}); + * + * //Accessing an element + * int i = m1[3][5]; + * + * //Setting an element + * m1[2][8] = 0; + * + * //A 3-dimensional matrix with indicies [0..4][0..9][0..19] + * NdMatrix m2({5,10,20}); + * + * //A 2-dimensional matrix with indicies [0..4][0..9], with all entries + * //initialized to 42 + * NdMatrix m3({5,10}, 42); + * + * //Filling all entries with value 101 + * m3.fill(101); + * + * //Resizing an existing matrix (all values reset to default constucted value) + * m3.resize({5,5}) + * + * //Resizing an existing matrix (all elements set to value 88) + * m3.resize({15,55}, 88) + */ template class NdMatrix : public NdMatrixBase { //General case static_assert(N >= 2, "Minimum dimension 2"); public: - //Use the base constructors + ///@brief Use the base constructors using NdMatrixBase::NdMatrixBase; public: - //Access an element - // - //Returns a proxy-object to allow chained array-style indexing (N >= 2 case) + /** + * @brief Access an element + * + * Returns a proxy-object to allow chained array-style indexing (N >= 2 case) + */ const NdMatrixProxy operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(this->dim_size(1) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(index < this->dim_sizes_[0], "Index out of range (above dimension maximum)"); - //Peel off the first dimension + // Peel off the first dimension return NdMatrixProxy( this->dim_sizes_.data() + 1, //Pass the dimension information this->dim_strides_.data() + 1, //Pass the stride for the next dimension this->data_.get() + this->dim_strides_[0] * index); //Advance to index in this dimension } - //Access an element - // - //Returns a proxy-object to allow chained array-style indexing + /** + * @brief Access an element + * + * Returns a proxy-object to allow chained array-style indexing + */ NdMatrixProxy operator[](size_t index) { //Call the const version, since returned by value don't need to worry about const return const_cast*>(this)->operator[](index); } }; +/** + * @brief A 1-dimensional matrix supporting arbitrary (continuous) index ranges per dimension. + * + * This is considered a specialization for N=1 + */ template class NdMatrix : public NdMatrixBase { - //Specialization for N = 1 public: - //Use the base constructors + ///@brief Use the base constructors using NdMatrixBase::NdMatrixBase; public: - //Access an element (immutable) + ///@brief Access an element (immutable) const T& operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(index >= 0, "Index out of range (below dimension minimum)"); @@ -352,14 +393,14 @@ class NdMatrix : public NdMatrixBase { return this->data_[index]; } - //Access an element (mutable) + ///@brief Access an element (mutable) T& operator[](size_t index) { //Call the const version, and cast away const-ness return const_cast(const_cast*>(this)->operator[](index)); } }; -//Convenient short forms for common NdMatricies +///@brief Convenient short forms for common NdMatricies template using Matrix = NdMatrix; diff --git a/libs/libvtrutil/src/vtr_ndoffsetmatrix.h b/libs/libvtrutil/src/vtr_ndoffsetmatrix.h index ec9652b165a..c4255303866 100644 --- a/libs/libvtrutil/src/vtr_ndoffsetmatrix.h +++ b/libs/libvtrutil/src/vtr_ndoffsetmatrix.h @@ -7,18 +7,28 @@ namespace vtr { -//A half-open range specification for a matrix dimension [begin_index, last_index), -//with valid indicies from [begin_index() ... end_index()-1], provided size() > 0. +/** + * @brief A half-open range specification for a matrix dimension [begin_index, last_index) + * + * It comes with valid indicies from [begin_index() ... end_index()-1], provided size() > 0. + */ class DimRange { public: + ///@brief default constructor DimRange() = default; + + ///@brief a constructor with begin_index, end_index DimRange(size_t begin, size_t end) : begin_index_(begin) , end_index_(end) {} + ///@brief Return the begin index size_t begin_index() const { return begin_index_; } + + ///@brief Return the end index size_t end_index() const { return end_index_; } + ///@brief Return the size size_t size() const { return end_index_ - begin_index_; } private: @@ -26,39 +36,49 @@ class DimRange { size_t end_index_ = 0; }; -//Proxy class for a sub-matrix of a NdOffsetMatrix class. -//This is used to allow chaining of array indexing [] operators in a natural way. -// -//Each instance of this class peels off one-dimension and returns a NdOffsetMatrixProxy representing -//the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case. -// -//Since this expansion happens at compiler time all the proxy classes get optimized away, -//yielding both high performance and generality. -// -//Recursive case: N-dimensional array +/** + * @brief Proxy class for a sub-matrix of a NdOffsetMatrix class. + * + * This is used to allow chaining of array indexing [] operators in a natural way. + * + * Each instance of this class peels off one-dimension and returns a NdOffsetMatrixProxy representing + * the resulting sub-matrix. This is repeated recursively until we hit the 1-dimensional base-case. + * + * Since this expansion happens at compiler time all the proxy classes get optimized away, + * yielding both high performance and generality. + * + * Recursive case: N-dimensional array + */ template class NdOffsetMatrixProxy { public: static_assert(N > 0, "Must have at least one dimension"); - //Construct a matrix proxy object - // - // dim_ranges: Array of DimRange objects - // idim: The dimension associated with this proxy - // dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) - // start: Pointer to the start of the sub-matrix this proxy represents + /** + * @brief Construct a matrix proxy object + * + * dim_ranges: Array of DimRange objects + * idim: The dimension associated with this proxy + * dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) + * start: Pointer to the start of the sub-matrix this proxy represents + */ NdOffsetMatrixProxy(const DimRange* dim_ranges, size_t idim, size_t dim_stride, T* start) : dim_ranges_(dim_ranges) , idim_(idim) , dim_stride_(dim_stride) , start_(start) {} + ///@brief const [] operator const NdOffsetMatrixProxy operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(index >= dim_ranges_[idim_].begin_index(), "Index out of range (below dimension minimum)"); VTR_ASSERT_SAFE_MSG(index < dim_ranges_[idim_].end_index(), "Index out of range (above dimension maximum)"); - //The elements are stored in zero-indexed form, so we need to adjust - //for any non-zero minimum index + /* + * Calculate the effective index + * + * The elements are stored in zero-indexed form, so we need to adjust + * for any non-zero minimum index + */ size_t effective_index = index - dim_ranges_[idim_].begin_index(); //Determine the stride of the next dimension @@ -71,6 +91,7 @@ class NdOffsetMatrixProxy { start_ + dim_stride_ * effective_index); //Advance to index in this dimension } + ///@brief [] operator NdOffsetMatrixProxy operator[](size_t index) { //Call the const version and cast-away constness return const_cast*>(this)->operator[](index); @@ -83,16 +104,24 @@ class NdOffsetMatrixProxy { T* start_; }; -//Base case: 1-dimensional array +///@brief Base case: 1-dimensional array template class NdOffsetMatrixProxy { public: + /** + * @brief Construct a matrix proxy object + * + * - dim_ranges: Array of DimRange objects + * - dim_stride: The stride of this dimension (i.e. how many element in memory between indicies of this dimension) + * - start: Pointer to the start of the sub-matrix this proxy represents + */ NdOffsetMatrixProxy(const DimRange* dim_ranges, size_t idim, size_t dim_stride, T* start) : dim_ranges_(dim_ranges) , idim_(idim) , dim_stride_(dim_stride) , start_(start) {} + ///@brief const [] operator const T& operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(dim_stride_ == 1, "Final dimension must have stride 1"); VTR_ASSERT_SAFE_MSG(index >= dim_ranges_[idim_].begin_index(), "Index out of range (below dimension minimum)"); @@ -106,6 +135,7 @@ class NdOffsetMatrixProxy { return start_[effective_index]; } + ///@brief [] operator T& operator[](size_t index) { //Call the const version and cast-away constness return const_cast(const_cast*>(this)->operator[](index)); @@ -118,54 +148,63 @@ class NdOffsetMatrixProxy { T* start_; }; -//Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension. -//This class implements all of the matrix handling (lifetime etc.) except for indexing -//(which is implemented in the NdOffsetMatrix class). Indexing is split out to allows specialization -//of indexing for N = 1. -// -//Implementation: -// -//This class uses a single linear array to store the matrix in c-style (row major) -//order. That is, the right-most index is laid out contiguous memory. -// -//This should improve memory usage (no extra pointers to store for each dimension), -//and cache locality (less indirection via pointers, predictable strides). -// -//The indicies are calculated based on the dimensions to access the appropriate elements. -//Since the indexing calculations are visible to the compiler at compile time they can be -//optimized to be efficient. +/** + * @brief Base class for an N-dimensional matrix supporting arbitrary index ranges per dimension. + * + * This class implements all of the matrix handling (lifetime etc.) except for indexing + * (which is implemented in the NdOffsetMatrix class). Indexing is split out to allows specialization + * of indexing for N = 1. + * + * Implementation: + * + * This class uses a single linear array to store the matrix in c-style (row major) + * order. That is, the right-most index is laid out contiguous memory. + * + * This should improve memory usage (no extra pointers to store for each dimension), + * and cache locality (less indirection via pointers, predictable strides). + * + * The indicies are calculated based on the dimensions to access the appropriate elements. + * Since the indexing calculations are visible to the compiler at compile time they can be + * optimized to be efficient. + */ template class NdOffsetMatrixBase { public: static_assert(N >= 1, "Minimum dimension 1"); - //An empty matrix (all dimensions size zero) + ///@brief An empty matrix (all dimensions size zero) NdOffsetMatrixBase() { clear(); } - //Specified dimension sizes: - // [0..dim_sizes[0]) - // [0..dim_sizes[1]) - // ... - //with optional fill value + /** + * @brief Specified dimension sizes: + * + * [0..dim_sizes[0]) + * [0..dim_sizes[1]) + * ... + * with optional fill value + */ NdOffsetMatrixBase(std::array dim_sizes, T value = T()) { resize(dim_sizes, value); } - //Specified dimension index ranges: - // [dim_ranges[0].begin_index() ... dim_ranges[1].end_index()) - // [dim_ranges[1].begin_index() ... dim_ranges[1].end_index()) - // ... - //with optional fill value + /** + * @brief Specified dimension index ranges: + * + * [dim_ranges[0].begin_index() ... dim_ranges[1].end_index()) + * [dim_ranges[1].begin_index() ... dim_ranges[1].end_index()) + * ... + * with optional fill value + */ NdOffsetMatrixBase(std::array dim_ranges, T value = T()) { resize(dim_ranges, value); } public: //Accessors - //Returns the size of the matrix (number of elements) + ///@brief Returns the size of the matrix (number of elements) size_t size() const { - //Size is the product of all dimension sizes + ///@brief Size is the product of all dimension sizes size_t cnt = dim_size(0); for (size_t idim = 1; idim < ndims(); ++idim) { cnt *= dim_size(idim); @@ -173,31 +212,31 @@ class NdOffsetMatrixBase { return cnt; } - //Returns true if there are no elements in the matrix + ///@brief Returns true if there are no elements in the matrix bool empty() const { return size() == 0; } - //Returns the number of dimensions (i.e. N) + ///@brief Returns the number of dimensions (i.e. N) size_t ndims() const { return dim_ranges_.size(); } - //Returns the size of the ith dimension + ///@brief Returns the size of the ith dimension size_t dim_size(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); return dim_ranges_[i].size(); } - //Returns the starting index of ith dimension + ///@brief Returns the starting index of ith dimension size_t begin_index(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); return dim_ranges_[i].begin_index(); } - //Returns the one-past-the-end index of the ith dimension + ///@brief Returns the one-past-the-end index of the ith dimension size_t end_index(size_t i) const { VTR_ASSERT_SAFE(i < ndims()); @@ -205,15 +244,17 @@ class NdOffsetMatrixBase { } public: //Mutators - //Set all elements to 'value' + ///@brief Set all elements to 'value' void fill(T value) { std::fill(data_.get(), data_.get() + size(), value); } - //Resize the matrix to the specified dimensions - // - //If 'value' is specified all elements will be initialized to it, - //otherwise they will be default constructed. + /** + * @brief Resize the matrix to the specified dimensions + * + * If 'value' is specified all elements will be initialized to it, + * otherwise they will be default constructed. + */ void resize(std::array dim_sizes, T value = T()) { //Convert dimension to range [0..dim) for (size_t i = 0; i < dim_sizes.size(); ++i) { @@ -223,17 +264,19 @@ class NdOffsetMatrixBase { fill(value); } - //Resize the matrix to the specified dimension ranges - // - //If 'value' is specified all elements will be initialized to it, - //otherwise they will be default constructed. + /** + * @brief Resize the matrix to the specified dimension ranges + * + * If 'value' is specified all elements will be initialized to it, + * otherwise they will be default constructed. + */ void resize(std::array dim_ranges, T value = T()) { dim_ranges_ = dim_ranges; alloc(); fill(value); } - //Reset the matrix to size zero + ///@brief Reset the matrix to size zero void clear() { data_.reset(nullptr); for (size_t i = 0; i < dim_ranges_.size(); ++i) { @@ -242,27 +285,29 @@ class NdOffsetMatrixBase { } public: //Lifetime management - //Copy constructor + ///@brief Copy constructor NdOffsetMatrixBase(const NdOffsetMatrixBase& other) : NdOffsetMatrixBase(other.dim_ranges_) { std::copy(other.data_.get(), other.data_.get() + other.size(), data_.get()); } - //Move constructor + ///@brief Move constructor NdOffsetMatrixBase(NdOffsetMatrixBase&& other) : NdOffsetMatrixBase() { swap(*this, other); } - //Copy/move assignment - // - //Note that rhs is taken by value (copy-swap idiom) + /** + * @brief Copy/move assignment + * + * Note that rhs is taken by value (copy-swap idiom) + */ NdOffsetMatrixBase& operator=(NdOffsetMatrixBase rhs) { swap(*this, rhs); return *this; } - //Swap two NdOffsetMatrixBase objects + ///@brief Swap two NdOffsetMatrixBase objects friend void swap(NdOffsetMatrixBase& m1, NdOffsetMatrixBase& m2) { using std::swap; swap(m1.dim_ranges_, m2.dim_ranges_); @@ -270,7 +315,7 @@ class NdOffsetMatrixBase { } private: - //Allocate space for all the elements + // Allocate space for all the elements void alloc() { data_ = std::make_unique(size()); } @@ -280,71 +325,78 @@ class NdOffsetMatrixBase { std::unique_ptr data_ = nullptr; }; -//An N-dimensional matrix supporting arbitrary (continuous) index ranges -//per dimension. -// -//If no second template parameter is provided defaults to a 2-dimensional -//matrix -// -//Examples: -// -// //A 2-dimensional matrix with indicies [0..4][0..9] -// NdOffsetMatrix m1({5,10}); -// -// //Accessing an element -// int i = m4[3][5]; -// -// //Setting an element -// m4[6][20] = 0; -// -// //A 2-dimensional matrix with indicies [2..6][5..9] -// // Note that C++ requires one more set of curly brace than you would expect -// NdOffsetMatrix m2({{{2,7},{5,10}}}); -// -// //A 3-dimensional matrix with indicies [0..4][0..9][0..19] -// NdOffsetMatrix m3({5,10,20}); -// -// //A 3-dimensional matrix with indicies [2..6][1..19][50..89] -// NdOffsetMatrix m4({{{2,7}, {1,20}, {50,90}}}); -// -// //A 2-dimensional matrix with indicies [2..6][1..20], with all entries -// //intialized to 42 -// NdOffsetMatrix m4({{{2,7}, {1,21}}}, 42); -// -// //A 2-dimensional matrix with indicies [0..4][0..9], with all entries -// //initialized to 42 -// NdOffsetMatrix m1({5,10}, 42); -// -// //Filling all entries with value 101 -// m1.fill(101); -// -// //Resizing an existing matrix (all values reset to default constucted value) -// m1.resize({5,5}) -// -// //Resizing an existing matrix (all elements set to value 88) -// m1.resize({15,55}, 88) +/** + * @brief An N-dimensional matrix supporting arbitrary (continuous) index ranges per dimension. + * + * If no second template parameter is provided defaults to a 2-dimensional + * matrix + * + * Examples: + * + * //A 2-dimensional matrix with indicies [0..4][0..9] + * NdOffsetMatrix m1({5,10}); + * + * //Accessing an element + * int i = m4[3][5]; + * + * //Setting an element + * m4[6][20] = 0; + * + * //A 2-dimensional matrix with indicies [2..6][5..9] + * // Note that C++ requires one more set of curly brace than you would expect + * NdOffsetMatrix m2({{{2,7},{5,10}}}); + * + * //A 3-dimensional matrix with indicies [0..4][0..9][0..19] + * NdOffsetMatrix m3({5,10,20}); + * + * //A 3-dimensional matrix with indicies [2..6][1..19][50..89] + * NdOffsetMatrix m4({{{2,7}, {1,20}, {50,90}}}); + * + * //A 2-dimensional matrix with indicies [2..6][1..20], with all entries + * //intialized to 42 + * NdOffsetMatrix m4({{{2,7}, {1,21}}}, 42); + * + * //A 2-dimensional matrix with indicies [0..4][0..9], with all entries + * //initialized to 42 + * NdOffsetMatrix m1({5,10}, 42); + * + * //Filling all entries with value 101 + * m1.fill(101); + * + * //Resizing an existing matrix (all values reset to default constucted value) + * m1.resize({5,5}) + * + * //Resizing an existing matrix (all elements set to value 88) + * m1.resize({15,55}, 88) + */ template class NdOffsetMatrix : public NdOffsetMatrixBase { //General case static_assert(N >= 2, "Minimum dimension 2"); public: - //Use the base constructors + ///@brief Use the base constructors using NdOffsetMatrixBase::NdOffsetMatrixBase; public: - //Access an element - // - //Returns a proxy-object to allow chained array-style indexing (N >= 2 case) - //template= 2>::type, typename T1=T> + /** + * @brief Access an element + * + * Returns a proxy-object to allow chained array-style indexing (N >= 2 case) + * template= 2>::type, typename T1=T> + */ const NdOffsetMatrixProxy operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(this->dim_size(1) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(index >= this->dim_ranges_[0].begin_index(), "Index out of range (below dimension minimum)"); VTR_ASSERT_SAFE_MSG(index < this->dim_ranges_[0].end_index(), "Index out of range (above dimension maximum)"); - //The elements are stored in zero-indexed form, so adjust for any - //non-zero minimum index in this dimension + /* + * Clacluate the effective index + * + * The elements are stored in zero-indexed form, so adjust for any + * non-zero minimum index in this dimension + */ size_t effective_index = index - this->dim_ranges_[0].begin_index(); //Calculate the stride for the current dimension @@ -360,24 +412,30 @@ class NdOffsetMatrix : public NdOffsetMatrixBase { this->data_.get() + dim_stride * effective_index); //Advance to index in this dimension } - //Access an element - // - //Returns a proxy-object to allow chained array-style indexing + /** + * @brief Access an element + * + * Returns a proxy-object to allow chained array-style indexing + */ NdOffsetMatrixProxy operator[](size_t index) { //Call the const version, since returned by value don't need to worry about const return const_cast*>(this)->operator[](index); } }; +/** + * @brief A 1-dimensional matrix supporting arbitrary (continuous) index ranges per dimension. + * + * This is considered a specialization for N=1 + */ template class NdOffsetMatrix : public NdOffsetMatrixBase { - //Specialization for N = 1 public: - //Use the base constructors + ///@brief Use the base constructors using NdOffsetMatrixBase::NdOffsetMatrixBase; public: - //Access an element (immutable) + ///@brief Access an element (immutable) const T& operator[](size_t index) const { VTR_ASSERT_SAFE_MSG(this->dim_size(0) > 0, "Can not index into size zero dimension"); VTR_ASSERT_SAFE_MSG(index >= this->dim_ranges_[0].begin_index(), "Index out of range (below dimension minimum)"); @@ -386,14 +444,14 @@ class NdOffsetMatrix : public NdOffsetMatrixBase { return this->data_[index]; } - //Access an element (mutable) + ///@brief Access an element (mutable) T& operator[](size_t index) { //Call the const version, and cast away const-ness return const_cast(const_cast*>(this)->operator[](index)); } }; -//Convenient short forms for common NdMatricies +///@brief Convenient short forms for common NdMatricies template using OffsetMatrix = NdOffsetMatrix; diff --git a/libs/libvtrutil/src/vtr_ostream_guard.h b/libs/libvtrutil/src/vtr_ostream_guard.h index 65cb72a51e1..199c5cb4cc5 100644 --- a/libs/libvtrutil/src/vtr_ostream_guard.h +++ b/libs/libvtrutil/src/vtr_ostream_guard.h @@ -3,9 +3,10 @@ namespace vtr { -//A RAII guard class to ensure restoration of output stream format +///@brief A RAII guard class to ensure restoration of output stream format class OsFormatGuard { public: + ///@brief constructor explicit OsFormatGuard(std::ostream& os) : os_(os) , flags_(os_.flags()) //Save formatting flag state @@ -13,6 +14,7 @@ class OsFormatGuard { , precision_(os.precision()) , fill_(os.fill()) {} + ///@brief destructor ~OsFormatGuard() { os_.flags(flags_); //Restore os_.width(width_); diff --git a/libs/libvtrutil/src/vtr_pair_util.h b/libs/libvtrutil/src/vtr_pair_util.h index e25b9bd15df..feabbd1aca5 100644 --- a/libs/libvtrutil/src/vtr_pair_util.h +++ b/libs/libvtrutil/src/vtr_pair_util.h @@ -4,8 +4,9 @@ #include "vtr_range.h" namespace vtr { - -//Iterator which derefernces the 'first' element of a std::pair iterator +/** + * @brief Iterator which derefernces the 'first' element of a std::pair iterator + */ template class pair_first_iter { public: @@ -15,27 +16,41 @@ class pair_first_iter { using pointer = value_type*; using reference = value_type&; + ///@brief constructor pair_first_iter(PairIter init) : iter_(init) {} + + ///@brief increment operator (++) auto operator++() { iter_++; return *this; } + + ///@brief decrement operator (\-\-) auto operator--() { iter_--; return *this; } + + ///@brief dereference * operator auto operator*() { return iter_->first; } + + ///@brief -> operator auto operator-> () { return &iter_->first; } + ///@brief == operator friend bool operator==(const pair_first_iter lhs, const pair_first_iter rhs) { return lhs.iter_ == rhs.iter_; } + + ///@brief != operator friend bool operator!=(const pair_first_iter lhs, const pair_first_iter rhs) { return !(lhs == rhs); } private: PairIter iter_; }; -//Iterator which derefernces the 'second' element of a std::pair iterator +/** + *Iterator which derefernces the 'second' element of a std::pair iterator + */ template class pair_second_iter { public: @@ -45,20 +60,32 @@ class pair_second_iter { using pointer = value_type*; using reference = value_type&; + ///@brief constructor pair_second_iter(PairIter init) : iter_(init) {} + + ///@brief increment operator (++) auto operator++() { iter_++; return *this; } + + ///@brief decrement operator (--) auto operator--() { iter_--; return *this; } + + ///@brief dereference * operator auto operator*() { return iter_->second; } + + ///@brief -> operator auto operator-> () { return &iter_->second; } + ///@brief == operator friend bool operator==(const pair_second_iter lhs, const pair_second_iter rhs) { return lhs.iter_ == rhs.iter_; } + + ///@brief != operator friend bool operator!=(const pair_second_iter lhs, const pair_second_iter rhs) { return !(lhs == rhs); } private: diff --git a/libs/libvtrutil/src/vtr_path.h b/libs/libvtrutil/src/vtr_path.h index d5c128d442c..a48d2bdb59c 100644 --- a/libs/libvtrutil/src/vtr_path.h +++ b/libs/libvtrutil/src/vtr_path.h @@ -3,20 +3,30 @@ #include #include +/** + * @file + * @brief This file defines some useful utilities to handle paths + */ namespace vtr { -//Splits off the name and extension (including ".") of the specified filename +///@brief Splits off the name and extension (including ".") of the specified filename std::array split_ext(const std::string& filename); -//Returns the basename of path (i.e. the last filename component) -// For example, the path "/home/user/my_files/test.blif" -> "test.blif" +/** + * @brief Returns the basename of path (i.e. the last filename component) + * + * For example, the path "/home/user/my_files/test.blif" -> "test.blif" + */ std::string basename(const std::string& path); -//Returns the dirname of path (i.e. everything except the last filename component) -// For example, the path "/home/user/my_files/test.blif" -> "/home/user/my_files/" +/** + * Returns the dirname of path (i.e. everything except the last filename component) + * + * For example, the path "/home/user/my_files/test.blif" -> "/home/user/my_files/" + */ std::string dirname(const std::string& path); -//Returns the current working directory +///@brief Returns the current working directory std::string getcwd(); } // namespace vtr diff --git a/libs/libvtrutil/src/vtr_ragged_matrix.h b/libs/libvtrutil/src/vtr_ragged_matrix.h index bfb787da270..bbe7fea78fc 100644 --- a/libs/libvtrutil/src/vtr_ragged_matrix.h +++ b/libs/libvtrutil/src/vtr_ragged_matrix.h @@ -8,49 +8,58 @@ namespace vtr { -//A 2 dimensional 'ragged' matrix with rows indexed by Index0, -//and each row of variable length (indexed by Index1) -// -//Example: -// -// std::vector row_sizes = {1, 5, 3, 10}; -// FlatRaggedMatrix matrix(row_sizes); -// -// //Fill in all entries with ascending values -// float value = 1.; -// for (size_t irow = 0; irow < row_sizes.size(); ++irow) { -// for (size_t icol = 0; icol < row_sizes[irow]; ++icoll) { -// matrix[irow][icol] = value; -// value += 1.; -// } -// } -// -// -//For efficiency, this class uses a flat memory layout, -//where all elements are laid out contiguiously (one row -//after another). -// -//Expects Index0 and Index1 to be convertable to size_t +/** + * @brief A 2 dimensional 'ragged' matrix with rows indexed by Index0, and each row of variable length (indexed by Index1) + * + * Example: + * + * std::vector row_sizes = {1, 5, 3, 10}; + * FlatRaggedMatrix matrix(row_sizes); + * + * //Fill in all entries with ascending values + * float value = 1.; + * for (size_t irow = 0; irow < row_sizes.size(); ++irow) { + * for (size_t icol = 0; icol < row_sizes[irow]; ++icoll) { + * matrix[irow][icol] = value; + * value += 1.; + * } + * } + * + * + * For efficiency, this class uses a flat memory layout, + * where all elements are laid out contiguiously (one row + * after another). + * + * Expects Index0 and Index1 to be convertable to size_t. + */ template class FlatRaggedMatrix { - public: //Lifetime + public: + ///@brief default constructor FlatRaggedMatrix() = default; - //Constructs matrix with 'nrows' rows, where the row length is determined - //by calling 'row_length_callback' with the associated row index. + /** + * @brief Constructs matrix with 'nrows' rows. + * + * The row length is determined by calling + * 'row_length_callback' with the associated row index. + */ template FlatRaggedMatrix(size_t nrows, Callback& row_length_callback, T default_value = T()) : FlatRaggedMatrix(RowLengthIterator(0, row_length_callback), RowLengthIterator(nrows, row_length_callback), default_value) {} - //Constructs matrix from a container of row lengths + ///@brief Constructs matrix from a container of row lengths template FlatRaggedMatrix(Container container, T default_value = T()) : FlatRaggedMatrix(std::begin(container), std::end(container), default_value) {} - //Constructs matrix from an iterator range, where the length of the range is - //the number of rows, and iterator values are the row lengths. + /** + * @brief Constructs matrix from an iterator range. + * + * The length of the range is the number of rows, and iterator values are the row lengths. + */ template FlatRaggedMatrix(Iter row_size_first, Iter row_size_last, T default_value = T()) { size_t nrows = std::distance(row_size_first, row_size_last); @@ -72,11 +81,12 @@ class FlatRaggedMatrix { } public: //Accessors - //Iterators to *all* elements + ///@brief Iterators to *all* elements auto begin() { return data_.begin(); } + ///@brief Iterator to the last element of the matrix auto end() { if (empty()) { return data_.end(); @@ -84,10 +94,12 @@ class FlatRaggedMatrix { return data_.end() - 1; } + ///@brief Iterator to the first element of the matrix (immutable) auto begin() const { return data_.begin(); } + ///@brief Iterator to the last element of the matrix (immutable) auto end() const { if (empty()) { return data_.end(); @@ -95,6 +107,7 @@ class FlatRaggedMatrix { return data_.end() - 1; } + ///@brief Return the size of the matrix size_t size() const { if (data_.empty()) { return 0; @@ -102,11 +115,12 @@ class FlatRaggedMatrix { return data_.size() - 1; //-1 for sentinel } + ///@brief Return true if empty bool empty() const { return size() == 0; } - //Indexing operators for the first dimension + ///@brief Indexing operators for the first dimension vtr::array_view operator[](Index0 i) { int idx = size_t(i); T* first = &data_[first_elem_[idx]]; @@ -115,6 +129,7 @@ class FlatRaggedMatrix { last - first); } + ///@brief Indexing operators for the first dimension (immutable) vtr::array_view operator[](Index0 i) const { int idx = size_t(i); const T* first = &data_[first_elem_[idx]]; @@ -123,51 +138,64 @@ class FlatRaggedMatrix { last - first); } + ///@brief Clears the matrix void clear() { data_.clear(); first_elem_.clear(); } + ///@brief Swaps two matrices void swap(FlatRaggedMatrix& other) { std::swap(data_, other.data_); std::swap(first_elem_, other.first_elem_); } + ///@brief Swaps two matrices friend void swap(FlatRaggedMatrix& lhs, FlatRaggedMatrix& rhs) { lhs.swap(rhs); } public: //Types - //Proxy class used to represent a 'row' in the matrix + ///@brief Proxy class used to represent a 'row' in the matrix template class ProxyRow { public: + ///@brief constructor ProxyRow(U* first, U* last) : first_(first) , last_(last) {} + ///@brief Return iterator to the first element U* begin() { return first_; } + ///@brief Return iterator to the last element U* end() { return last_; } + ///@brief Return iterator to the first element (immutable) const U* begin() const { return first_; } + ///@brief Return iterator to the last element (immutable) const U* end() const { return last_; } + ///@brief Return the size of the row size_t size() const { return last_ - first_; } + ///@brief indexing [] operator U& operator[](Index1 j) { VTR_ASSERT_SAFE(size_t(j) < size()); return first_[size_t(j)]; } + ///@brief indexing [] operator (immutable) const U& operator[](Index1 j) const { VTR_ASSERT_SAFE(size_t(j) < size()); return first_[size_t(j)]; } + ///@brief Return iterator to the first element U* data() { return first_; } + ///@brief Return iterator to the first element (immutable) U* data() const { return first_; } @@ -178,8 +206,11 @@ class FlatRaggedMatrix { }; private: - //Iterator for constructing FlatRaggedMatrix which uses a callback to determine - //row lengths. + /* + * Iterator for constructing FlatRaggedMatrix. + * + * uses a callback to determine row lengths. + */ template class RowLengthIterator : public std::iterator { public: diff --git a/libs/libvtrutil/src/vtr_random.cpp b/libs/libvtrutil/src/vtr_random.cpp index 282814a83ed..3427e5fc2e6 100644 --- a/libs/libvtrutil/src/vtr_random.cpp +++ b/libs/libvtrutil/src/vtr_random.cpp @@ -16,6 +16,9 @@ constexpr size_t IM = 2147483648u; static RandState random_state = 0; +/** + * @brief The pseudo-random number generator is initialized using the argument passed as seed. + */ void srandom(int seed) { random_state = (unsigned int)seed; } diff --git a/libs/libvtrutil/src/vtr_random.h b/libs/libvtrutil/src/vtr_random.h index 161081331b0..c5a3ce66351 100644 --- a/libs/libvtrutil/src/vtr_random.h +++ b/libs/libvtrutil/src/vtr_random.h @@ -6,20 +6,33 @@ namespace vtr { /*********************** Portable random number generators *******************/ typedef unsigned RandState; +/** + * @brief The pseudo-random number generator is initialized using the argument passed as seed. + */ void srandom(int seed); + +///@brief Return The random number generator state RandState get_random_state(); + +///@brief Return a randomly generated integer less than or equal imax int irand(int imax); + +///@brief Return a randomly generated integer less than or equal imax using the generator (rand_state) int irand(int imax, RandState& rand_state); + +///@brief Return a randomly generated float number between [0,1] float frand(); -//Portable/invariant version of std::shuffle -// -//Note that std::shuffle relies on std::uniform_int_distribution -//which can produce different sequences accross different -//compilers/compiler versions. -// -//This version should be deterministic/invariant. However, since -//it uses vtr::irand(), may not be as well distributed as std::shuffle. +/** + * @brief Portable/invariant version of std::shuffle + * + * Note that std::shuffle relies on std::uniform_int_distribution + * which can produce different sequences accross different + * compilers/compiler versions. + * + * This version should be deterministic/invariant. However, since + * it uses vtr::irand(), may not be as well distributed as std::shuffle. + */ template void shuffle(Iter first, Iter last, RandState& rand_state) { for (auto i = (last - first) - 1; i > 0; --i) { diff --git a/libs/libvtrutil/src/vtr_range.h b/libs/libvtrutil/src/vtr_range.h index ef6d3babb70..493a379fbd9 100644 --- a/libs/libvtrutil/src/vtr_range.h +++ b/libs/libvtrutil/src/vtr_range.h @@ -3,8 +3,8 @@ #include namespace vtr { -/* - * The vtr::Range template models a range defined by two iterators of type T. +/** + * @brief The vtr::Range template models a range defined by two iterators of type T. * * It allows conveniently returning a range from a single function call * without having to explicity expose the underlying container, or make two @@ -40,14 +40,21 @@ namespace vtr { template class Range { public: + ///@brief constructor Range(T b, T e) : begin_(b) , end_(e) {} + ///@brief Return an iterator to the start of the range T begin() { return begin_; } + ///@brief Return an iterator to the end of the range T end() { return end_; } + ///@brief Return an iterator to the start of the range (immutable) const T begin() const { return begin_; } + ///@brief Return an iterator to the end of the range (immutable) const T end() const { return end_; } + ///@brief Return true if empty bool empty() { return begin_ == end_; } + ///@brief Return the range size size_t size() { return std::distance(begin_, end_); } private: @@ -55,8 +62,8 @@ class Range { T end_; }; -/* - * Creates a vtr::Range from a pair of iterators. +/** + * @brief Creates a vtr::Range from a pair of iterators. * * Unlike using the vtr::Range() constructor (which requires specifying * the template type T, using vtr::make_range() infers T from the arguments. @@ -67,8 +74,8 @@ class Range { template auto make_range(T b, T e) { return Range(b, e); } -/* - * Creates a vtr::Range from a container +/** + * @brief Creates a vtr::Range from a container */ template auto make_range(const Container& c) { return make_range(std::begin(c), std::end(c)); } diff --git a/libs/libvtrutil/src/vtr_rusage.cpp b/libs/libvtrutil/src/vtr_rusage.cpp index b6a8ea7ce23..a3b74c04c86 100644 --- a/libs/libvtrutil/src/vtr_rusage.cpp +++ b/libs/libvtrutil/src/vtr_rusage.cpp @@ -7,6 +7,7 @@ namespace vtr { +///@brief Returns the maximum resident set size in bytes, or zero if unable to determine. size_t get_max_rss() { size_t max_rss = 0; diff --git a/libs/libvtrutil/src/vtr_rusage.h b/libs/libvtrutil/src/vtr_rusage.h index cf179abe77b..b69dc438a97 100644 --- a/libs/libvtrutil/src/vtr_rusage.h +++ b/libs/libvtrutil/src/vtr_rusage.h @@ -4,8 +4,7 @@ namespace vtr { -//Returns the maximum resident set size in bytes, -//or zero if unable to determine. +///@brief Returns the maximum resident set size in bytes, or zero if unable to determine. size_t get_max_rss(); } // namespace vtr diff --git a/libs/libvtrutil/src/vtr_sentinels.h b/libs/libvtrutil/src/vtr_sentinels.h index 4f8c971b554..036fd593b17 100644 --- a/libs/libvtrutil/src/vtr_sentinels.h +++ b/libs/libvtrutil/src/vtr_sentinels.h @@ -1,38 +1,47 @@ #ifndef VTR_SENTINELS_H #define VTR_SENTINELS_H -namespace vtr { -//Some specialized containers like vtr::linear_map and -//vtr::vector_map require sentinel values to mark invalid/uninitialized -//values. By convention, such containers query the sentinel objects static -//INVALID() member function to retrieve the sentinel value. -// -//These classes allows users to specify a custom sentinel value. -// -//Usually the containers default to DefaultSentinel +/** + * @file + * @brief This header defines different sentinal value classes + */ +namespace vtr { -//The sentinel value is the default constructed value of the type +/** + * @brief The Default sentinal value class + * + * Some specialized containers like vtr::linear_map and + * vtr::vector_map require sentinel values to mark invalid/uninitialized + * values. By convention, such containers query the sentinel objects static + * INVALID() member function to retrieve the sentinel value. + * + * These classes allows users to specify a custom sentinel value. + * + * Usually the containers default to DefaultSentinel + * + * The sentinel value is the default constructed value of the type + */ template class DefaultSentinel { public: constexpr static T INVALID() { return T(); } }; -//Specialization for pointer types +///@brief Specialization for pointer types template class DefaultSentinel { public: constexpr static T* INVALID() { return nullptr; } }; -//The sentile value is a specified value of the type +///@brief The sentile value is a specified value of the type template class CustomSentinel { public: constexpr static T INVALID() { return T(val); } }; -//The common case where -1 is used as the sentinel value +///@brief The common case where -1 is used as the sentinel value template using MinusOneSentinel = CustomSentinel; diff --git a/libs/libvtrutil/src/vtr_small_vector.h b/libs/libvtrutil/src/vtr_small_vector.h index ce9540bc52a..5fe75520129 100644 --- a/libs/libvtrutil/src/vtr_small_vector.h +++ b/libs/libvtrutil/src/vtr_small_vector.h @@ -11,8 +11,11 @@ namespace vtr { namespace small_vector_impl { -//The long format view of the vector, which consists of a dynamically allocated array, -//capacity and size. +/** + * @brief The long format view of the vector. + * + * It consists of a dynamically allocated array, capacity and size. + */ template struct long_format { T* data_ = nullptr; @@ -20,17 +23,24 @@ struct long_format { S size_ = 0; }; -//The short format view of the vector, which consists of an in-place (potentially empty) -//array of objects, a pad, and a size. +/** + * @brief The short format view of the vector. + * + * It consists of an in-place (potentially empty) + * array of objects, a pad, and a size. + */ template struct short_format { std::array data_; - std::array pad_; //Padding to keep size_ aligned in both long_format and short_format + std::array pad_; ///< Padding to keep size_ aligned in both long_format and short_format S size_ = 0; }; -//We need a specialized version of short_format for padding of size zero, -//since a std::array with zero array size may still have non-zero sizeof() +/** + * @brief A specialized version of short_format for padding of size zero. + * + * Since a std::array with zero array size may still have non-zero sizeof() + */ template struct short_format { std::array data_; @@ -39,26 +49,29 @@ struct short_format { } // namespace small_vector_impl -//vtr::small_vector is a std::vector like container which: -// * consumes less memory: sizeof(vtr::small_vector) < sizeof(std::vector) -// * possibly stores elements in-place (i.e. within the object) -// -//On a typical LP64 system a vtr::small_vector consumes 16 bytes by default and supports -//vectors up to ~2^32 elements long, while a std::vector consumes 24 bytes and supports up -//to ~2^64 elements. The type used to store the size and capacity is configurable, -//and set by the second template parameter argument. Setting it to size_t will replicate -//std::vector's characteristics. -// -//For short vectors vtr::small_vector will try to store elements in-place (i.e. within the -//vtr::small_vector object) instead of dynamically allocating an array (by re-using the -//internal storage for the pointer, size and capacity). Whether this is possible depends on -//the size and alignment requirements of the value type, as compared to -//vtr::small_vector. If in-place storage is not possible (e.g. due to a large value -//type, or a large number of elements) a dynamic buffer is allocated (similar to -//std::vector). -// -//This is a highly specialized container. Unless you have specifically measured it's -//usefulness you should use std::vector. +/** + * @brief vtr::small_vector is a std::vector like container which: + * + * - consumes less memory: sizeof(vtr::small_vector) < sizeof(std::vector) + * - possibly stores elements in-place (i.e. within the object) + * + * On a typical LP64 system a vtr::small_vector consumes 16 bytes by default and supports + * vectors up to ~2^32 elements long, while a std::vector consumes 24 bytes and supports up + * to ~2^64 elements. The type used to store the size and capacity is configurable, + * and set by the second template parameter argument. Setting it to size_t will replicate + * std::vector's characteristics. + * + * For short vectors vtr::small_vector will try to store elements in-place (i.e. within the + * vtr::small_vector object) instead of dynamically allocating an array (by re-using the + * internal storage for the pointer, size and capacity). Whether this is possible depends on + * the size and alignment requirements of the value type, as compared to + * vtr::small_vector. If in-place storage is not possible (e.g. due to a large value + * type, or a large number of elements) a dynamic buffer is allocated (similar to + * std::vector). + * + * This is a highly specialized container. Unless you have specifically measured it's + * usefulness you should use std::vector. + */ template class small_vector { public: //Types @@ -78,6 +91,7 @@ class small_vector { typedef S size_type; public: //Constructors + ///@brief constructor small_vector() { if (SHORT_CAPACITY == 0) { long_.data_ = nullptr; @@ -85,6 +99,7 @@ class small_vector { } set_size(0); } + ///@brief constructor small_vector(size_type nelem) : small_vector() { reserve(nelem); @@ -95,22 +110,27 @@ class small_vector { } public: //Accessors + ///@brief Return a const_iterator to the first element const_iterator begin() const { return cbegin(); } + ///@brief Return a const_iterator pointing to the past-the-end element in the container. const_iterator end() const { return cend(); } + ///@brief Return a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). const_reverse_iterator rbegin() const { return crbegin(); } + ///@brief Return a const_reverse_iterator pointing to the theoretical element preceding the first element in the container (which is considered its reverse end). const_reverse_iterator rend() const { return crend(); } + ///@brief Return a const_iterator pointing to the first element in the container. const_iterator cbegin() const { if (is_short()) { return short_.data_.data(); @@ -118,6 +138,7 @@ class small_vector { return long_.data_; } + ///@brief a const_iterator pointing to the past-the-end element in the container. const_iterator cend() const { if (is_short()) { return short_.data_.data() + size(); @@ -125,23 +146,27 @@ class small_vector { return long_.data_ + size(); } + ///@brief Return a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). const_reverse_iterator crbegin() const { return const_reverse_iterator(cend()); } + ///@brief Return a const_reverse_iterator pointing to the theoretical element preceding the first element in the container (which is considered its reverse end). const_reverse_iterator crend() const { return const_reverse_iterator(cbegin()); } + ///@brief return the vector size (Padding ensures long/short format sizes are always aligned) size_type size() const { - //Padding ensures long/short format sizes are always aligned return long_.size_; } + ///@brief Return the maximum size size_t max_size() const { return std::numeric_limits::max(); } + ///@brief Return the vector capacity size_type capacity() const { if (is_short()) { return SHORT_CAPACITY; //Fixed capacity @@ -149,8 +174,10 @@ class small_vector { return long_.capacity_; } + ///@brief Return true if empty bool empty() const { return size() == 0; } + ///@brief Immutable indexing operator [] const_reference operator[](size_t i) const { if (is_short()) { return short_.data_[i]; @@ -158,6 +185,7 @@ class small_vector { return long_.data_[i]; } + ///@brief Immutable at() operator const_reference at(size_t i) const { if (i > size()) { throw std::out_of_range("Index out of bounds"); @@ -165,14 +193,17 @@ class small_vector { return operator[](i); } + ///@brief Return a constant reference to the first element const_reference front() const { return *begin(); } + ///@brief Return a constant reference to the last element const_reference back() const { return *(end() - 1); } + ///@brief Return a constant pointer to the vector data const_pointer data() const { if (is_short()) { short_.data_; @@ -181,28 +212,34 @@ class small_vector { } public: //Mutators + ///@brief Return an iterator pointing to the first element in the sequence iterator begin() { //Call const method and cast-away constness return const_cast(const_cast*>(this)->begin()); } + ///@brief Return an iterator referring to the past-the-end element in the vector container. iterator end() { return const_cast(const_cast*>(this)->end()); } + ///@brief Return a reverse iterator pointing to the last element in the vector (i.e., its reverse beginning). reverse_iterator rbegin() { //Call const method and cast-away constness return reverse_iterator(const_cast*>(this)->end()); } + ///@brief Return a reverse iterator pointing to the theoretical element preceding the first element in the vector (which is considered its reverse end). reverse_iterator rend() { return reverse_iterator(const_cast*>(this)->begin()); } + ///@brief Resizes the container so that it contains n elements void resize(size_type n) { resize(n, value_type()); } + ///@brief Resizes the container so that it contains n elements and fills it with val void resize(size_type n, value_type val) { if (n < size()) { //Remove at end @@ -213,33 +250,42 @@ class small_vector { } } + /** + * @brief Reserve memory for a spicific number of elemnts + * + * Don't change capacity unless requested number of elements is both: + * - More than the short capacity (no need to reserve up to short capacity) + * - Greater than the current size (capacity can never be below size) + */ void reserve(size_type num_elems) { - //Don't change capacity unless requested number of elements is both: - // * More than the short capacity (no need to reserve up to short capacity) - // * Greater than the current size (capacity can never be below size) if (num_elems > SHORT_CAPACITY && num_elems > size()) { change_capacity(num_elems); } } + ///@brief Requests the container to reduce its capacity to fit its size. void shrink_to_fit() { if (!is_short()) { change_capacity(size()); } } + ///@brief Indexing operator [] reference operator[](size_t i) { return const_cast(const_cast*>(this)->operator[](i)); } + ///@brief at() operator reference at(size_t i) { return const_cast(const_cast*>(this)->at(i)); } + ///@brief Returns a reference to the first element in the vector. reference front() { return const_cast(const_cast*>(this)->front()); } + ///@brief Returns a reference to the last element in the vector. reference back() { return const_cast(const_cast*>(this)->back()); } @@ -248,21 +294,38 @@ class small_vector { return const_cast(const_cast*>(this)->data()); } + /** + * @brief Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. + * + * Input iterators to the initial and final positions in a sequence. The range used is [first,last), + * which includes all the elements between first and last, including the element pointed by first + * but not the element pointed by last. + */ template void assign(InputIterator first, InputIterator last) { insert(begin(), first, last); } + /** + * @brief Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. + * + * Resize the vector to n and fill it with val + */ void assign(size_type n, const value_type& val) { insert(begin(), n, val); } + /** + * @brief Assigns new contents to the vector, replacing its current contents, and modifying its size accordingly. + * + * The compiler will automatically construct such objects from initializer list declarators (il) + */ void assign(std::initializer_list il) { assign(il.begin(), il.end()); } + ///@brief Construct default value_type at new location void push_back(value_type value) { - //Construct default value_type at new location auto new_ptr = next_back(); new (new_ptr) T(); @@ -272,25 +335,33 @@ class small_vector { *new_ptr = std::move(value); } + ///@brief Removes the last element in the vector, effectively reducing the container size by one. void pop_back() { if (size() > 0) { erase(end() - 1); } } + ///@brief The vector is extended by inserting new elements before the element at the specified position, effectively increasing the container size by the number of elements inserted. iterator insert(const_iterator position, const value_type& val) { return insert(position, 1, val); } + /** + * @brief Insert a new value + * + * Location of position as an index, which will be + * unchanged if the underlying storage is reallocated + */ iterator insert(const_iterator position, size_type n, const value_type& val) { - //Location of position as an index, which will be - //unchanged if the underlying storage is reallocated size_type i = std::distance(cbegin(), position); - //If needed, grow capacity - // - //Note that change_capacity will automatically convert from short to long - //format if required. + /* + * If needed, grow capacity + * + * Note that change_capacity will automatically convert from short to long + * format if required. + */ size_type new_size = size() + n; if (capacity() < new_size) { change_capacity(new_size); @@ -308,6 +379,7 @@ class small_vector { return first; } + ///@brief Insert n elements at position position and fill them with value val iterator insert(const_iterator position, size_type n, value_type&& val) { return insert(position, n, value_type(val)); //TODO: optimize for moved val } @@ -339,10 +411,12 @@ class small_vector { //return begin() + i; //} + ///@brief Removes from the vector a single element (position). iterator erase(const_iterator position) { return erase(position, position + 1); } + ///@brief Removes from the vector either a range of elements ([first,last)). iterator erase(const_iterator first, const_iterator last) { //Number of elements to erase size_type n = std::distance(first, last); @@ -416,10 +490,12 @@ class small_vector { return begin() + std::distance(cbegin(), position); } + ///@brief Exchanges the content of the container by the content of x, which is another vector object of the same type. Sizes may differ. void swap(small_vector& other) { swap(*this, other); } + ///@brief swaps two vectors friend void swap(small_vector& lhs, small_vector& rhs) { using std::swap; @@ -436,23 +512,29 @@ class small_vector { auto& long_vec = ((lhs.is_short()) ? rhs : lhs); auto& short_vec = ((lhs.is_short()) ? lhs : rhs); - //If the two vectors are in different formats we can't just swap them, - //since the short format has real values (potentially with destructors), - //while the long format has only basic data types. - // - //Instead we copy the short_vec values into long, destruct the original short_vec - //values and then set short_vec to point to long_vec's original buffer (avoids - //extra copy of long elements). - - //Save long data + /** + * @brief Swapping two vectors of different formats + * + * If the two vectors are in different formats we can't just swap them, + * since the short format has real values (potentially with destructors), + * while the long format has only basic data types. + * + * Instead we copy the short_vec values into long, destruct the original short_vec + * values and then set short_vec to point to long_vec's original buffer (avoids + * extra copy of long elements). + * + * Save long data + */ pointer long_buf = long_vec.long_.data_; size_type long_size = long_vec.long_size_; size_type long_capacity = long_vec.long_.capacity_; - //Copy short data into long - // - //Note that the long format contains only basic data types with no destructors to call, - //so we can use uninitialzed copy + /** + * @brief Copy short data into long + * + * Note that the long format contains only basic data types with no destructors to call, + * so we can use uninitialzed copy + */ std::uninitialized_copy(short_vec.short_.begin(), short_vec.short_.end(), long_vec.short_.data_); long_vec.short_.size_ = short_vec.size(); @@ -466,12 +548,14 @@ class small_vector { } } + ///@brief Removes all elements from the vector (which are destroyed), leaving the container with a size of 0. void clear() { //Destruct all elements and clear size, but do not free memory destruct_elements(); set_size(0); } + ///@brief Inserts a new element at the end of the vector, right after its current last element. This new element is constructed in place using args as the arguments for its constructor. template void emplace_back(Args&&... args) { //Construct in-place @@ -485,6 +569,7 @@ class small_vector { //} public: //Comparisons + ///@brief == p[erator friend bool operator==(const small_vector& lhs, const small_vector& rhs) { if (lhs.size() != rhs.size()) { return false; @@ -493,28 +578,34 @@ class small_vector { rhs.begin()); } + ///@brief < operator friend bool operator<(const small_vector& lhs, const small_vector& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } + ///@brief != operator friend bool operator!=(const small_vector& lhs, const small_vector& rhs) { return !(lhs == rhs); } + ///@brief > operator friend bool operator>(const small_vector& lhs, const small_vector& rhs) { return rhs < lhs; } + ///@brief <= operator friend bool operator<=(const small_vector& lhs, const small_vector& rhs) { return !(rhs < lhs); } + ///@brief >= operator friend bool operator>=(const small_vector& lhs, const small_vector& rhs) { return !(lhs < rhs); } public: //Lifetime management + ///@brief destructor ~small_vector() { destruct_elements(); if (!is_short()) { @@ -522,6 +613,7 @@ class small_vector { } } + ///@brief copy constructor small_vector(const small_vector& other) { if (other.is_short()) { ~small_vector(); //Clean-up elements @@ -548,6 +640,7 @@ class small_vector { } } + ///@brief copy and swap constructor small_vector(small_vector&& other) : small_vector() { swap(*this, other); //Copy-swap @@ -562,11 +655,15 @@ class small_vector { static constexpr size_t LONG_FMT_SIZE = sizeof(small_vector_impl::long_format); static constexpr size_t LONG_FMT_ALIGN = alignof(small_vector_impl::long_format); - //The number of value types which can be stored in-place in the object (may be zero) + ///@brief The number of value types which can be stored in-place in the object (may be zero) static constexpr size_t SHORT_CAPACITY = (LONG_FMT_SIZE - sizeof(size_type)) / sizeof(value_type); - //The amount of padding required to ensure the size_ attributes of long_format and short_format - //are aligned. + /** + * @brief required padding + * + * The amount of padding required to ensure the size_ attributes of long_format and short_format + * are aligned. + */ static constexpr size_t SHORT_PAD = LONG_FMT_SIZE - (sizeof(value_type) * SHORT_CAPACITY + sizeof(size_type)); static constexpr size_t SHORT_FMT_SIZE = sizeof(small_vector_impl::short_format); @@ -579,8 +676,11 @@ class small_vector { static constexpr size_t INPLACE_CAPACITY = SHORT_CAPACITY; private: //Internal methods - //Returns a pointer to the (uninitialized) location for the next element to be added. - //Automatically grows the storage if needed. + /** + * @brief Returns a pointer to the (uninitialized) location for the next element to be added. + * + * Automatically grows the storage if needed. + */ T* next_back() { T* next = nullptr; if (size() < SHORT_CAPACITY) { //Space in-place @@ -597,10 +697,12 @@ class small_vector { return next; } - //Increases the capacity by GROWTH_FACTOR - // - //Note that this automatically handles the case of growing beyond SHORT_CAPACITY and - //switching to long_format + /** + * @brief Increases the capacity by GROWTH_FACTOR + * + * Note that this automatically handles the case of growing beyond SHORT_CAPACITY and + * switching to long_format + */ void grow() { //How much to scale the size of the storage when out of space constexpr size_type GROWTH_FACTOR = 2; @@ -615,11 +717,13 @@ class small_vector { change_capacity(new_capacity); } - //Changes capacity to new_capacity - // - //It is assumed that new_capacity is > SHORT_CAPACITY. - // - //If currently in short format, automatically converts to long format + /** + * @brief Changes capacity to new_capacity + * + * It is assumed that new_capacity is > SHORT_CAPACITY. + * + * If currently in short format, automatically converts to long format + */ void change_capacity(size_type new_capacity) { VTR_ASSERT_SAFE_MSG(new_capacity >= size(), "New capacity should be at least size"); @@ -648,36 +752,44 @@ class small_vector { } } - //Returns true if using the short/in-place format + ///@brief Returns true if using the short/in-place format bool is_short() const { return SHORT_CAPACITY > 0u //Can use the inplace buffer && size() <= SHORT_CAPACITY; //Not using the dynamic buffer } + /** + * @brief set the size + * + * The two data (short/long) are padded to + * ensure that thier size_ members area always + * aligned, allowing is to set the size directly + * for both formats + */ void set_size(size_type new_size) { - //The two data (short/long) are padded to - //ensure that thier size_ members area always - //aligned, allowing is to set the size directly - //for both formats short_.size_ = new_size; } - //Allocates raw (un-initialzied) memory for nelem objects of type T + ///@brief Allocates raw (un-initialzied) memory for nelem objects of type T static T* alloc(size_type nelem) { return static_cast(::operator new(sizeof(T) * nelem)); } - //Deallocates a block of memory - // - //Caller must ensure any object's associated with this block have already had - //their destructors called + /** + * @brief Deallocates a block of memory + * + * Caller must ensure any object's associated with this block have already had + * their destructors called + */ static void dealloc(T* data) { ::operator delete(data); } - //Swaps the elements in [src_first, src_last) to positions starting at dst_first - // - //Returns an iterator to the element in the first swapped location + /** + * @brief Swaps the elements in [src_first, src_last) to positions starting at dst_first + * + * Returns an iterator to the element in the first swapped location + */ iterator swap_elements(iterator src_first, iterator src_last, iterator dst_first) { VTR_ASSERT_SAFE_MSG(src_first < src_last, "First swap range first must start before last"); @@ -689,9 +801,11 @@ class small_vector { return src_first; } - //Swaps the elements in [src_first, src_last) in reverse order starting at dst_first and working backwards - // - //Returns an iterator to the element in the first swapped location + /** + * @brief Swaps the elements in [src_first, src_last) in reverse order starting at dst_first and working backwards + * + * Returns an iterator to the element in the first swapped location + */ iterator reverse_swap_elements(iterator src_first, iterator src_last, iterator dst_first) { VTR_ASSERT_SAFE_MSG(src_first < src_last, "First swap range first must start before last"); @@ -703,28 +817,32 @@ class small_vector { return src_first; } - //Calls the destructors of all elements currently held + ///@brief Calls the destructors of all elements currently held void destruct_elements() { destruct_elements(begin(), end()); } + ///@brief Calls the destructors of elements in [first, last] range void destruct_elements(iterator first, iterator last) { for (auto itr = first; itr != last; ++itr) { itr->~T(); } } + ///@brief Calls the destructors of elements in one position (position) void destruct_element(iterator position) { destruct_elements(position, position + 1); } private: //Data - //The object data storage is re-used between the long and short formats. - // - //If the capacity is small (less than or equal to SHORT_CAPACITY) the - //short format (which stores element in-place) is used. Otherwise the - //long format is used and the elements are stored in a dynamically - //allocated buffer + /* + * The object data storage is re-used between the long and short formats. + * + * If the capacity is small (less than or equal to SHORT_CAPACITY) the + * short format (which stores element in-place) is used. Otherwise the + * long format is used and the elements are stored in a dynamically + * allocated buffer + */ union { small_vector_impl::long_format long_; small_vector_impl::short_format short_; diff --git a/libs/libvtrutil/src/vtr_string_interning.h b/libs/libvtrutil/src/vtr_string_interning.h index e8beac04170..3af949701b2 100644 --- a/libs/libvtrutil/src/vtr_string_interning.h +++ b/libs/libvtrutil/src/vtr_string_interning.h @@ -1,45 +1,47 @@ -// Provides basic string interning, along with pattern splitting suitable -// for use with FASM. -// -// For reference, string interning refers to keeping a unique copy of a string -// in storage, and then handing out an id to that storage location, rather than -// keeping the string around. This deduplicates memory overhead for strings. -// -// This string internment has an additional feature that is splitting the -// input string into "parts" based on '.', which happens to be the feature -// seperator for FASM. This means the string "TILE.CLB.A" and "TILE.CLB.B" -// would be made up of the intern ids for {"TILE", "CLB", "A"} and -// {"TILE", "CLB", "B"} respectively, allowing some internal deduplication. -// -// Strings can contain up to kMaxParts, before they will be interned as their -// whole string. -// -// Interned strings (interned_string) that come from the same internment -// object (string_internment) can safely be checked for equality and hashed -// without touching the underlying string. Lexigraphical comprisions (e.g. <) -// requires reconstructing the string. -// -// Basic usage: -// 1) Create a string_internment -// 2) Invoke string_internment::intern_string, which returns the -// interned_string object that is the interned string's unique idenfier. -// This idenfier can be checked for equality or hashed. If -// string_internment::intern_string is called with the same string, a value -// equivalent interned_string object will be returned. -// 3. If the original string is required, interned_string::get can be invoked -// to copy the string into a std::string. -// interned_string also provides iteration via begin/end, however the begin -// method requires a pointer to original string_internment object. This is -// not suitable for range iteration, so the method interned_string::bind -// can be used to create a bound_interned_string that can be used in a -// range iteration context. -// -// For reference, the reason that interned_string's does not have a -// reference back to the string_internment object is to keep their memory -// footprint lower. #ifndef VTR_STRING_INTERNING_H_ #define VTR_STRING_INTERNING_H_ +/** + * @file + * @brief Provides basic string interning, along with pattern splitting suitable for use with FASM. + * + * For reference, string interning refers to keeping a unique copy of a string + * in storage, and then handing out an id to that storage location, rather than + * keeping the string around. This deduplicates memory overhead for strings. + * + * This string internment has an additional feature that is splitting the + * input string into "parts" based on '.', which happens to be the feature + * seperator for FASM. This means the string "TILE.CLB.A" and "TILE.CLB.B" + * would be made up of the intern ids for {"TILE", "CLB", "A"} and + * {"TILE", "CLB", "B"} respectively, allowing some internal deduplication. + * + * Strings can contain up to kMaxParts, before they will be interned as their + * whole string. + * + * Interned strings (interned_string) that come from the same internment + * object (string_internment) can safely be checked for equality and hashed + * without touching the underlying string. Lexigraphical comprisions (e.g. <) + * requires reconstructing the string. + * + * Basic usage: + * -# Create a string_internment + * -# Invoke string_internment::intern_string, which returns the + * interned_string object that is the interned string's unique idenfier. + * This idenfier can be checked for equality or hashed. If + * string_internment::intern_string is called with the same string, a value + * equivalent interned_string object will be returned. + * -# If the original string is required, interned_string::get can be invoked + * to copy the string into a std::string. + * interned_string also provides iteration via begin/end, however the begin + * method requires a pointer to original string_internment object. This is + * not suitable for range iteration, so the method interned_string::bind + * can be used to create a bound_interned_string that can be used in a + * range iteration context. + * + * For reference, the reason that interned_string's does not have a + * reference back to the string_internment object is to keep their memory + * footprint lower. + */ #include #include #include @@ -64,29 +66,35 @@ class interned_string_less; struct interned_string_tag; typedef StrongId StringId; -// To keep interned_string memory footprint lower and flexible, these values -// control the size of the storage used. - -// Number of bytes to represent the StringId. This implies a maximum number -// of unique strings available equal to (1 << (kBytesPerId*CHAR_BIT)). +/** + * @brief Values that control the size of the used storage + * + * To keep interned_string memory footprint lower and flexible, these values + * control the size of the storage used. + * + * Number of bytes to represent the StringId. This implies a maximum number of unique strings available equal to (1 << (kBytesPerId*CHAR_BIT)). + */ constexpr size_t kBytesPerId = 3; -// Maximum number of splits to accomidate before just interning the entire string. +///@brief Maximum number of splits to accomidate before just interning the entire string. constexpr size_t kMaxParts = 3; -// Number of bytes to represent the number of splits present in an interned string. +///@brief Number of bytes to represent the number of splits present in an interned string. constexpr size_t kSizeSize = 1; -// Which character to split the input string by. +///@brief Which character to split the input string by. constexpr char kSplitChar = '.'; static_assert((1 << (CHAR_BIT * kSizeSize)) > kMaxParts, "Size of size data is too small"); -// Iterator over interned string. -// This object is much heavier memory wise than interned_string, so do not -// store these. -// -// This iterator only accomidates the forward_iterator concept. -// -// Do no construct this iterator directly. Use either -// bound_interned_string::begin/end or interned_string;:begin/end. +/** + * @brief Iterator over interned string. + * + * This object is much heavier memory wise than interned_string, so do not + * store these. + * + * This iterator only accomidates the forward_iterator concept. + * + * Do no construct this iterator directly. Use either + * bound_interned_string::begin/end or interned_string;:begin/end. + */ class interned_string_iterator { public: interned_string_iterator(const string_internment* internment, std::array intern_ids, size_t n); @@ -136,26 +144,33 @@ class interned_string_iterator { vtr::string_view view_; }; +///@brief == operator inline bool operator==(const interned_string_iterator& lhs, const interned_string_iterator& rhs) { return lhs.internment_ == rhs.internment_ && lhs.num_parts_ == rhs.num_parts_ && lhs.parts_ == rhs.parts_ && lhs.part_idx_ == rhs.part_idx_ && lhs.str_idx_ == rhs.str_idx_ && lhs.view_ == rhs.view_; } +///@brief != operator inline bool operator!=(const interned_string_iterator& lhs, const interned_string_iterator& rhs) { return !(lhs == rhs); } -// A interned_string bound to it's string_internment object. -// -// This object is heavier than just an interned_string. -// This object holds a pointer to interned_string, so its lifetime must be -// shorter than the parent interned_string. +/** + * @brief A interned_string bound to it's string_internment object. + * + * This object is heavier than just an interned_string. + * This object holds a pointer to interned_string, so its lifetime must be + * shorter than the parent interned_string. + */ class bound_interned_string { public: + ///@brief constructor bound_interned_string(const string_internment* internment, const interned_string* str) : internment_(internment) , str_(str) {} + ///@brief return an iterator to the first part of the interned_string interned_string_iterator begin() const; + ///@brief return an iterator to the last part of the interned_string interned_string_iterator end() const; private: @@ -163,13 +178,16 @@ class bound_interned_string { const interned_string* str_; }; -// Interned string value returned from a string_internment object. -// -// This is a value object without allocation. It can be checked for equality -// and hashed safely against other interned_string's generated from the same -// string_internment. +/** + * @brief Interned string value returned from a string_internment object. + * + * This is a value object without allocation. It can be checked for equality + * and hashed safely against other interned_string's generated from the same + * string_internment. + */ class interned_string { public: + ///@brief constructor interned_string(std::array intern_ids, size_t n) { std::fill(storage_.begin(), storage_.end(), 0); set_num_parts(n); @@ -178,29 +196,37 @@ class interned_string { } } - // Copy the underlying string into output. - // - // internment must the object that generated this interned_string. + /** + * @brief Copy the underlying string into output. + * + * internment must the object that generated this interned_string. + */ void get(const string_internment* internment, std::string* output) const; - // Returns the underlying string as a std::string. - // - // This method will allocated memory. + /** + * @brief Returns the underlying string as a std::string. + * + * This method will allocated memory. + */ std::string get(const string_internment* internment) const { std::string result; get(internment, &result); return result; } - // Bind the parent string_internment and return a bound_interned_string - // object. That bound_interned_string lifetime must be shorter than this - // interned_string object lifetime, as bound_interned_string contains - // a reference this object, along with a reference to the internment - // object. + /** + * @brief Bind the parent string_internment and return a bound_interned_string object. + * + * That bound_interned_string lifetime must be shorter than this + * interned_string object lifetime, as bound_interned_string contains + * a reference this object, along with a reference to the internment + * object. + */ bound_interned_string bind(const string_internment* internment) const { return bound_interned_string(internment, this); } + ///@brief begin() function interned_string_iterator begin(const string_internment* internment) const { size_t n = num_parts(); std::array intern_ids; @@ -212,14 +238,18 @@ class interned_string { return interned_string_iterator(internment, intern_ids, n); } + ///@brief end() function interned_string_iterator end() const { return interned_string_iterator(); } + ///@brief == operator friend bool operator==(interned_string lhs, interned_string rhs) noexcept; + ///@brief != operator friend bool operator!=(interned_string lhs, interned_string rhs) noexcept; + ///@brief hash function friend std::hash; friend interned_string_less; @@ -270,39 +300,53 @@ class interned_string { std::array storage_; }; +///@brief == operator inline bool operator==(interned_string lhs, interned_string rhs) noexcept { return lhs.storage_ == rhs.storage_; } + +///@brief != operator inline bool operator!=(interned_string lhs, interned_string rhs) noexcept { return lhs.storage_ != rhs.storage_; } + +///@brief < operator inline bool operator<(bound_interned_string lhs, bound_interned_string rhs) noexcept { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } + +///@brief >= operator inline bool operator>=(bound_interned_string lhs, bound_interned_string rhs) noexcept { return !std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } + +///@brief > operator inline bool operator>(bound_interned_string lhs, bound_interned_string rhs) noexcept { return rhs < lhs; } + +///@brief <= operator inline bool operator<=(bound_interned_string lhs, bound_interned_string rhs) noexcept { return rhs >= lhs; } -// Storage of interned string, and object capable of generating new -// interned_string objects. +/** + * @brief Storage of interned string, and object capable of generating new interned_string objects. + */ class string_internment { public: - // Intern a string, and return a unique identifier to that string. - // - // If interned_string is ever called with two strings of the same value, - // the interned_string will be equal. + /** + * @brief Intern a string, and return a unique identifier to that string. + * + * If interned_string is ever called with two strings of the same value, + * the interned_string will be equal. + */ interned_string intern_string(vtr::string_view view) { size_t num_parts = 1; for (const auto& c : view) { @@ -336,14 +380,17 @@ class string_internment { } } - // Retrieve a string part based on id. This method should not generally - // be called directly. + /** + * @brief Retrieve a string part based on id. + * + * This method should not generally be called directly. + */ vtr::string_view get_string(StringId id) const { auto& str = strings_[id]; return vtr::string_view(str.data(), str.size()); } - // Number of unique string parts stored. + ///@brief Number of unique string parts stored. size_t unique_strings() const { return strings_.size(); } @@ -369,6 +416,11 @@ class string_internment { std::unordered_map string_to_id_; }; +/** + * @brief Copy the underlying string into output. + * + * internment must the object that generated this interned_string. + */ inline void interned_string::get(const string_internment* internment, std::string* output) const { // Implements // kSplitChar.join(interned_string->get_string(id(idx)) for idx in range(num_parts()))); @@ -392,6 +444,12 @@ inline void interned_string::get(const string_internment* internment, std::strin } } +/** + * @brief constructor for interned string iterator. + * + * Do no construct this iterator directly. Use either + * bound_interned_string::begin/end or interned_string;:begin/end. + */ inline interned_string_iterator::interned_string_iterator(const string_internment* internment, std::array intern_ids, size_t n) : internment_(internment) , num_parts_(n) @@ -405,6 +463,7 @@ inline interned_string_iterator::interned_string_iterator(const string_internmen } } +///@brief Increment operator for interned_string_iterator inline interned_string_iterator& interned_string_iterator::operator++() { if (num_parts_ == size_t(-1)) { throw std::out_of_range("Invalid iterator"); @@ -439,6 +498,7 @@ inline interned_string_iterator& interned_string_iterator::operator++() { return *this; } +///@brief Increment operator for interned_string_iterator inline interned_string_iterator interned_string_iterator::operator++(int) { interned_string_iterator prev = *this; ++*this; @@ -446,10 +506,12 @@ inline interned_string_iterator interned_string_iterator::operator++(int) { return prev; } +///@brief return an iterator to the first part of the interned_string inline interned_string_iterator bound_interned_string::begin() const { return str_->begin(internment_); } +///@brief return an iterator to the last part of the interned_string inline interned_string_iterator bound_interned_string::end() const { return interned_string_iterator(); } @@ -461,8 +523,12 @@ inline std::ostream& operator<<(std::ostream& os, bound_interned_string const& v return os; } +/** + * @brief A friend class to interned_string that compares 2 interned_strings + */ class interned_string_less { public: + ///@brief Return true if the first interned string is less than the second one bool operator()(const vtr::interned_string& lhs, const vtr::interned_string& rhs) const { return lhs.storage_ < rhs.storage_; } @@ -471,6 +537,12 @@ class interned_string_less { } // namespace vtr namespace std { +/** + * @brief Hash function for the interned_string + * + * It is defined as a friend function to interned_string class. + * It returns a unique hash for every interned_string. + */ template<> struct hash { std::size_t operator()(vtr::interned_string const& s) const noexcept { diff --git a/libs/libvtrutil/src/vtr_string_view.h b/libs/libvtrutil/src/vtr_string_view.h index 0c9b4d8e91b..12a7a7a446c 100644 --- a/libs/libvtrutil/src/vtr_string_view.h +++ b/libs/libvtrutil/src/vtr_string_view.h @@ -10,33 +10,43 @@ namespace vtr { -// Implements a view to a fixed length string. -// The underlying string does not need to be NULL terminated. +/** + * @brief Implements a view to a fixed length string (similar to std::basic_string_view). + * + * The underlying string does not need to be NULL terminated. + */ class string_view { public: static constexpr size_t npos = size_t(-1); + ///@brief constructor explicit constexpr string_view() : data_(nullptr) , size_(0) {} + + ///@brief constructor explicit string_view(const char* str) : data_(str) , size_(strlen(str)) {} + ///@brief constructor explicit constexpr string_view(const char* str, size_t size) : data_(str) , size_(size) {} constexpr string_view(const string_view& other) noexcept = default; + ///@brief copy constructor constexpr string_view& operator=(const string_view& view) noexcept { data_ = view.data_; size_ = view.size_; return *this; } + ///@brief indexing [] operator (immutable) constexpr char operator[](size_t pos) const { return data_[pos]; } + ///@brief aT() operator (immutable) const char& at(size_t pos) const { if (pos >= size()) { throw std::out_of_range("Pos is out of range."); @@ -45,48 +55,63 @@ class string_view { return data_[pos]; } + ///@brief Returns the first character of the string constexpr const char& front() const { return data_[0]; } + ///@brief Returns the last character of the string constexpr const char& back() const { return data_[size() - 1]; } + ///@brief Returns a pointer to the string data constexpr const char* data() const { return data_; } + ///@brief Returns the string size constexpr size_t size() const noexcept { return size_; } + + ///@brief Returns the string size constexpr size_t length() const noexcept { return size_; } + ///@brief Returns true if empty constexpr bool empty() const noexcept { return size_ == 0; } + ///@brief Returns a pointer to the begin of the string constexpr const char* begin() const noexcept { return data_; } + + ///@brief Same as begin() constexpr const char* cbegin() const noexcept { return data_; } + ///@brief Returns a pointer to the end of the string constexpr const char* end() const noexcept { return data_ + size_; } + + ///@brief Same as end() constexpr const char* cend() const noexcept { return data_ + size_; } + ///@brief Swaps two string views void swap(string_view& v) noexcept { std::swap(data_, v.data_); std::swap(size_, v.size_); } + ///@brief Returns a newly constructed string object with its value initialized to a copy of a substring of this object. string_view substr(size_t pos = 0, size_t count = npos) { if (pos > size()) { throw std::out_of_range("Pos is out of range."); @@ -105,31 +130,43 @@ class string_view { size_t size_; }; +///@brief == operator inline bool operator==(string_view lhs, string_view rhs) noexcept { return lhs.size() == rhs.size() && (lhs.empty() || rhs.empty() || (strncmp(lhs.data(), rhs.data(), std::min(lhs.size(), rhs.size())) == 0)); } + +///@brief != operator inline bool operator!=(string_view lhs, string_view rhs) noexcept { return lhs.size() != rhs.size() || strncmp(lhs.data(), rhs.data(), std::min(lhs.size(), rhs.size())) != 0; } + +///@brief < operator inline bool operator<(string_view lhs, string_view rhs) noexcept { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } + +///brief >= operator inline bool operator>=(string_view lhs, string_view rhs) noexcept { return !std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } + +///@brief > operator inline bool operator>(string_view lhs, string_view rhs) noexcept { return rhs < lhs; } + +///@brief <= operator inline bool operator<=(string_view lhs, string_view rhs) noexcept { return rhs >= lhs; } +///@brief << operator for ostream inline std::ostream& operator<<(std::ostream& os, string_view const& value) { for (const auto& c : value) { os << c; diff --git a/libs/libvtrutil/src/vtr_strong_id.h b/libs/libvtrutil/src/vtr_strong_id.h index abd7de120be..1ce922ab5da 100644 --- a/libs/libvtrutil/src/vtr_strong_id.h +++ b/libs/libvtrutil/src/vtr_strong_id.h @@ -1,9 +1,11 @@ #ifndef VTR_STRONG_ID_H #define VTR_STRONG_ID_H -/* - * This header provides the StrongId class, a template which can be used to - * create strong Id's which avoid accidental type conversions (generating - * compiler errors when they occur). +/** + * @file + * @brief This header provides the StrongId class. + * + * It is template which can be used to create strong Id's + * which avoid accidental type conversions (generating compiler errors when they occur). * * Motivation * ========== @@ -67,9 +69,9 @@ * * The StrongId template class takes one required and three optional template parameters: * - * 1) Tag - the unique type used to identify this type of Ids [Required] - * 2) T - the underlying integral id type (default: int) [Optional] - * 3) T sentinel - a value representing an invalid Id (default: -1) [Optional] + * 1. Tag - the unique type used to identify this type of Ids [Required] + * 2. T - the underlying integral id type (default: int) [Optional] + * 3. T sentinel - a value representing an invalid Id (default: -1) [Optional] * * If no value is supllied during construction the StrongId is initialized to the invalid/sentinel value. * @@ -147,13 +149,16 @@ namespace vtr { -//Forward declare the class (needed for operator declarations) +// Forward declare the class (needed for operator declarations) template class StrongId; -//Forward declare the equality/inequality operators -// We need to do this before the class definition so the class can -// friend them +/* + * Forward declare the equality/inequality operators + * + * We need to do this before the class definition so the class can + * friend them + */ template bool operator==(const StrongId& lhs, const StrongId& rhs); @@ -163,56 +168,63 @@ bool operator!=(const StrongId& lhs, const StrongId bool operator<(const StrongId& lhs, const StrongId& rhs); -//Class template definition with default template parameters +///@brief Class template definition with default template parameters template class StrongId { static_assert(std::is_integral::value, "T must be integral"); public: - //Gets the invalid Id + ///@brief Gets the invalid Id static constexpr StrongId INVALID() { return StrongId(); } - //Default to the sentinel value + ///@brief Default to the sentinel value constexpr StrongId() : id_(sentinel) {} - //Only allow explict constructions from a raw Id (no automatic conversions) + ///@brief Only allow explict constructions from a raw Id (no automatic conversions) explicit constexpr StrongId(T id) : id_(id) {} - //Allow some explicit conversion to useful types + // Allow some explicit conversion to useful types: - //Allow explicit conversion to bool (e.g. if(id)) + ///@brief Allow explicit conversion to bool (e.g. if(id)) explicit operator bool() const { return *this != INVALID(); } - //Allow explicit conversion to size_t (e.g. my_vector[size_t(strong_id)]) + ///@brief Allow explicit conversion to size_t (e.g. my_vector[size_t(strong_id)]) explicit operator std::size_t() const { return static_cast(id_); } - //To enable hasing Ids + ///@brief To enable hasing Ids friend std::hash>; - //To enable comparisions between Ids - // Note that since these are templated functions we provide an empty set of template parameters - // after the function name (i.e. <>) + /** + * @brief To enable comparisions between Ids + * + * Note that since these are templated functions we provide an empty set of template parameters + * after the function name (i.e. <>) + */ friend bool operator== <>(const StrongId& lhs, const StrongId& rhs); + ///@brief != operator friend bool operator!= <>(const StrongId& lhs, const StrongId& rhs); + ///@brief < operator friend bool operator< <>(const StrongId& lhs, const StrongId& rhs); private: T id_; }; +///@brief == operator template bool operator==(const StrongId& lhs, const StrongId& rhs) { return lhs.id_ == rhs.id_; } +///@brief != operator template bool operator!=(const StrongId& lhs, const StrongId& rhs) { return !(lhs == rhs); } -//Needed for std::map-like containers +///@brief operator < Needed for std::map-like containers template bool operator<(const StrongId& lhs, const StrongId& rhs) { return lhs.id_ < rhs.id_; @@ -220,7 +232,7 @@ bool operator<(const StrongId& lhs, const StrongId struct hash> { diff --git a/libs/libvtrutil/src/vtr_strong_id_range.h b/libs/libvtrutil/src/vtr_strong_id_range.h index 6e3e1486014..e9fd938f3d6 100644 --- a/libs/libvtrutil/src/vtr_strong_id_range.h +++ b/libs/libvtrutil/src/vtr_strong_id_range.h @@ -6,26 +6,34 @@ namespace vtr { -/* - * This header defines a utility class for StrongId's. StrongId's are - * described in vtr_strong_id.h. In some cases, StrongId's be considered +/** + * @file + * @brief This header defines a utility class for StrongId's. + * + * StrongId's are described in vtr_strong_id.h. In some cases, StrongId's be considered * like random access iterators, but not all StrongId's have this property. * In addition, there is utility in refering to a range of id's, and being able * to iterator over that range. + */ + +/** + * @brief StrongIdIterator class * * StrongIdIterator allows a StrongId to be treated like a random access * iterator. Whether this is a correct use of the abstraction is up to the * called. * - * StrongIdRange allows a pair of StrongId's to defines a continguous range of - * ids. The "end" StrongId is excluded from this range. */ template class StrongIdIterator { public: + ///@brief constructor StrongIdIterator() = default; + ///@brief copy constructor StrongIdIterator& operator=(const StrongIdIterator& other) = default; + ///@brief copy constructor StrongIdIterator(const StrongIdIterator& other) = default; + ///@brief constructor explicit StrongIdIterator(StrongId id) : id_(id) { VTR_ASSERT(bool(id)); @@ -37,11 +45,13 @@ class StrongIdIterator { using pointer = StrongId*; using difference_type = ssize_t; + ///@brief Dereference operator (*) StrongId& operator*() { VTR_ASSERT_SAFE(bool(id_)); return this->id_; } + ///@brief += operator StrongIdIterator& operator+=(ssize_t n) { VTR_ASSERT_SAFE(bool(id_)); id_ = StrongId(size_t(id_) + n); @@ -49,6 +59,7 @@ class StrongIdIterator { return *this; } + ///@brief -= operator StrongIdIterator& operator-=(ssize_t n) { VTR_ASSERT_SAFE(bool(id_)); id_ = StrongId(size_t(id_) - n); @@ -56,6 +67,7 @@ class StrongIdIterator { return *this; } + ///@brief ++ operator StrongIdIterator& operator++() { VTR_ASSERT_SAFE(bool(id_)); *this += 1; @@ -63,6 +75,7 @@ class StrongIdIterator { return *this; } + ///@brief Decremment operator StrongIdIterator& operator--() { VTR_ASSERT_SAFE(bool(id_)); *this -= 1; @@ -70,10 +83,12 @@ class StrongIdIterator { return *this; } + ///@brief Indexing operator [] StrongId operator[](ssize_t offset) const { return StrongId(size_t(id_) + offset); } + ///@brief + operator template friend StrongIdIterator operator+( const StrongIdIterator& lhs, @@ -83,6 +98,7 @@ class StrongIdIterator { return ret; } + ///@brief - operator template friend StrongIdIterator operator-( const StrongIdIterator& lhs, @@ -92,6 +108,7 @@ class StrongIdIterator { return ret; } + ///@brief ~ operator template friend ssize_t operator-( const StrongIdIterator& lhs, @@ -104,16 +121,19 @@ class StrongIdIterator { return ret; } + ///@brief == operator template friend bool operator==(const StrongIdIterator& lhs, const StrongIdIterator& rhs) { return lhs.id_ == rhs.id_; } + ///@brief != operator template friend bool operator!=(const StrongIdIterator& lhs, const StrongIdIterator& rhs) { return lhs.id_ != rhs.id_; } + ///@brief < operator template friend bool operator<(const StrongIdIterator& lhs, const StrongIdIterator& rhs) { return lhs.id_ < rhs.id_; @@ -123,22 +143,34 @@ class StrongIdIterator { StrongId id_; }; +/** + * @brief StrongIdRange class + * + * StrongIdRange allows a pair of StrongId's to defines a continguous range of + * ids. The "end" StrongId is excluded from this range. + */ template class StrongIdRange { public: + ///@brief constructor StrongIdRange(StrongId b, StrongId e) : begin_(b) , end_(e) { VTR_ASSERT(begin_ < end_ || begin_ == end_); } + + ///@brief Returns a StrongIdIterator to the first strongId in the range StrongIdIterator begin() const { return StrongIdIterator(begin_); } + ///@brief Returns a StrongIdIterator referring to the past-the-end element in the vector container. StrongIdIterator end() const { return StrongIdIterator(end_); } + ///@brief Returns true if the range is empty bool empty() { return begin_ == end_; } + ///@brief Reurns the size of the range size_t size() { return std::distance(begin(), end()); } diff --git a/libs/libvtrutil/src/vtr_time.cpp b/libs/libvtrutil/src/vtr_time.cpp index 89def557455..a557f186735 100644 --- a/libs/libvtrutil/src/vtr_time.cpp +++ b/libs/libvtrutil/src/vtr_time.cpp @@ -7,44 +7,54 @@ namespace vtr { int f_timer_depth = 0; +///@brief Constructor Timer::Timer() : start_(clock::now()) , initial_max_rss_(get_max_rss()) { } +///@brief Returns the elapsed seconds since construction float Timer::elapsed_sec() const { return std::chrono::duration(clock::now() - start_).count(); } +///@brief Returns the maximum resident size (rss) in bytes float Timer::max_rss_mib() const { return get_max_rss() / BYTE_TO_MIB; } +///@brief Returns the change in maximum resident size in bytes float Timer::delta_max_rss_mib() const { return (get_max_rss() - initial_max_rss_) / BYTE_TO_MIB; } +///@brief Constructor ScopedActionTimer::ScopedActionTimer(std::string action_str) : action_(action_str) , depth_(f_timer_depth++) { } +///@brief Destructor ScopedActionTimer::~ScopedActionTimer() { --f_timer_depth; } +///@brief Sets quiet value (when true, prints the timing info) void ScopedActionTimer::quiet(bool value) { quiet_ = value; } +///@brief Returns the quiet value bool ScopedActionTimer::quiet() const { return quiet_; } +///@brief Returns the action string std::string ScopedActionTimer::action() const { return action_; } +///@brief Pads the output string with # if it is not empty std::string ScopedActionTimer::pad() const { if (depth() == 0) { return ""; @@ -52,14 +62,17 @@ std::string ScopedActionTimer::pad() const { return std::string(depth(), '#') + " "; } +///@brief Returns the depth int ScopedActionTimer::depth() const { return depth_; } +///@brief Constructor ScopedFinishTimer::ScopedFinishTimer(std::string action_str) : ScopedActionTimer(action_str) { } +///@brief Destructor ScopedFinishTimer::~ScopedFinishTimer() { if (!quiet()) { vtr::printf_info("%s%s took %.2f seconds (max_rss %.1f MiB)\n", @@ -68,11 +81,13 @@ ScopedFinishTimer::~ScopedFinishTimer() { } } +///@brief Constructor ScopedStartFinishTimer::ScopedStartFinishTimer(std::string action_str) : ScopedActionTimer(action_str) { vtr::printf_info("%s%s\n", pad().c_str(), action().c_str()); } +///@brief Destructor ScopedStartFinishTimer::~ScopedStartFinishTimer() { if (!quiet()) { vtr::printf_info("%s%s took %.2f seconds (max_rss %.1f MiB, delta_rss %+.1f MiB)\n", diff --git a/libs/libvtrutil/src/vtr_time.h b/libs/libvtrutil/src/vtr_time.h index d25ac25c623..2a4d4ec8af0 100644 --- a/libs/libvtrutil/src/vtr_time.h +++ b/libs/libvtrutil/src/vtr_time.h @@ -5,27 +5,27 @@ namespace vtr { -//Class for tracking time elapsed since construction +///@brief Class for tracking time elapsed since construction class Timer { public: Timer(); virtual ~Timer() = default; - //No copy + ///@brief No copy Timer(Timer&) = delete; Timer& operator=(Timer&) = delete; - //No move + ///@brief No move Timer(Timer&&) = delete; Timer& operator=(Timer&&) = delete; - //Return elapsed time in seconds + ///@brief Return elapsed time in seconds float elapsed_sec() const; - //Return peak memory resident set size (in MiB) + ///@brief Return peak memory resident set size (in MiB) float max_rss_mib() const; - //Return change in peak memory resident set size (in MiB) + ///@brief Return change in peak memory resident set size (in MiB) float delta_max_rss_mib() const; private: @@ -36,6 +36,7 @@ class Timer { constexpr static float BYTE_TO_MIB = 1024 * 1024; }; +///@brief Scoped time class which prints the time elapsed for the specifid action class ScopedActionTimer : public Timer { public: ScopedActionTimer(const std::string action); @@ -55,36 +56,39 @@ class ScopedActionTimer : public Timer { int depth_; }; -//Scoped elapsed time class which prints the time elapsed for -//the specified action when it is destructed. -// -//For example: -// -// { -// vtr::ScopedFinishTimer timer("my_action"); -// -// //Do other work -// -// //Will print: 'my_action took X.XX seconds' when out-of-scope -// } +/** + * @brief Scoped elapsed time class which prints the time elapsed for the specified action when it is destructed. + * + * For example: + * + * { + * vtr::ScopedFinishTimer timer("my_action"); + * + * //Do other work + * + * //Will print: 'my_action took X.XX seconds' when out-of-scope + * } + */ class ScopedFinishTimer : public ScopedActionTimer { public: ScopedFinishTimer(const std::string action); ~ScopedFinishTimer(); }; -//Scoped elapsed time class which prints out the action when -//initialized and again both the action and elapsed time -//when destructed. -//For example: -// -// { -// vtr::ScopedStartFinishTimer timer("my_action") //Will print: 'my_action' -// -// //Do other work -// -// //Will print 'my_action took X.XX seconds' when out of scope -// } +/** + * @brief Scoped elapsed time class which prints out the action when initialized and again both the action and elapsed time + * + * when destructed. + * For example: + * + * { + * vtr::ScopedStartFinishTimer timer("my_action") //Will print: 'my_action' + * + * //Do other work + * + * //Will print 'my_action took X.XX seconds' when out of scope + * } + */ class ScopedStartFinishTimer : public ScopedActionTimer { public: ScopedStartFinishTimer(const std::string action); diff --git a/libs/libvtrutil/src/vtr_token.cpp b/libs/libvtrutil/src/vtr_token.cpp index 0be69eb507f..1715e9f2381 100644 --- a/libs/libvtrutil/src/vtr_token.cpp +++ b/libs/libvtrutil/src/vtr_token.cpp @@ -17,7 +17,7 @@ enum e_token_type GetTokenTypeFromChar(const enum e_token_type cur_token_type, bool IsWhitespace(char c); -/* Returns true if character is whatspace between tokens */ +///@brief Returns true if character is whatspace between tokens bool IsWhitespace(char c) { switch (c) { case ' ': @@ -30,7 +30,7 @@ bool IsWhitespace(char c) { } } -/* Returns a token list of the text for a given string. */ +///@brief Returns a token list of the text for a given string. t_token* GetTokensFromString(const char* inString, int* num_tokens) { const char* cur; t_token* tokens; @@ -104,6 +104,7 @@ t_token* GetTokensFromString(const char* inString, int* num_tokens) { return tokens; } +///@brief Free (tokens) void freeTokens(t_token* tokens, const int num_tokens) { int i; for (i = 0; i < num_tokens; i++) { @@ -112,6 +113,7 @@ void freeTokens(t_token* tokens, const int num_tokens) { free(tokens); } +///@brief Returns a token type of the given char enum e_token_type GetTokenTypeFromChar(const enum e_token_type cur_token_type, const char cur) { if (IsWhitespace(cur)) { @@ -137,6 +139,7 @@ enum e_token_type GetTokenTypeFromChar(const enum e_token_type cur_token_type, } } +///@brief Returns true if the token's type equals to token_type bool checkTokenType(const t_token token, enum e_token_type token_type) { if (token.type != token_type) { return false; @@ -144,6 +147,7 @@ bool checkTokenType(const t_token token, enum e_token_type token_type) { return true; } +///@brief Returns a 2D array representing the atof result of all the input string entries seperated by whitespace void my_atof_2D(float** matrix, const int max_i, const int max_j, const char* instring) { int i, j; char *cur, *cur2, *copy, *final; @@ -185,10 +189,12 @@ void my_atof_2D(float** matrix, const int max_i, const int max_j, const char* in } /* Date:July 2nd, 2013 * - * Author: Daniel Chen * - * Purpose: Checks if the number of entries (separated by whitespace) * - * matches the the expected number (max_i * max_j), * - * can be used before calling my_atof_2D */ + * Author: Daniel Chen */ +/** + * @brief Checks if the number of entries (separated by whitespace) matches the the expected number (max_i * max_j) + * + * can be used before calling my_atof_2D + */ bool check_my_atof_2D(const int max_i, const int max_j, const char* instring, int* num_entries) { /* Check if max_i * max_j matches number of entries in instring */ const char* cur = instring; diff --git a/libs/libvtrutil/src/vtr_token.h b/libs/libvtrutil/src/vtr_token.h index 22d0e3afa7c..9556d6614ad 100644 --- a/libs/libvtrutil/src/vtr_token.h +++ b/libs/libvtrutil/src/vtr_token.h @@ -1,12 +1,14 @@ /** - * Jason Luu - * July 22, 2009 - * Tokenizer + * @file + * @author Jason Luu + * @Date July 22, 2009 + * @brief Tokenizer */ #ifndef TOKEN_H #define TOKEN_H +///@brief Token types enum e_token_type { TOKEN_NULL, TOKEN_STRING, @@ -19,6 +21,7 @@ enum e_token_type { TOKEN_DOT }; +///@brief Token structure struct t_token { enum e_token_type type; char* data; diff --git a/libs/libvtrutil/src/vtr_util.cpp b/libs/libvtrutil/src/vtr_util.cpp index d02155fa399..abf54158522 100644 --- a/libs/libvtrutil/src/vtr_util.cpp +++ b/libs/libvtrutil/src/vtr_util.cpp @@ -20,8 +20,11 @@ std::string out_file_prefix; /* used by fopen */ static int file_line_number = 0; /* file in line number being parsed (used by fgets) */ static int cont; /* line continued? (used by strtok)*/ -//Splits the string 'text' along the specified delimiter characters in 'delims' -//The split strings (excluding the delimiters) are returned +/** + * @brief Splits the c-style string 'text' along the specified delimiter characters in 'delims' + * + * The split strings (excluding the delimiters) are returned + */ std::vector split(const char* text, const std::string delims) { if (text) { std::string text_str(text); @@ -30,6 +33,11 @@ std::vector split(const char* text, const std::string delims) { return std::vector(); } +/** + * @brief Splits the string 'text' along the specified delimiter characters in 'delims' + * + * The split strings (excluding the delimiters) are returned + */ std::vector split(const std::string& text, const std::string delims) { std::vector tokens; @@ -62,6 +70,7 @@ std::vector split(const std::string& text, const std::string delims return tokens; } +///@brief Returns 'input' with the first instance of 'search' replaced with 'replace' std::string replace_first(const std::string& input, const std::string& search, const std::string& replace) { auto pos = input.find(search); @@ -72,6 +81,7 @@ std::string replace_first(const std::string& input, const std::string& search, c return output; } +///@brief Returns 'input' with all instances of 'search' replaced with 'replace' std::string replace_all(const std::string& input, const std::string& search, const std::string& replace) { std::string output; @@ -90,12 +100,12 @@ std::string replace_all(const std::string& input, const std::string& search, con return output; } -//Retruns true if str starts with prefix +///@brief Retruns true if str starts with prefix bool starts_with(std::string str, std::string prefix) { return str.find(prefix) == 0; } -//Returns a std::string formatted using a printf-style format string +///@brief Returns a std::string formatted using a printf-style format string std::string string_fmt(const char* fmt, ...) { // Make a variable argument list va_list va_args; @@ -112,8 +122,7 @@ std::string string_fmt(const char* fmt, ...) { return str; } -//Returns a std::string formatted using a printf-style format string taking -//an explicit va_list +///@brief Returns a std::string formatted using a printf-style format string taking an explicit va_list std::string vstring_fmt(const char* fmt, va_list args) { // We need to copy the args so we don't change them before the true formating va_list va_args_copy; @@ -143,8 +152,7 @@ std::string vstring_fmt(const char* fmt, va_list args) { return std::string(buf.get(), len); } -/* An alternate for strncpy since strncpy doesn't work as most - * people would expect. This ensures null termination */ +///@brief An alternate for strncpy since strncpy doesn't work as most people would expect. This ensures null termination char* strncpy(char* dest, const char* src, size_t size) { /* Find string's length */ size_t len = std::strlen(src); @@ -162,6 +170,12 @@ char* strncpy(char* dest, const char* src, size_t size) { return dest; } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ char* strdup(const char* str) { if (str == nullptr) { return nullptr; @@ -173,6 +187,12 @@ char* strdup(const char* str) { ; } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ template T atoT(const std::string& value, const std::string& type_name) { //The c version of atof doesn't catch errors. @@ -193,32 +213,58 @@ T atoT(const std::string& value, const std::string& type_name) { return val; } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ int atoi(const std::string& value) { return atoT(value, "int"); } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ double atod(const std::string& value) { return atoT(value, "double"); } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ float atof(const std::string& value) { return atoT(value, "float"); } +/** + * @brief Legacy c-style function replacements. + * + * Typically these add extra error checking + * and/or correct 'unexpected' behaviour of the standard c-functions + */ unsigned atou(const std::string& value) { return atoT(value, "unsigned int"); } +/** + * @brief Get next token, and wrap to next line if \ at end of line. + * + * There is a bit of a "gotcha" in strtok. It does not make a * + * copy of the character array which you pass by pointer on the + * first call. Thus, you must make sure this array exists for + * as long as you are using strtok to parse that line. Don't + * use local buffers in a bunch of subroutines calling each + * other; the local buffer may be overwritten when the stack is + * restored after return from the subroutine. + */ char* strtok(char* ptr, const char* tokens, FILE* fp, char* buf) { - /* Get next token, and wrap to next line if \ at end of line. * - * There is a bit of a "gotcha" in strtok. It does not make a * - * copy of the character array which you pass by pointer on the * - * first call. Thus, you must make sure this array exists for * - * as long as you are using strtok to parse that line. Don't * - * use local buffers in a bunch of subroutines calling each * - * other; the local buffer may be overwritten when the stack is * - * restored after return from the subroutine. */ - char* val; val = std::strtok(ptr, tokens); @@ -234,6 +280,7 @@ char* strtok(char* ptr, const char* tokens, FILE* fp, char* buf) { } } +///@brief The legacy fopen function with extra error checking FILE* fopen(const char* fname, const char* flag) { FILE* fp; size_t Len; @@ -263,18 +310,21 @@ FILE* fopen(const char* fname, const char* flag) { return (fp); } +///@brief The legacy fclose function int fclose(FILE* f) { return std::fclose(f); } +/** + * @brief Get an input line, update the line number and cut off any comment part. + * + * A \ at the end of a line with no comment part (#) means continue. + * vtr::fgets should give + * identical results for Windows (\r\n) and Linux (\n) + * newlines, since it replaces each carriage return \r + * by a newline character \n. Returns NULL after EOF. + */ char* fgets(char* buf, int max_size, FILE* fp) { - /* Get an input line, update the line number and cut off * - * any comment part. A \ at the end of a line with no * - * comment part (#) means continue. vtr::fgets should give * - * identical results for Windows (\r\n) and Linux (\n) * - * newlines, since it replaces each carriage return \r * - * by a newline character \n. Returns NULL after EOF. */ - int ch; int i; @@ -324,9 +374,7 @@ char* fgets(char* buf, int max_size, FILE* fp) { return nullptr; } -/* - * Returns line number of last opened and read file - */ +///@brief Returns line number of last opened and read file int get_file_line_number_of_last_opened_file() { return file_line_number; } @@ -347,16 +395,15 @@ bool file_exists(const char* filename) { } /* Date:July 17th, 2013 - * Author: Daniel Chen - * Purpose: Checks the file extension of an file to ensure - * correct file format. Returns true if format is - * correct, and false otherwise. - * Note: This is probably a fragile check, but at least - * should prevent common problems such as swapping - * architecture file and blif file on the VPR - * command line. + * Author: Daniel Chen */ +/** + * @brief Checks the file extension of an file to ensure correct file format. + * + * Returns true if format is correct, and false otherwise. + * @note This is probably a fragile check, but at least should + * prevent common problems such as swapping architecture file + * and blif file on the VPR command line. */ - bool check_file_name_extension(const char* file_name, const char* file_extension) { const char* str; @@ -371,6 +418,9 @@ bool check_file_name_extension(const char* file_name, return true; } +/** + * @brief Legacy ReadLine Tokening + */ std::vector ReadLineTokens(FILE* InFile, int* LineNum) { std::unique_ptr buf(new char[vtr::bufsize]); @@ -381,6 +431,7 @@ std::vector ReadLineTokens(FILE* InFile, int* LineNum) { return vtr::split(line); } +///@brief Returns pid if os is unix, -1 otherwise. int get_pid() { #if defined(__unix__) return getpid(); diff --git a/libs/libvtrutil/src/vtr_util.h b/libs/libvtrutil/src/vtr_util.h index eebd43d4b89..e094758c37b 100644 --- a/libs/libvtrutil/src/vtr_util.h +++ b/libs/libvtrutil/src/vtr_util.h @@ -9,30 +9,35 @@ namespace vtr { -//Splits the string 'text' along the specified delimiter characters in 'delims' -//The split strings (excluding the delimiters) are returned +/** + * @brief Splits the string 'text' along the specified delimiter characters in 'delims' + * + * The split strings (excluding the delimiters) are returned + */ std::vector split(const char* text, const std::string delims = " \t\n"); std::vector split(const std::string& text, const std::string delims = " \t\n"); -//Returns 'input' with the first instance of 'search' replaced with 'replace' +///@brief Returns 'input' with the first instance of 'search' replaced with 'replace' std::string replace_first(const std::string& input, const std::string& search, const std::string& replace); -//Returns 'input' with all instances of 'search' replaced with 'replace' +///@brief Returns 'input' with all instances of 'search' replaced with 'replace' std::string replace_all(const std::string& input, const std::string& search, const std::string& replace); -//Retruns true if str starts with prefix +///@brief Retruns true if str starts with prefix bool starts_with(std::string str, std::string prefix); -//Returns a std::string formatted using a printf-style format string +///@brief Returns a std::string formatted using a printf-style format string std::string string_fmt(const char* fmt, ...); -//Returns a std::string formatted using a printf-style format string taking -//an explicit va_list +///@brief Returns a std::string formatted using a printf-style format string taking an explicit va_list std::string vstring_fmt(const char* fmt, va_list args); -//Joins a sequence by a specified delimeter -// For example the sequence {"home", "user", "my_files", "test.blif"} with delim="/" -// would return "home/user/my_files/test.blif" +/** + * @brief Joins a sequence by a specified delimeter + * + * For example the sequence {"home", "user", "my_files", "test.blif"} with delim="/" + * would return "home/user/my_files/test.blif" + */ template std::string join(Iter begin, Iter end, std::string delim); @@ -45,10 +50,6 @@ std::string join(std::initializer_list list, std::string delim); template void uniquify(Container container); -/* - * Legacy c-style function replacements, typically these add extra error checking - * and/or correct 'unexpected' behaviour of the standard c-functions - */ constexpr size_t bufsize = 32768; /* Maximum line length for various parsing proc. */ char* strncpy(char* dest, const char* src, size_t size); char* strdup(const char* str); @@ -62,8 +63,8 @@ unsigned atou(const std::string& value); float atof(const std::string& value); double atod(const std::string& value); -/* - * File utilities +/** + * @brief File utilities */ int get_file_line_number_of_last_opened_file(); bool file_exists(const char* filename); @@ -72,13 +73,13 @@ bool check_file_name_extension(const char* file_name, extern std::string out_file_prefix; -/* - * Legacy ReadLine Tokening +/** + * @brief Legacy ReadLine Tokening */ std::vector ReadLineTokens(FILE* InFile, int* LineNum); -/* - * Template implementations +/** + * @brief Template join function implementation */ template std::string join(Iter begin, Iter end, std::string delim) { @@ -102,6 +103,11 @@ std::string join(std::initializer_list list, std::string delim) { return join(list.begin(), list.end(), delim); } +/** + * @brief Template uniquify function implementation + * + * Removes repeated elements in the container + */ template void uniquify(Container container) { std::sort(container.begin(), container.end()); diff --git a/libs/libvtrutil/src/vtr_vec_id_set.h b/libs/libvtrutil/src/vtr_vec_id_set.h index 9e0a1f0802e..7207225932c 100644 --- a/libs/libvtrutil/src/vtr_vec_id_set.h +++ b/libs/libvtrutil/src/vtr_vec_id_set.h @@ -5,8 +5,10 @@ namespace vtr { -/* - * Implements a set-like interface which supports: +/** + * @brief Implements a set-like interface which supports multiple operations + * + * The supported operations are: * - insertion * - iteration * - membership test @@ -27,12 +29,17 @@ class vec_id_set { typedef typename std::vector::const_iterator const_iterator; typedef const_iterator iterator; + ///@brief Returns an iterator to the first element in the sequence auto begin() const { return vec_.begin(); } + ///@brief Returns an iterator referring to the past-the-end element in the vector container auto end() const { return vec_.end(); } + ///@brief Returns a constant iterator to the first element in the sequence auto cbegin() const { return vec_.cbegin(); } + ///@brief Returns a constant iterator referring to the past-the-end element in the vector container auto cend() const { return vec_.cend(); } + ///@brief Insert val in the set bool insert(T val) { if (count(val)) { //Already inserted return false; @@ -51,6 +58,7 @@ class vec_id_set { return true; } + ///@brief Iterators specifying a range of elements. Copies of the elements in the range [first,last) are inserted in the container. template void insert(Iter first, Iter last) { size_t nelem = std::distance(first, last); @@ -62,6 +70,7 @@ class vec_id_set { } } + ///@brief Count elements with a specific value size_t count(T val) const { if (size_t(val) < contained_.size()) { //Value is with-in range of previously inserted @@ -71,14 +80,17 @@ class vec_id_set { return 0; } + ///@brief Returns the size of the container size_t size() const { return vec_.size(); } + ///@brief Sort elements in the container void sort() { std::sort(vec_.begin(), vec_.end()); } + ///@bried Clears the container void clear() { vec_.clear(); contained_.clear(); diff --git a/libs/libvtrutil/src/vtr_vector.h b/libs/libvtrutil/src/vtr_vector.h index 64f6ab319cc..dc8b689afd8 100644 --- a/libs/libvtrutil/src/vtr_vector.h +++ b/libs/libvtrutil/src/vtr_vector.h @@ -7,14 +7,44 @@ namespace vtr { -//A std::vector container which is indexed by K (instead of size_t). -// -//The main use of this container is to behave like a std::vector which is -//indexed by a vtr::StrongId. It assumes that K is explicitly convertable to size_t -//(i.e. via operator size_t()), and can be explicitly constructed from a size_t. -// -//If you need more std::map-like (instead of std::vector-like) behaviour see -//vtr::vector_map. +/** + * @brief A std::vector container which is indexed by K (instead of size_t). + * + * The main use of this container is to behave like a std::vector which is + * indexed by a vtr::StrongId. It assumes that K is explicitly convertable to size_t + * (i.e. via operator size_t()), and can be explicitly constructed from a size_t. + * + * It includes all the following std::vector functions: + * - begin + * - cbegin + * - cend + * - crbegin + * - crend + * - end + * - rbegin + * - rend + * - capacity + * - empty + * - max_size + * - reserve + * - resize + * - shrink_to_fit + * - size + * - back + * - front + * - assign + * - clear + * - emplace + * - emplace_back + * - erase + * - get_allocator + * - insert + * - pop_back + * - push_back + * + * If you need more std::map-like (instead of std::vector-like) behaviour see + * vtr::vector_map. + */ template> class vector : private std::vector { using storage = std::vector; @@ -73,76 +103,99 @@ class vector : private std::vector { using storage::pop_back; using storage::push_back; - //We can't using-forward storage::data, as it might not exist - //in the particular specialization (typically: vector) - //causing compiler complains. - //Instead, implement it as inline forwarding method whose - //compilation is deferred to when it is actually requested. + /* + * We can't using-forward storage::data, as it might not exist + * in the particular specialization (typically: vector) + * causing compiler complains. + * Instead, implement it as inline forwarding method whose + * compilation is deferred to when it is actually requested. + */ + ///@brief Returns a pointer to the vector's data inline V* data() { return storage::data(); } + ///@brief Returns a pointer to the vector's data (immutable) inline const V* data() const { return storage::data(); } - //Don't include operator[] and at() from std::vector, - //since we redine them to take key_type instead of size_t + /* + * Don't include operator[] and at() from std::vector, + * + * since we redine them to take key_type instead of size_t + */ + ///@brief [] operator reference operator[](const key_type id) { auto i = size_t(id); return storage::operator[](i); } + ///@brief [] operator immutable const_reference operator[](const key_type id) const { auto i = size_t(id); return storage::operator[](i); } + ///@brief at() operator reference at(const key_type id) { auto i = size_t(id); return storage::at(i); } + ///@brief at() operator immutable const_reference at(const key_type id) const { auto i = size_t(id); return storage::at(i); } - //We must re-define swap to avoid inaccessible base class - //errors + // We must re-define swap to avoid inaccessible base class errors + ///@brief swap function void swap(vector& other) { std::swap(*this, other); } - //Returns a range containing the keys + ///@brief Returns a range containing the keys key_range keys() const { return vtr::make_range(key_begin(), key_end()); } public: - //Iterator class which is convertable to the key_type - //This allows end-users to call the parent class's keys() member - //to iterate through the keys with a range-based for loop + /** + * @brief Iterator class which is convertable to the key_type + * + * This allows end-users to call the parent class's keys() member + * to iterate through the keys with a range-based for loop + */ class key_iterator : public std::iterator { public: - //We use the intermediate type my_iter to avoid a potential ambiguity for which - //clang generates errors and warnings + ///@brief We use the intermediate type my_iter to avoid a potential ambiguity for which clang generates errors and warnings using my_iter = typename std::iterator; using typename my_iter::iterator; using typename my_iter::pointer; using typename my_iter::reference; using typename my_iter::value_type; + ///@brief constructor key_iterator(key_iterator::value_type init) : value_(init) {} - //vtr::vector assumes that the key time is convertable to size_t and - //that all the underlying IDs are zero-based and contiguous. That means - //we can just increment the underlying Id to build the next key. + /* + * vtr::vector assumes that the key time is convertable to size_t. + * + * It also assumes all the underlying IDs are zero-based and contiguous. That means + * we can just increment the underlying Id to build the next key. + */ + ///@brief ++ operator key_iterator operator++() { value_ = value_type(size_t(value_) + 1); return *this; } + ///@brief decrement operator key_iterator operator--() { value_ = value_type(size_t(value_) - 1); return *this; } + ///@brief dereference oeprator reference operator*() { return value_; } + ///@brief -> operator pointer operator->() { return &value_; } + ///@brief == operator friend bool operator==(const key_iterator lhs, const key_iterator rhs) { return lhs.value_ == rhs.value_; } + ///@brief != operator friend bool operator!=(const key_iterator lhs, const key_iterator rhs) { return !(lhs == rhs); } private: diff --git a/libs/libvtrutil/src/vtr_vector_map.h b/libs/libvtrutil/src/vtr_vector_map.h index d86988dff2c..fbb19152639 100644 --- a/libs/libvtrutil/src/vtr_vector_map.h +++ b/libs/libvtrutil/src/vtr_vector_map.h @@ -7,36 +7,38 @@ namespace vtr { -//A vector-like container which is indexed by K (instead of size_t as in std::vector). -// -//The main use of this container is to behave like a std::vector which is indexed by -//vtr::StrongId. -// -//Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and -//that the conversion results in a linearly increasing index into the underlying vector. -// -//This results in a container that is somewhat similar to a std::map (i.e. converts from one -//type to another), but requires contiguously ascending (i.e. linear) keys. Unlike std::map -//only the values are stored (at the specified index/key), reducing memory usage and improving -//cache locality. Furthermore, operator[] and find() return the value or iterator directly -//associated with the value (like std::vector) rather than a std::pair (like std::map). -//insert() takes both the key and value as separate arguments and has no return value. -// -//Additionally, vector_map will silently create values for 'gaps' in the index range (i.e. -//those elements are initialized with Sentinel::INVALID()). -// -//If you need a fully featured std::map like container without the above differences see -//vtr::linear_map. -// -//If you do not need std::map-like features see vtr::vector. -// -//Note that it is possible to use vector_map with sparse/non-contiguous keys, but this is typically -//memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1], -//where max_key is the largest key that has been inserted. -// -//As with a std::vector, it is the caller's responsibility to ensure there is sufficient space -//when a given index/key before it is accessed. The exception to this are the find(), insert() and -//update() methods which handle non-existing keys gracefully. +/** + * @brief A vector-like container which is indexed by K (instead of size_t as in std::vector). + * + * The main use of this container is to behave like a std::vector which is indexed by + * vtr::StrongId. + * + * Requires that K be convertable to size_t with the size_t operator (i.e. size_t()), and + * that the conversion results in a linearly increasing index into the underlying vector. + * + * This results in a container that is somewhat similar to a std::map (i.e. converts from one + * type to another), but requires contiguously ascending (i.e. linear) keys. Unlike std::map + * only the values are stored (at the specified index/key), reducing memory usage and improving + * cache locality. Furthermore, operator[] and find() return the value or iterator directly + * associated with the value (like std::vector) rather than a std::pair (like std::map). + * insert() takes both the key and value as separate arguments and has no return value. + * + * Additionally, vector_map will silently create values for 'gaps' in the index range (i.e. + * those elements are initialized with Sentinel::INVALID()). + * + * If you need a fully featured std::map like container without the above differences see + * vtr::linear_map. + * + * If you do not need std::map-like features see vtr::vector. + * + * Note that it is possible to use vector_map with sparse/non-contiguous keys, but this is typically + * memory inefficient as the underlying vector will allocate space for [0..size_t(max_key)-1], + * where max_key is the largest key that has been inserted. + * + * As with a std::vector, it is the caller's responsibility to ensure there is sufficient space + * when a given index/key before it is accessed. The exception to this are the find(), insert() and + * update() methods which handle non-existing keys gracefully. + */ template> class vector_map { public: //Public types @@ -47,30 +49,39 @@ class vector_map { typedef typename std::vector::const_iterator const_iterator; typedef typename std::vector::const_reverse_iterator const_reverse_iterator; - public: //Constructor + public: + ///@brief Constructor template vector_map(Args&&... args) : vec_(std::forward(args)...) {} public: //Accessors - //Iterators + ///@brief Returns an iterator referring to the first element in the map container. const_iterator begin() const { return vec_.begin(); } + ///@brief Returns an iterator referring to the past-the-end element in the map container. const_iterator end() const { return vec_.end(); } + ///@begin Returns a reverse iterator pointing to the last element in the container (i.e., its reverse beginning). const_reverse_iterator rbegin() const { return vec_.rbegin(); } + ///@brief Returns a reverse iterator pointing to the theoretical element right before the first element in the map container (which is considered its reverse end). const_reverse_iterator rend() const { return vec_.rend(); } //Indexing + ///@brief [] operator immutable const_reference operator[](const K n) const { size_t index = size_t(n); - // Shouldn't check for index >= 0, since size_t is unsigned thus won't be negative - // A negative input to n would result in an absurdly large number close the maximum size of size_t, and be caught by index < vec_.size() - // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf chapter 4.7 para 2 + /** + * Shouldn't check for index >= 0, since size_t is unsigned thus won't be negative + * + * A negative input to n would result in an absurdly large number close the maximum size of size_t, and be caught by index < vec_.size() + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf chapter 4.7 para 2 + */ VTR_ASSERT_SAFE_MSG(index < vec_.size(), "Out-of-range index"); return vec_[index]; } + ///@brief Searches the container for an element with a key equivalent to k and returns an iterator to it if found, otherwise it returns an iterator to vector_map::end. const_iterator find(const K key) const { if (size_t(key) < vec_.size()) { return vec_.begin() + size_t(key); @@ -79,40 +90,51 @@ class vector_map { } } + ///@brief Returns the number of elements in the container. std::size_t size() const { return vec_.size(); } + ///@brief Returns true if the container is empty bool empty() const { return vec_.empty(); } + ///@brief Returns true if the container contains key bool contains(const K key) const { return size_t(key) < vec_.size(); } + ///@brief Returns 1 if the container contains key, 0 otherwise size_t count(const K key) const { return contains(key) ? 1 : 0; } public: //Mutators - //Delegate potentially overloaded functions to the underlying vector with perfect - //forwarding + // Delegate potentially overloaded functions to the underlying vector with perfect forwarding + ///@brief push_back function template void push_back(Args&&... args) { vec_.push_back(std::forward(args)...); } + ///@brief emplace_back function template void emplace_back(Args&&... args) { vec_.emplace_back(std::forward(args)...); } + ///@brief resize function template void resize(Args&&... args) { vec_.resize(std::forward(args)...); } + ///@brief clears the container void clear() { vec_.clear(); } + ///@brief Returns the capacity of the container size_t capacity() const { return vec_.capacity(); } + ///@brief Requests the container to reduce its capacity to fit its size. void shrink_to_fit() { vec_.shrink_to_fit(); } - //Iterators + ///@brief Returns an iterator referring to the first element in the map container. iterator begin() { return vec_.begin(); } + ///@brief Returns an iterator referring to the past-the-end element in the map container. iterator end() { return vec_.end(); } - //Indexing + ///@brief Indexing reference operator[](const K n) { VTR_ASSERT_SAFE_MSG(size_t(n) < vec_.size(), "Out-of-range index"); return vec_[size_t(n)]; } + ///@brief Returns an iterator to the first element in the container that compares equal to val. If no such element is found, the function returns end(). iterator find(const K key) { if (size_t(key) < vec_.size()) { return vec_.begin() + size_t(key); @@ -121,6 +143,7 @@ class vector_map { } } + ///@brief Extends the container by inserting new elements, effectively increasing the container size by the number of elements inserted. void insert(const K key, const V value) { if (size_t(key) >= vec_.size()) { //Resize so key is in range @@ -131,9 +154,10 @@ class vector_map { operator[](key) = value; } + ///@brief Inserts the new key value pair in the container void update(const K key, const V value) { insert(key, value); } - //Swap (this enables std::swap via ADL) + ///@brief Swap (this enables std::swap via ADL) friend void swap(vector_map& x, vector_map& y) { std::swap(x.vec_, y.vec_); }