Browse Source

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.
release/0.19
Jessica James 8 years ago
parent
commit
2ff758047a
  1. 30
      Jupiter/Algorithm.h
  2. 11
      Jupiter/Hash_Table.h
  3. 122
      Jupiter/Hash_Table_Imp.h
  4. 16
      Jupiter/INIConfig.cpp

30
Jupiter/Algorithm.h

@ -62,11 +62,15 @@ namespace Jupiter
*/
template<typename T> void merge_sort_serial(T *in_data, size_t in_data_length);
/** Internal helper templates */
namespace Internal
{
template<typename T> 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<typename T> void merge_sort_direct(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads);
}
}
@ -82,7 +86,7 @@ template<typename T> void Jupiter::Algorithm::merge_sort(T *in_data, size_t in_d
template<typename T> void Jupiter::Algorithm::merge_sort_parallel(T *in_data, size_t in_data_length)
{
merge_sort_parallel<T>(in_data, in_data_length);
merge_sort_parallel<T>(in_data, in_data_length, std::thread::hardware_concurrency());
}
template<typename T> 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<typename T> void Jupiter::Algorithm::merge_sort_parallel(T *in_data, si
buffer[index] = in_data[index];
// mergesort into buffer
Internal::merge_sort_internal<T>(in_data, in_data_length, buffer, thread_count - 1);
merge_sort_direct<T>(in_data, in_data_length, buffer, thread_count - 1);
// mergesort is complete; free buffer
delete[] buffer;
@ -125,7 +129,7 @@ template<typename T> void Jupiter::Algorithm::merge_sort_serial(T *in_data, size
buffer[index] = in_data[index];
// mergesort into buffer
Internal::merge_sort_internal<T>(in_data, in_data_length, buffer, 0);
merge_sort_direct<T>(in_data, in_data_length, buffer, 0);
// mergesort is complete; free buffer
delete[] buffer;
@ -133,7 +137,7 @@ template<typename T> void Jupiter::Algorithm::merge_sort_serial(T *in_data, size
/** Internals */
template<typename T> void Jupiter::Algorithm::Internal::merge_sort_internal(T *in_source, size_t in_length, T *out_buffer, unsigned int unused_threads)
template<typename T> 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<typename T> void Jupiter::Algorithm::Internal::merge_sort_internal(T *i
if (unused_threads == 0) // serial
{
// sort left
merge_sort_internal<T>(left_buffer, left_length, in_source, 0);
merge_sort_direct<T>(left_buffer, left_length, in_source, 0);
// sort right
merge_sort_internal<T>(right_buffer, right_length, in_source + left_length, 0);
merge_sort_direct<T>(right_buffer, right_length, in_source + left_length, 0);
}
else // parallel
{
@ -161,10 +165,10 @@ template<typename T> 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<T>, left_buffer, left_length, in_source, left_thread_count);
std::thread left_sort_thread(merge_sort_direct<T>, left_buffer, left_length, in_source, left_thread_count);
// sort right
merge_sort_internal<T>(right_buffer, right_length, in_source + left_length, unused_threads - left_thread_count);
merge_sort_direct<T>(right_buffer, right_length, in_source + left_length, unused_threads - left_thread_count);
left_sort_thread.join();
}

11
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 <forward_list>
#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<typename CastT> CastT getCast(const InKeyT &in_key, const CastT &in_value) const;
@ -99,6 +100,7 @@ namespace Jupiter
* @param in_callback Function to callback
*/
template<typename CallT> void callback(CallT &in_callback) const;
template<typename CallT> void callback(CallT &in_callback);
/**
* @brief Copy assignment operator
@ -137,7 +139,7 @@ namespace Jupiter
~Bucket();
/** List of entries in the bucket */
Jupiter::SLList<Entry> m_entries;
std::forward_list<Entry> m_entries;
};
/**
@ -190,6 +192,7 @@ namespace Jupiter
* @param in_callback Function to callback
*/
template<typename CallT> void callback(CallT &in_callback) const;
template<typename CallT> void callback(CallT &in_callback);
/**
* @brief Returns the number of entries in the table

122
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<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::Entry::Entry
/** Hash_Table::Bucket */
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
ValueT *Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::get(const InKeyT &in_key) const
const ValueT *Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::get(const InKeyT &in_key) const
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
ValueT *Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::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<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::get(
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
const InValueT &Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::get(const InKeyT &in_key, const InValueT &in_value) const
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, siz
template<typename CastT>
CastT Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::getCast(const InKeyT &in_key, const CastT &in_value) const
{
for (Jupiter::SLList<Entry>::Node *node = m_entries.getHead(); node != nullptr; node = node->next)
if (node->data->key == in_key)
return static_cast<CastT>(node->data->value);
for (auto node = m_entries.begin(); node != m_entries.end(); ++node)
if (node->key == in_key)
return static_cast<CastT>(node->value);
return in_value;
}
@ -102,54 +112,60 @@ CastT Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::getCas
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
bool Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::set(const InKeyT &in_key, const InValueT &in_value)
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
bool Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::set(const InKeyT &in_key)
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
bool Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::remove(const InKeyT &in_key)
{
Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, siz
template<typename CallT>
void Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::callback(CallT &in_callback) const
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
template<typename CallT>
void Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::callback(CallT &in_callback)
{
for (auto node = m_entries.begin(); node != m_entries.end(); ++node)
in_callback(*node);
}
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
typename Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket &Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::operator=(const Bucket &in_bucket)
{
m_entries.eraseAndDelete();
for (Jupiter::SLList<Entry>::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<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket &Jup
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::Bucket(const Bucket &in_bucket)
{
for (Jupiter::SLList<Entry>::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<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
@ -196,7 +220,7 @@ Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::Bucket(Bucke
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::Bucket::~Bucket()
{
m_entries.eraseAndDelete();
m_entries.clear();
}
/** Hash_Table */
@ -286,6 +310,20 @@ void Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::callback(CallT
}
}
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
template<typename CallT>
void Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::callback(CallT &in_callback)
{
Bucket *itr = m_buckets;
Bucket *end = m_buckets + m_buckets_size;
while (itr != end)
{
itr->callback<CallT>(in_callback);
++itr;
}
}
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
size_t Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::size() const
{
@ -327,22 +365,22 @@ typename Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF> &Jupiter::Ha
else
{
// we need to erase data; slightly modified version of copy_to_buckets()
Jupiter::SLList<Bucket::Entry>::Node *node;
std::forward_list<Bucket::Entry>::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<KeyT, ValueT, InKeyT, InValueT, HashF>::expand()
template<typename KeyT, typename ValueT, typename InKeyT, typename InValueT, size_t(*HashF)(const InKeyT &)>
void Jupiter::Hash_Table<KeyT, ValueT, InKeyT, InValueT, HashF>::copy_to_buckets(Bucket *in_buckets, size_t in_buckets_size) const
{
Jupiter::SLList<Bucket::Entry>::Node *node;
std::forward_list<Bucket::Entry>::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

16
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<HashTable::Bucket::Entry>::Node *entry_itr;
std::forward_list<HashTable::Bucket::Entry>::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<SectionHashTable::Bucket::Entry>::Node *entry_itr;
std::forward_list<SectionHashTable::Bucket::Entry>::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;
}

Loading…
Cancel
Save