You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

algorithm.h 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Frozen
  3. * Copyright 2016 QuarksLab
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. */
  22. #ifndef FROZEN_LETITGO_ALGORITHM_H
  23. #define FROZEN_LETITGO_ALGORITHM_H
  24. #include "frozen/bits/basic_types.h"
  25. #include "frozen/bits/version.h"
  26. #include "frozen/string.h"
  27. namespace frozen {
  28. // 'search' implementation if C++17 is not available
  29. // https://en.cppreference.com/w/cpp/algorithm/search
  30. template<class ForwardIterator, class Searcher>
  31. ForwardIterator search(ForwardIterator first, ForwardIterator last, const Searcher & searcher)
  32. {
  33. return searcher(first, last).first;
  34. }
  35. // text book implementation from
  36. // https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
  37. template <std::size_t size> class knuth_morris_pratt_searcher {
  38. bits::carray<std::ptrdiff_t, size> step_;
  39. bits::carray<char, size> needle_;
  40. static constexpr bits::carray<std::ptrdiff_t, size>
  41. build_kmp_cache(char const (&needle)[size + 1]) {
  42. std::ptrdiff_t cnd = 0;
  43. bits::carray<std::ptrdiff_t, size> cache;
  44. cache.fill(-1);
  45. for (std::size_t pos = 1; pos < size; ++pos) {
  46. if (needle[pos] == needle[cnd]) {
  47. cache[pos] = cache[cnd];
  48. cnd += 1;
  49. } else {
  50. cache[pos] = cnd;
  51. cnd = cache[cnd];
  52. while (cnd >= 0 && needle[pos] != needle[cnd])
  53. cnd = cache[cnd];
  54. cnd += 1;
  55. }
  56. }
  57. return cache;
  58. }
  59. public:
  60. constexpr knuth_morris_pratt_searcher(char const (&needle)[size + 1])
  61. : step_{build_kmp_cache(needle)}, needle_(needle) {}
  62. template <class ForwardIterator>
  63. constexpr std::pair<ForwardIterator, ForwardIterator> operator()(ForwardIterator first, ForwardIterator last) const {
  64. std::size_t i = 0;
  65. ForwardIterator iter = first;
  66. while (iter != last) {
  67. if (needle_[i] == *iter) {
  68. if (i == (size - 1))
  69. return { iter - i, iter - i + size };
  70. ++i;
  71. ++iter;
  72. } else {
  73. if (step_[i] > -1) {
  74. i = step_[i];
  75. } else {
  76. ++iter;
  77. i = 0;
  78. }
  79. }
  80. }
  81. return { last, last };
  82. }
  83. };
  84. template <std::size_t N>
  85. constexpr knuth_morris_pratt_searcher<N - 1> make_knuth_morris_pratt_searcher(char const (&needle)[N]) {
  86. return {needle};
  87. }
  88. // text book implementation from
  89. // https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
  90. template <std::size_t size> class boyer_moore_searcher {
  91. using skip_table_type = bits::carray<std::ptrdiff_t, sizeof(char) << 8>;
  92. using suffix_table_type = bits::carray<std::ptrdiff_t, size>;
  93. skip_table_type skip_table_;
  94. suffix_table_type suffix_table_;
  95. bits::carray<char, size> needle_;
  96. constexpr auto build_skip_table(char const (&needle)[size + 1]) {
  97. skip_table_type skip_table;
  98. skip_table.fill(size);
  99. for (std::size_t i = 0; i < size - 1; ++i)
  100. skip_table[needle[i]] -= i + 1;
  101. return skip_table;
  102. }
  103. constexpr bool is_prefix(char const (&needle)[size + 1], std::size_t pos) {
  104. std::size_t suffixlen = size - pos;
  105. for (std::size_t i = 0; i < suffixlen; i++) {
  106. if (needle[i] != needle[pos + i])
  107. return false;
  108. }
  109. return true;
  110. }
  111. constexpr std::size_t suffix_length(char const (&needle)[size + 1],
  112. std::size_t pos) {
  113. // increment suffix length slen to the first mismatch or beginning
  114. // of the word
  115. for (std::size_t slen = 0; slen < pos ; slen++)
  116. if (needle[pos - slen] != needle[size - 1 - slen])
  117. return slen;
  118. return pos;
  119. }
  120. constexpr auto build_suffix_table(char const (&needle)[size + 1]) {
  121. suffix_table_type suffix;
  122. std::ptrdiff_t last_prefix_index = size - 1;
  123. // first loop
  124. for (std::ptrdiff_t p = size - 1; p >= 0; p--) {
  125. if (is_prefix(needle, p + 1))
  126. last_prefix_index = p + 1;
  127. suffix[p] = last_prefix_index + (size - 1 - p);
  128. }
  129. // second loop
  130. for (std::size_t p = 0; p < size - 1; p++) {
  131. auto slen = suffix_length(needle, p);
  132. if (needle[p - slen] != needle[size - 1 - slen])
  133. suffix[size - 1 - slen] = size - 1 - p + slen;
  134. }
  135. return suffix;
  136. }
  137. public:
  138. constexpr boyer_moore_searcher(char const (&needle)[size + 1])
  139. : skip_table_{build_skip_table(needle)},
  140. suffix_table_{build_suffix_table(needle)},
  141. needle_(needle) {}
  142. template <class ForwardIterator>
  143. constexpr std::pair<ForwardIterator, ForwardIterator> operator()(ForwardIterator first, ForwardIterator last) const {
  144. if (size == 0)
  145. return { first, first + size };
  146. ForwardIterator iter = first + size - 1;
  147. while (iter < last) {
  148. std::ptrdiff_t j = size - 1;
  149. while (j > 0 && (*iter == needle_[j])) {
  150. --iter;
  151. --j;
  152. }
  153. if (*iter == needle_[0])
  154. return { iter, iter + size};
  155. iter += std::max(skip_table_[*iter], suffix_table_[j]);
  156. }
  157. return { last, last + size};
  158. }
  159. };
  160. template <std::size_t N>
  161. constexpr boyer_moore_searcher<N - 1> make_boyer_moore_searcher(char const (&needle)[N]) {
  162. return {needle};
  163. }
  164. } // namespace frozen
  165. #endif