From 2ff758047ac12abf90dfef1d604bf6070704cab3 Mon Sep 17 00:00:00 2001 From: Jessica James Date: Thu, 19 Jan 2017 03:17:15 -0500 Subject: [PATCH] Replaced all usage of SLList with std::forward_list. Fixed an infinite recursion bug in merge_sort_parallel and renamed merge_sort_internal to merge_sort_direct. --- Jupiter/Algorithm.h | 30 +++++----- Jupiter/Hash_Table.h | 11 ++-- Jupiter/Hash_Table_Imp.h | 122 +++++++++++++++++++++++++-------------- Jupiter/INIConfig.cpp | 16 ++--- 4 files changed, 112 insertions(+), 67 deletions(-) diff --git a/Jupiter/Algorithm.h b/Jupiter/Algorithm.h index 0036f61..7cf66ec 100644 --- a/Jupiter/Algorithm.h +++ b/Jupiter/Algorithm.h @@ -62,11 +62,15 @@ namespace Jupiter */ template void merge_sort_serial(T *in_data, size_t in_data_length); - /** Internal helper templates */ - namespace Internal - { - template void merge_sort_internal(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads); - } + /** + * @brief Sorts an array of data in-place using merge sort across the specified number of threads + * + * @param in_source Data to sort + * @param in_length Length of the array of data to sort + * @param out_buffer Working array for sorting; must be the same size as in_source + * @param unused_threads Number of additional threads to spawn (not including the thread calling the function) + */ + template void merge_sort_direct(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads); } } @@ -82,7 +86,7 @@ template void Jupiter::Algorithm::merge_sort(T *in_data, size_t in_d template void Jupiter::Algorithm::merge_sort_parallel(T *in_data, size_t in_data_length) { - merge_sort_parallel(in_data, in_data_length); + merge_sort_parallel(in_data, in_data_length, std::thread::hardware_concurrency()); } template void Jupiter::Algorithm::merge_sort_parallel(T *in_data, size_t in_data_length, unsigned int in_max_threads, bool in_force_max_threads) @@ -107,7 +111,7 @@ template void Jupiter::Algorithm::merge_sort_parallel(T *in_data, si buffer[index] = in_data[index]; // mergesort into buffer - Internal::merge_sort_internal(in_data, in_data_length, buffer, thread_count - 1); + merge_sort_direct(in_data, in_data_length, buffer, thread_count - 1); // mergesort is complete; free buffer delete[] buffer; @@ -125,7 +129,7 @@ template void Jupiter::Algorithm::merge_sort_serial(T *in_data, size buffer[index] = in_data[index]; // mergesort into buffer - Internal::merge_sort_internal(in_data, in_data_length, buffer, 0); + merge_sort_direct(in_data, in_data_length, buffer, 0); // mergesort is complete; free buffer delete[] buffer; @@ -133,7 +137,7 @@ template void Jupiter::Algorithm::merge_sort_serial(T *in_data, size /** Internals */ -template void Jupiter::Algorithm::Internal::merge_sort_internal(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads) +template void Jupiter::Algorithm::merge_sort_direct(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads) { if (in_length <= 1) // Nothing to sort return; @@ -149,10 +153,10 @@ template void Jupiter::Algorithm::Internal::merge_sort_internal(T *i if (unused_threads == 0) // serial { // sort left - merge_sort_internal(left_buffer, left_length, in_source, 0); + merge_sort_direct(left_buffer, left_length, in_source, 0); // sort right - merge_sort_internal(right_buffer, right_length, in_source + left_length, 0); + merge_sort_direct(right_buffer, right_length, in_source + left_length, 0); } else // parallel { @@ -161,10 +165,10 @@ template void Jupiter::Algorithm::Internal::merge_sort_internal(T *i unsigned int left_thread_count = unused_threads / 2; // sort left - std::thread left_sort_thread(merge_sort_internal, left_buffer, left_length, in_source, left_thread_count); + std::thread left_sort_thread(merge_sort_direct, left_buffer, left_length, in_source, left_thread_count); // sort right - merge_sort_internal(right_buffer, right_length, in_source + left_length, unused_threads - left_thread_count); + merge_sort_direct(right_buffer, right_length, in_source + left_length, unused_threads - left_thread_count); left_sort_thread.join(); } diff --git a/Jupiter/Hash_Table.h b/Jupiter/Hash_Table.h index 5314cc8..23126c4 100644 --- a/Jupiter/Hash_Table.h +++ b/Jupiter/Hash_Table.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2016 Jessica James. + * Copyright (C) 2016-2017 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,8 +24,8 @@ * @brief Defines a generic hash table structure */ +#include #include "String.h" -#include "SLList.h" namespace Jupiter { @@ -69,7 +69,8 @@ namespace Jupiter * @param in_key Key of the entry to search for * @return Pointer to the value of the entry if it exists, nullptr otherwise */ - ValueT *get(const InKeyT &in_key) const; + const ValueT *get(const InKeyT &in_key) const; + ValueT *get(const InKeyT &in_key); const InValueT &get(const InKeyT &in_key, const InValueT &in_value) const; template CastT getCast(const InKeyT &in_key, const CastT &in_value) const; @@ -99,6 +100,7 @@ namespace Jupiter * @param in_callback Function to callback */ template void callback(CallT &in_callback) const; + template void callback(CallT &in_callback); /** * @brief Copy assignment operator @@ -137,7 +139,7 @@ namespace Jupiter ~Bucket(); /** List of entries in the bucket */ - Jupiter::SLList m_entries; + std::forward_list m_entries; }; /** @@ -190,6 +192,7 @@ namespace Jupiter * @param in_callback Function to callback */ template void callback(CallT &in_callback) const; + template void callback(CallT &in_callback); /** * @brief Returns the number of entries in the table diff --git a/Jupiter/Hash_Table_Imp.h b/Jupiter/Hash_Table_Imp.h index 8823470..fa38db5 100644 --- a/Jupiter/Hash_Table_Imp.h +++ b/Jupiter/Hash_Table_Imp.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2016 Jessica James. + * Copyright (C) 2016-2017 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -69,11 +69,21 @@ Jupiter::Hash_Table::Bucket::Entry::Entry /** Hash_Table::Bucket */ template -ValueT *Jupiter::Hash_Table::Bucket::get(const InKeyT &in_key) const +const ValueT *Jupiter::Hash_Table::Bucket::get(const InKeyT &in_key) const { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - if (node->data->key == in_key) - return &node->data->value; + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) + return &node->value; + + return nullptr; +} + +template +ValueT *Jupiter::Hash_Table::Bucket::get(const InKeyT &in_key) +{ + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) + return &node->value; return nullptr; } @@ -81,9 +91,9 @@ ValueT *Jupiter::Hash_Table::Bucket::get( template const InValueT &Jupiter::Hash_Table::Bucket::get(const InKeyT &in_key, const InValueT &in_value) const { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - if (node->data->key == in_key) - return node->data->value; + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) + return node->value; return in_value; } @@ -92,9 +102,9 @@ template CastT Jupiter::Hash_Table::Bucket::getCast(const InKeyT &in_key, const CastT &in_value) const { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - if (node->data->key == in_key) - return static_cast(node->data->value); + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) + return static_cast(node->value); return in_value; } @@ -102,54 +112,60 @@ CastT Jupiter::Hash_Table::Bucket::getCas template bool Jupiter::Hash_Table::Bucket::set(const InKeyT &in_key, const InValueT &in_value) { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - if (node->data->key == in_key) + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) { - node->data->value = in_value; + node->value = in_value; return false; } - m_entries.add(new Entry(in_key, in_value)); + m_entries.emplace_front(in_key, in_value); return true; } template bool Jupiter::Hash_Table::Bucket::set(const InKeyT &in_key) { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - if (node->data->key == in_key) + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + if (node->key == in_key) return false; - m_entries.add(new Entry(in_key)); + m_entries.emplace_front(in_key); return true; } template bool Jupiter::Hash_Table::Bucket::remove(const InKeyT &in_key) { - Jupiter::SLList::Node *node = m_entries.getHead(); + auto node = m_entries.begin(); + auto end = m_entries.end(); // No nodes in the bucket - if (node == nullptr) + if (node == end) return false; // Check if the head is the desired node - if (node->data->key == in_key) + if (node->key == in_key) { - delete m_entries.removeHead(); + m_entries.pop_front(); return true; } + auto next_node = node; + ++next_node; + // iterate through list - while (node->next != nullptr) + while (next_node != end) { - if (node->next->data->key == in_key) + if (next_node->key == in_key) { // The next node is the desired node - delete m_entries.removeNext(node); + m_entries.erase_after(node); return true; } - node = node->next; + + node = next_node; + ++next_node; } return false; @@ -159,16 +175,24 @@ template void Jupiter::Hash_Table::Bucket::callback(CallT &in_callback) const { - for (Jupiter::SLList::Node *node = m_entries.getHead(); node != nullptr; node = node->next) - in_callback(*node->data); + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + in_callback(*node); +} + +template +template +void Jupiter::Hash_Table::Bucket::callback(CallT &in_callback) +{ + for (auto node = m_entries.begin(); node != m_entries.end(); ++node) + in_callback(*node); } template typename Jupiter::Hash_Table::Bucket &Jupiter::Hash_Table::Bucket::operator=(const Bucket &in_bucket) { - m_entries.eraseAndDelete(); - for (Jupiter::SLList::Node *node = in_bucket.m_entries.getHead(); node != nullptr; node = node->next) - m_entries.add(new Entry(node->data->key, node->data->value)); + m_entries.clear(); + for (auto node = in_bucket.m_entries.begin(); node != m_entries.end(); ++node) + m_entries.emplace_front(node->key, node->value); return *this; } @@ -183,8 +207,8 @@ typename Jupiter::Hash_Table::Bucket &Jup template Jupiter::Hash_Table::Bucket::Bucket(const Bucket &in_bucket) { - for (Jupiter::SLList::Node *node = in_bucket.m_entries.getHead(); node != nullptr; node = node->next) - m_entries.add(new Entry(node->data->key, node->data->value)); + for (auto node = in_bucket.m_entries.getHead(); node != in_bucket.m_entries.end(); ++node) + m_entries.emplace_front(node->key, node->value); } template @@ -196,7 +220,7 @@ Jupiter::Hash_Table::Bucket::Bucket(Bucke template Jupiter::Hash_Table::Bucket::~Bucket() { - m_entries.eraseAndDelete(); + m_entries.clear(); } /** Hash_Table */ @@ -286,6 +310,20 @@ void Jupiter::Hash_Table::callback(CallT } } +template +template +void Jupiter::Hash_Table::callback(CallT &in_callback) +{ + Bucket *itr = m_buckets; + Bucket *end = m_buckets + m_buckets_size; + + while (itr != end) + { + itr->callback(in_callback); + ++itr; + } +} + template size_t Jupiter::Hash_Table::size() const { @@ -327,22 +365,22 @@ typename Jupiter::Hash_Table &Jupiter::Ha else { // we need to erase data; slightly modified version of copy_to_buckets() - Jupiter::SLList::Node *node; + std::forward_list::iterator node; size_t index = 0; while (index != in_table.m_buckets_size) { - in_table.m_buckets[index].m_entries.eraseAndDelete(); + in_table.m_buckets[index].m_entries.clear(); - for (node = in_table.m_buckets[index].m_entries.getHead(); node != nullptr; node = node->next) - m_buckets[HashF(node->data->key) % m_buckets_size].set(node->data->key, node->data->value); + for (node = in_table.m_buckets[index].m_entries.begin(); node != in_table.m_buckets[index].m_entries.end(); ++node) + m_buckets[HashF(node->key) % m_buckets_size].set(node->key, node->value); ++index; } while (index != m_buckets_size) { - in_table.m_buckets[index].m_entries.eraseAndDelete(); + in_table.m_buckets[index].m_entries.clear(); ++index; } } @@ -460,11 +498,11 @@ void Jupiter::Hash_Table::expand() template void Jupiter::Hash_Table::copy_to_buckets(Bucket *in_buckets, size_t in_buckets_size) const { - Jupiter::SLList::Node *node; + std::forward_list::iterator node; for (size_t index = 0; index != m_buckets_size; ++index) - for (node = m_buckets[index].m_entries.getHead(); node != nullptr; node = node->next) - in_buckets[HashF(node->data->key) % in_buckets_size].set(node->data->key, node->data->value); + for (node = m_buckets[index].m_entries.begin(); node != m_buckets[index].m_entries.end(); ++node) + in_buckets[HashF(node->key) % in_buckets_size].set(node->key, node->value); } #endif // _HASH_TABLE_IMP_H_HEADER \ No newline at end of file diff --git a/Jupiter/INIConfig.cpp b/Jupiter/INIConfig.cpp index ce92230..d7a01e8 100644 --- a/Jupiter/INIConfig.cpp +++ b/Jupiter/INIConfig.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2016 Jessica James. + * Copyright (C) 2016-2017 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,20 +49,20 @@ void Jupiter::INIConfig::write_helper(FILE *in_file, const Jupiter::Config *in_s { auto bucket_itr = in_section->getTable().begin(); auto bucket_end = in_section->getTable().end(); - Jupiter::SLList::Node *entry_itr; + std::forward_list::iterator entry_itr; while (bucket_itr != bucket_end) { - for (entry_itr = bucket_itr->m_entries.getHead(); entry_itr != nullptr; entry_itr = entry_itr->next) + for (entry_itr = bucket_itr->m_entries.begin(); entry_itr != bucket_itr->m_entries.end(); ++entry_itr) { // Tabs for (index = 1; index < in_depth; ++index) fputc('\t', in_file); // Write entry - entry_itr->data->key.print(in_file); + entry_itr->key.print(in_file); fputs(" = ", in_file); - entry_itr->data->value.println(in_file); + entry_itr->value.println(in_file); } ++bucket_itr; @@ -73,12 +73,12 @@ void Jupiter::INIConfig::write_helper(FILE *in_file, const Jupiter::Config *in_s { auto bucket_itr = in_section->getSections().begin(); auto bucket_end = in_section->getSections().end(); - Jupiter::SLList::Node *entry_itr; + std::forward_list::iterator entry_itr; while (bucket_itr != bucket_end) { - for (entry_itr = bucket_itr->m_entries.getHead(); entry_itr != nullptr; entry_itr = entry_itr->next) - write_helper(in_file, &entry_itr->data->value, in_depth + 1); + for (entry_itr = bucket_itr->m_entries.begin(); entry_itr != bucket_itr->m_entries.end(); ++entry_itr) + write_helper(in_file, &entry_itr->value, in_depth + 1); ++bucket_itr; }