<tb@panthema.net>
<http://www.gnu.org/licenses/>
#include <string.h>
#include "../tools/stringtools.h"
#include "../tools/contest.h"
#ifndef BINGMANN_LCP_INSSORT_H_
#define BINGMANN_LCP_INSSORT_H_
namespace bingmann_lcp_inssort {
using namespace stringtools;
static inline
void lcp_insertion_sort(string* str, uintptr_t* lcp, size_t n, size_t depth)
{
if (n <= 1) return;
for (size_t j = 0; j < n - 1; ++j)
{
string new_str = str[j];
size_t new_lcp = depth;
size_t i = j;
while (i > 0)
{
size_t prev_lcp = new_lcp;
string cur_str = str[i - 1];
size_t cur_lcp = lcp[i];
if (cur_lcp < new_lcp)
{
break;
}
else if (cur_lcp == new_lcp)
{
string s1 = new_str + new_lcp;
string s2 = cur_str + new_lcp;
while (*s1 != 0 && *s1 == *s2)
++s1, ++s2, ++new_lcp;
if (*s1 >= *s2)
{
lcp[i] = new_lcp;
new_lcp = prev_lcp;
break;
}
}
str[i] = cur_str;
lcp[i + 1] = cur_lcp;
--i;
}
str[i] = new_str;
lcp[i + 1] = new_lcp;
}
{
size_t j = n - 1;
string new_str = str[j];
size_t new_lcp = depth;
size_t i = j;
while (i > 0)
{
size_t prev_lcp = new_lcp;
string cur_str = str[i - 1];
size_t cur_lcp = lcp[i];
if (cur_lcp < new_lcp)
{
break;
}
else if (cur_lcp == new_lcp)
{
string s1 = new_str + new_lcp;
string s2 = cur_str + new_lcp;
while (*s1 != 0 && *s1 == *s2)
++s1, ++s2, ++new_lcp;
if (*s1 >= *s2)
{
lcp[i] = new_lcp;
new_lcp = prev_lcp;
break;
}
}
str[i] = cur_str;
if (i + 1 < n)
lcp[i + 1] = cur_lcp;
--i;
}
str[i] = new_str;
if (i + 1 < n)
lcp[i + 1] = new_lcp;
}
}
static inline
void lcp_insertion_sort_pseudocode(string* str, uintptr_t* lcp, size_t n, size_t depth)
{
unsigned int cmp = 0;
for (size_t j = 0; j < n; ++j)
{
string snew = str[j];
size_t h = depth;
size_t i = j;
while (i > 0)
{
if (lcp[i] < h)
{
break;
}
else if (lcp[i] == h)
{
size_t prev_lcp = h;
string s2 = str[i - 1];
while (cmp++, snew[h] != 0 && snew[h] == s2[h])
++h;
if (snew[h] >= s2[h])
{
lcp[i] = h;
h = prev_lcp;
break;
}
}
str[i] = str[i - 1];
lcp[i + 1] = lcp[i];
--i;
}
str[i] = snew;
lcp[i + 1] = h;
}
std::cout << "lcp_inssort comparisons = " << cmp << "\n";
}
static inline
void lcp_insertion_sort(string* str, size_t n, size_t depth)
{
uintptr_t tmp_lcp[n];
return lcp_insertion_sort(str, tmp_lcp, n, depth);
}
static inline
void lcp_insertion_sort(StringShadowPtr& str, size_t depth)
{
return lcp_insertion_sort(str.active(), str.size(), depth);
}
static inline
void lcp_insertion_sort(StringShadowLcpPtr& str, size_t depth)
{
return lcp_insertion_sort(str.active(), str.lcparray(), str.size(), depth);
}
static inline
void test_lcp_insertion_sort(string* strings, size_t n)
{
lcp_insertion_sort(strings, n, 0);
}
CONTESTANT_REGISTER(test_lcp_insertion_sort,
"bingmann/lcp_insertion_sort",
"LCP-aware insertion sort")
static inline
void test_lcp_insertion_sort_nolcp(string* strings, size_t n)
{
string* shadow = new string[n];
StringShadowPtr strptr(strings, shadow, n);
lcp_insertion_sort(strptr, 0);
delete [] shadow;
}
CONTESTANT_REGISTER(test_lcp_insertion_sort_nolcp,
"bingmann/lcp_insertion_sort_nolcp",
"LCP-aware insertion sort (without LCP output)")
static inline
void test_lcp_insertion_sort_pseudocode(string* strings, size_t n)
{
string* shadow = new string[n+1];
StringShadowLcpPtr strptr(strings, shadow, n);
strptr.lcp(0) = 42;
lcp_insertion_sort_pseudocode(strptr.active(), strptr.lcparray(), n, 0);
stringtools::verify_lcp(strptr.active(), strptr.lcparray(), n, 42);
delete [] shadow;
}
CONTESTANT_REGISTER(test_lcp_insertion_sort_pseudocode,
"bingmann/lcp_insertion_sort_pseudocode",
"LCP-aware insertion sort close to pseudo-code, with checking")
static inline
void lcp_insertion_sort_cache(string* str, uintptr_t* lcp, char_type* cache,
size_t n, size_t depth)
{
if (n <= 1) return;
for (size_t j = 0; j < n - 1; ++j)
{
string new_str = str[j];
char_type new_ch = new_str[depth];
size_t new_lcp = depth;
size_t i = j;
while (i > 0)
{
size_t prev_lcp = new_lcp;
string cur_str = str[i - 1];
size_t cur_lcp = lcp[i];
if (cur_lcp < new_lcp)
{
break;
}
else if (cur_lcp == new_lcp)
{
string s2 = cur_str + new_lcp;
while (new_ch != 0 && new_ch == *s2)
{
++s2, ++new_lcp;
new_ch = new_str[new_lcp];
}
if (new_ch >= *s2)
{
lcp[i] = new_lcp;
cache[i] = new_ch;
new_lcp = prev_lcp;
break;
}
}
str[i] = cur_str;
cache[i] = cache[i - 1];
lcp[i + 1] = cur_lcp;
--i;
}
str[i] = new_str;
lcp[i + 1] = new_lcp;
cache[i + 1] = str[i + 1][new_lcp];
}
{
size_t j = n - 1;
string new_str = str[j];
char_type new_ch = new_str[depth];
size_t new_lcp = depth;
size_t i = j;
while (i > 0)
{
size_t prev_lcp = new_lcp;
string cur_str = str[i - 1];
size_t cur_lcp = lcp[i];
if (cur_lcp < new_lcp)
{
break;
}
else if (cur_lcp == new_lcp)
{
string s2 = cur_str + new_lcp;
while (new_ch != 0 && new_ch == *s2)
{
++s2, ++new_lcp;
new_ch = new_str[new_lcp];
}
if (new_ch >= *s2)
{
lcp[i] = new_lcp;
cache[i] = new_ch;
new_lcp = prev_lcp;
break;
}
}
str[i] = cur_str;
cache[i] = cache[i - 1];
if (i + 1 < n)
lcp[i + 1] = cur_lcp;
--i;
}
str[i] = new_str;
if (i + 1 < n)
{
lcp[i + 1] = new_lcp;
cache[i + 1] = str[i + 1][new_lcp];
}
}
}
static inline
void test_lcp_insertion_sort_cache(string* strings, size_t n)
{
lcp_t* lcps = new lcp_t[n];
char_type* cache = new char_type[n];
lcp_insertion_sort_cache(strings, lcps, cache, n, 0);
stringtools::verify_lcp_cache(strings, lcps, cache, n, -1);
delete [] lcps;
delete [] cache;
}
CONTESTANT_REGISTER(test_lcp_insertion_sort_cache,
"bingmann/lcp_insertion_sort_cache",
"LCP-aware insertion sort (with distinguishing character cache)")
}
#endif