Browse Source

Added merge sort

Temporary fix in IRC client
release/0.19
Jessica James 8 years ago
parent
commit
7e221aeef1
  1. 222
      Jupiter/Algorithm.h
  2. 36
      Jupiter/IRC_Client.cpp
  3. 1
      Jupiter/Jupiter.vcxproj
  4. 3
      Jupiter/Jupiter.vcxproj.filters

222
Jupiter/Algorithm.h

@ -0,0 +1,222 @@
/**
* Copyright (C) 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Written by Jessica James <jessica.aj@outlook.com>
*/
#if !defined _ALGORITHM_H_HEADER
#define _ALGORITHM_H_HEADER
/**
* @file Algorithm.h
* @brief Provides various common algorithm implementations.
*/
namespace Jupiter
{
namespace Algorithm
{
/**
* @brief Sorts an array of data in-place using merge sort
*
* @param in_data Data to sort
* @param in_data_length Length of the array of data to sort
*/
template<typename T> void merge_sort_serial(T *in_data, size_t in_data_length);
/**
* @brief Sorts an array of data in-place using merge sort across multiple threads
*
* @param in_data Data to sort
* @param in_data_length Length of the array of data to sort
* @param in_max_threads Maximum number of threads to use
* @param in_use_max_threads True to force the number of threads to in_max_threads
*/
template<typename T> void merge_sort_parallel(T *in_data, size_t in_data_length, unsigned int in_max_threads, bool in_force_max_threads = false);
/**
* @brief Sorts an array of data in-place using merge sort across multiple threads
*
* @param in_data Data to sort
* @param in_data_length Length of the array of data to sort
*/
template<typename T> void merge_sort_parallel(T *in_data, size_t in_data_length);
/**
* @brief Sorts an array of data in-place using merge sort across multiple threads
*
* @param in_data Data to sort
* @param in_data_length Length of the array of data to sort
*/
template<typename T> void merge_sort(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);
}
}
}
/**
* IMPLEMENTATION:
* Merge Sort
*/
template<typename T> void Jupiter::Algorithm::merge_sort(T *in_data, size_t in_data_length)
{
merge_sort_parallel<T>(in_data, in_data_length);
}
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);
}
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)
{
constexpr size_t MINIMUM_ELEMENTS_PER_THREAD = 0x3FFF;
unsigned int thread_count = static_cast<unsigned int>(in_data_length) / MINIMUM_ELEMENTS_PER_THREAD;
if (thread_count > in_max_threads || in_force_max_threads)
thread_count = in_max_threads;
if (thread_count <= 1)
{
merge_sort_serial<T>(in_data, in_data_length);
return;
}
T *buffer = new T[in_data_length];
// copy base into buffer
for (size_t index = 0; index != in_data_length; ++index)
buffer[index] = in_data[index];
// mergesort into buffer
Internal::merge_sort_internal<T>(in_data, in_data_length, buffer, thread_count - 1);
// mergesort is complete; free buffer
delete[] buffer;
}
template<typename T> void Jupiter::Algorithm::merge_sort_serial(T *in_data, size_t in_data_length)
{
if (in_data_length <= 1)
return;
T *buffer = new T[in_data_length];
// copy base into buffer
for (size_t index = 0; index != in_data_length; ++index)
buffer[index] = in_data[index];
// mergesort into buffer
Internal::merge_sort_internal<T>(in_data, in_data_length, buffer, 0);
// mergesort is complete; free buffer
delete[] buffer;
}
/** 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)
{
if (in_length <= 1) // Nothing to sort
return;
/** Split */
T *left_buffer = out_buffer;
size_t left_length = in_length / 2;
T *right_buffer = out_buffer + left_length;
size_t right_length = in_length - left_length;
if (unused_threads == 0) // serial
{
// sort left
merge_sort_internal<T>(left_buffer, left_length, in_source, 0);
// sort right
merge_sort_internal<T>(right_buffer, right_length, in_source + left_length, 0);
}
else // parallel
{
--unused_threads;
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);
// sort right
merge_sort_internal<T>(right_buffer, right_length, in_source + left_length, unused_threads - left_thread_count);
left_sort_thread.join();
}
// merge left & right
while (true)
{
if (*right_buffer < *left_buffer)
{
*in_source = *right_buffer;
++in_source;
++right_buffer;
if (--right_length == 0)
{
// Only values on the left side remain
while (left_length != 0)
{
*in_source = *left_buffer;
++in_source;
++left_buffer;
--left_length;
}
return;
}
}
else
{
*in_source = *left_buffer;
++in_source;
++left_buffer;
if (--left_length == 0)
{
// Only values on the right side remain
while (right_length != 0)
{
*in_source = *right_buffer;
++in_source;
++right_buffer;
--right_length;
}
return;
}
}
}
}
#endif // _ALGORITHM_H_HEADER

36
Jupiter/IRC_Client.cpp

@ -1553,27 +1553,37 @@ size_t Jupiter::IRC::Client::User::getChannelCount() const
Jupiter::IRC::Client::Channel::Channel(const Jupiter::ReadableString &in_name, Jupiter::IRC::Client *in_parent)
{
auto to_lower = [&in_name]()
{
Jupiter::String result(in_name.size());
const char *itr = in_name.ptr();
const char *end = itr + in_name.size();
while (itr != end)
{
result += tolower(*itr);
++itr;
}
return result;
};
m_name = in_name;
m_parent = in_parent;
m_type = m_parent->getDefaultChanType();
auto read_type = [&in_name](Jupiter::Config &in_config, int default_type)
Jupiter::String name = to_lower();
auto read_type = [&name](Jupiter::Config &in_config, int default_type)
{
return in_config["Channels"_jrs][in_name].get<int>("Type"_jrs, default_type);
return in_config["Channels"_jrs][name].get<int>("Type"_jrs, default_type);
};
if (m_parent->getPrimaryConfigSection() == nullptr)
{
if (m_parent->getSecondaryConfigSection() != nullptr)
m_type = read_type(*m_parent->getSecondaryConfigSection(), m_type);
}
else if (m_parent->getSecondaryConfigSection() == nullptr)
if (m_parent->getSecondaryConfigSection() != nullptr)
m_type = read_type(*m_parent->getSecondaryConfigSection(), m_type);
if (m_parent->getPrimaryConfigSection() != nullptr)
m_type = read_type(*m_parent->getPrimaryConfigSection(), m_type);
else
{
m_type = read_type(*m_parent->getPrimaryConfigSection(),
read_type(*m_parent->getSecondaryConfigSection(), m_type));
}
}
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User *user)

1
Jupiter/Jupiter.vcxproj

@ -202,6 +202,7 @@
<ClCompile Include="INIConfig.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Algorithm.h" />
<ClInclude Include="ArrayList.h" />
<ClInclude Include="Base64.h" />
<ClInclude Include="Command.h" />

3
Jupiter/Jupiter.vcxproj.filters

@ -272,6 +272,9 @@
<ClInclude Include="INIConfig.h">
<Filter>Header Files\Files\Configs</Filter>
</ClInclude>
<ClInclude Include="Algorithm.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Jupiter.rc">

Loading…
Cancel
Save