mirror of https://github.com/JAJames/Jupiter.git
Jessica James
8 years ago
4 changed files with 249 additions and 13 deletions
@ -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
|
Loading…
Reference in new issue