├── .gitignore ├── src ├── copy_n.cpp ├── reverse.cpp ├── rotate.cpp ├── join.cpp ├── fill.cpp ├── generate.cpp ├── binary_search.cpp ├── accumulate.cpp ├── overwrite.cpp ├── reversed.cpp ├── replace.cpp ├── iota.cpp ├── erase.cpp ├── push_back.cpp ├── filter.cpp ├── insert.cpp ├── push_front.cpp ├── uniqued.cpp ├── count.cpp ├── replace_if.cpp ├── adjacent_filtered_bug.cpp ├── adjacent_find.cpp ├── remove_erase.cpp ├── slice_stride.cpp ├── next_permutation.cpp ├── prev_permutation.cpp ├── sub_range.cpp ├── random_shuffle.cpp ├── is_sorted.cpp ├── indirected.cpp ├── remove_erase_if.cpp ├── reverse_copy.cpp ├── rotate_copy.cpp ├── remove.cpp ├── replace_copy.cpp ├── size.cpp ├── transformed.cpp ├── swap_ranges.cpp ├── unique.cpp ├── remove_if.cpp ├── boost-range-traversal-1.56.hpp ├── combine.cpp ├── replace_copy_if.cpp ├── partial_sum.cpp ├── map_adaptors.cpp ├── unique_copy.cpp ├── remove_copy.cpp ├── inner_product.cpp ├── partition.cpp ├── istream_range.cpp ├── sort.cpp ├── general.cpp ├── search_n.cpp ├── remove_copy_if.cpp ├── stable_partition.cpp ├── inplace_merge.cpp ├── set_union.cpp ├── set_intersection.cpp ├── set_difference.cpp ├── copied.cpp ├── numeric_range.cpp ├── stable_sort.cpp ├── set_symmetric_difference.cpp ├── adjacent_difference.cpp ├── mismatch.cpp ├── includes.cpp ├── copy.cpp ├── replaced.cpp ├── min_max_element.cpp ├── partial_sort.cpp ├── equal.cpp ├── indexed.cpp ├── equal_range.cpp ├── for_each.cpp ├── nth_element.cpp ├── lexicographical_compare.cpp ├── any_range.cpp ├── merge.cpp ├── upper_bound.cpp ├── lower_bound.cpp ├── transform.cpp ├── iterator_range.cpp ├── search.cpp ├── heap.cpp ├── heap_with_predicate.cpp ├── find.cpp ├── string_conversions.cpp ├── adjacent_filter.cpp ├── tokenized.cpp └── boost-range-indexed-1.56.hpp ├── templates ├── index.md ├── index.html ├── entry.html └── entry.md ├── macros.gpp ├── README.md ├── NOTES ├── headertree.py ├── Makefile ├── docgen.py └── exampletable.txt /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | /bin/ 3 | /html/ 4 | /markdown/ 5 | /output/ 6 | /preprocessed/ 7 | /stamps/ 8 | -------------------------------------------------------------------------------- /src/copy_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 2, 3, 4, 5}; 7 | 8 | // Copy n elements to an output iterator. 9 | boost::range::copy_n(vec, 3, std::ostream_iterator(std::cout, " ")); 10 | std::cout << std::endl; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/reverse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | 9 | // Reverses the input range and returns a reference to it. 10 | boost::range::reverse(vec); 11 | 12 | std::cout << "reversed input vector: "; 13 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 14 | std::cout << std::endl; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/rotate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 2, 3, 4, 5}; 7 | 8 | // Rotates the input range and returns a reference to it. 9 | boost::range::rotate(vec, vec.begin() + 2); 10 | 11 | std::cout << "input vector rotated by 2 elements: "; 12 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 13 | std::cout << std::endl; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /templates/index.md: -------------------------------------------------------------------------------- 1 | Title: Boost Range For Humans 2 | 3 | {% for category in view %} 4 | {% if category.level_headers[0] %}##{{category.level_headers[0]}}{% endif %} 5 | {% if category.level_headers[1] %}###{{category.level_headers[1]}}{% endif %} 6 | {% if category.level_headers[2] %}####{{category.level_headers[2]}}{% endif %} 7 | 8 | {% for fun in category.functions %} 9 | * {{fun.name}} 10 | {%- endfor %} 11 | 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /src/join.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | int main() { 10 | std::string str = "abcde"; 11 | std::vector vec = {'A', 'B', 'C', 'D', 'E'}; 12 | 13 | // join() takes two ranges and concatenates them to a single range. 14 | for (const auto & c : boost::join(str, vec)) { 15 | std::cout << c; 16 | } 17 | std::cout << std::endl; 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /src/fill.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 2, 3, 4, 5}; 7 | 8 | // Fill the whole vector with zero. 9 | boost::range::fill(vec, 0); 10 | 11 | // Set the first three elements to 42. 12 | // The order of arguments is (n, value), consistent with fill constructors. 13 | // n must be smaller or equal to size(vec). 14 | boost::range::fill_n(vec, 3, 42); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/generate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int generator() { 7 | static int i = 0; 8 | return 2 * i++; 9 | } 10 | 11 | int main() { 12 | std::vector vec(10, 0); 13 | 14 | // Set each element of vec to the result of generator(). 15 | boost::range::generate(vec, generator); 16 | 17 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 18 | std::cout << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::string s = "abcddefghijkklmnoopqrstuvwxyyyz"; 6 | 7 | // Binary search to determine if a value is contained in a range. 8 | // Accepts an optional ordering pradicate. 9 | // Returns true if the value was found, false otherwise. 10 | bool has_n = boost::range::binary_search(s, 'n'); 11 | 12 | std::cout << (has_n ? "'n' is in s" : "'n' is not in s") << std::endl; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/accumulate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | 9 | // Straight-forward wrapper around std::accumulate(). 10 | int sum = boost::accumulate(vec, 0); 11 | int product = boost::accumulate(vec, 1, std::multiplies()); 12 | 13 | std::cout << "Sum(1..5): " << sum << std::endl; 14 | std::cout << "Product(1..5): " << product << std::endl; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/overwrite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector src = {3, 4, 5}; 8 | std::vector target = {95, 96, 97, 98, 99}; 9 | 10 | // Copy values from one range to another, overwriting the target values. 11 | boost::range::overwrite(src, target); 12 | 13 | boost::copy(target, std::ostream_iterator(std::cout, " ")); 14 | std::cout << std::endl; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/reversed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | @ifdef PIPE 7 | @define REVERSE reversed 8 | @else 9 | @define REVERSE reverse 10 | @endif 11 | 12 | int main() { 13 | std::string str = "abcdefghijklmnopqrstuvwxyz"; 14 | 15 | // Reverse iteration order over a range. Pretty straight-forward. 16 | std::cout << "Reversed abc: " 17 | << PARENWRAP(CALL0(boost::adaptors::REVERSE,str)) 18 | << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/replace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | 9 | // replace() is a wrapper for std::replace(). 10 | // It returns a reference to the input range. 11 | boost::range::replace(vec, 2, 0); 12 | 13 | std::cout << "input vector after replace(vec, 2, 0): "; 14 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/iota.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec(5, 0); 8 | 9 | // Fill an input range with a linear range of values. 10 | // The value of the first element is given as second parameter. 11 | // Returns a reference to the input range. 12 | boost::range::iota(vec, 10); 13 | 14 | boost::copy(vec, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/erase.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | 9 | // Erase an arbitrary range from a vector. 10 | boost::range::erase(vec, boost::make_iterator_range(vec.begin() + 1, 11 | vec.begin() + 4)); 12 | 13 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 14 | std::cout << std::endl; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/push_back.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector src = {3, 4, 5}; 8 | std::vector target = {95, 96, 97, 98, 99}; 9 | 10 | // Copy values from a range to a container, inserting them with push_back(). 11 | // Returns a reference to the target container. 12 | boost::range::push_back(target, src); 13 | 14 | boost::copy(target, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const std::vector vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 7 | 8 | @ifdef PIPE 9 | @define FILTER filtered 10 | @else 11 | @define FILTER filter 12 | @endif 13 | 14 | bool is_even(int n) { 15 | return n % 2 == 0; 16 | } 17 | 18 | int main() { 19 | std::cout << "vec filetered by is_even(): "; 20 | for (int i : CALL1(boost::adaptors::FILTER,vec,is_even)) { 21 | std::cout << i << " "; 22 | } 23 | std::cout << std::endl; 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/insert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | std::vector target = {97, 98, 99}; 9 | 10 | // Insert a range into a target container at a specified position. 11 | // Returns a reference to the target container. 12 | boost::range::insert(target, target.begin() + 2, vec); 13 | 14 | boost::copy(target, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/push_front.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector src = {3, 4, 5}; 8 | std::vector target = {95, 96, 97, 98, 99}; 9 | 10 | // Copy values from a range to a container, inserting them with push_front(). 11 | // Returns a reference to the target container. 12 | boost::range::push_front(target, src); 13 | 14 | boost::copy(target, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /src/uniqued.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const std::string str = "f00f"; 7 | 8 | @ifdef PIPE 9 | @define UNIQUE uniqued 10 | @else 11 | @define UNIQUE unique 12 | @endif 13 | 14 | int main() { 15 | // Equal values are unified if they are adjacent. Equal values that are 16 | // separated by different elements are left untouched. 17 | std::cout << "Uniqued version of \"" << str << "\": " 18 | << (CALL0(boost::adaptors::UNIQUE,str)) 19 | << std::endl; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/count.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool is_m_or_n(char c) { 6 | return c == 'm' || c == 'n'; 7 | } 8 | 9 | int main() { 10 | std::string s = "abcddefghijkklmmnoopqrstuvwxyyyz"; 11 | 12 | int num_o = boost::range::count(s, 'o'); 13 | int num_mn = boost::range::count_if(s, is_m_or_n); 14 | 15 | std::cout << "Input string: \"" << s << "\"" << std::endl; 16 | std::cout << "Number of 'o' characters: " << num_o << std::endl; 17 | std::cout << "Number of 'm' and 'n' characters: " << num_mn << std::endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/replace_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool is_3_or_4(int i) { 7 | return i == 3 || i == 4; 8 | } 9 | 10 | int main() { 11 | std::vector vec = {1, 2, 3, 4, 5}; 12 | 13 | // replace_if() is a wrapper for std::replace_if(). 14 | // Returns a reference to the input range. 15 | boost::range::replace_if(vec, is_3_or_4, 0); 16 | 17 | std::cout << "input vector after replace_if(): "; 18 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 19 | std::cout << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/adjacent_filtered_bug.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | int main() { 9 | std::istringstream ss2("1 2 3 4 5"); 10 | auto input_range2 = boost::istream_range(ss2); 11 | for (int input : input_range2 | boost::adaptors::uniqued) { 12 | std::cout << input; 13 | } 14 | std::cout << std::endl; 15 | 16 | std::vector vec{1, 2, 3, 4, 5}; 17 | for (int input : vec | boost::adaptors::uniqued) { 18 | std::cout << input; 19 | } 20 | std::cout << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/adjacent_find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::string s = "abccdb"; 7 | 8 | std::string::iterator eq_it = boost::range::adjacent_find(s); 9 | std::string::iterator gt_it = boost::range::adjacent_find(s, std::greater()); 10 | 11 | std::cout << "First duplicate character: '" << *eq_it << "' " 12 | << "at position " << (eq_it - s.begin()) << std::endl; 13 | std::cout << "First character greater than next: '" << *gt_it << "' " 14 | << "at position " << (gt_it - s.begin()) << std::endl; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/remove_erase.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::vector vec = {1, 2, 3, 4, 5}; 9 | 10 | // Remove elements, shrinking the container in the process. 11 | // Encapsulates the common erase-remove idiom. 12 | // Returns a reference to the input container. 13 | boost::range::remove_erase(vec, 2); 14 | 15 | std::cout << "input vector after remove_erase(vec, 2): "; 16 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 17 | std::cout << std::endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/slice_stride.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | const std::string str = "abcde"; 8 | 9 | @ifdef PIPE 10 | @define SLICE sliced 11 | @define STRIDE strided 12 | @else 13 | @define SLICE slice 14 | @define STRIDE stride 15 | @endif 16 | 17 | int main() { 18 | std::cout << "\"" << str << "\" sliced to (1, 4): " 19 | << (CALL2(boost::adaptors::SLICE,str,1,4)) 20 | << std::endl; 21 | std::cout << "\"" << str << "\" | strided(2): " 22 | << (CALL1(boost::adaptors::STRIDE,str,2)) 23 | << std::endl; 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/next_permutation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::string s = "abc"; 7 | 8 | // next_permutation() generates permutations of a sequence. 9 | // Permutations are generated in lexicographical order (or the order 10 | // enforced by an optional binary predicate). 11 | // If a larger permutation could be generated, true is returned, otherwise 12 | // the smallest permutation is generated and false is returned. 13 | do { 14 | std::cout << s << " "; 15 | } while (boost::range::next_permutation(s)); 16 | 17 | std::cout << std::endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/prev_permutation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::string s = "cba"; 7 | 8 | // prev_permutation() generates permutations of a sequence. 9 | // Permutations are generated in lexicographically descending order (or in 10 | // descending order based on an optional binary predicate). 11 | // If a smaller permutation could be generated, true is returned, otherwise 12 | // the largest permutation is generated and false is returned. 13 | do { 14 | std::cout << s << " "; 15 | } while (boost::range::prev_permutation(s)); 16 | 17 | std::cout << std::endl; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/sub_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | 8 | int main() { 9 | std::string s = "Boost Range"; 10 | 11 | // sub_range() creates a range object from a begin and end iterator, 12 | // just like iterator_range() does. However, sub_range() has the container 13 | // as template type instead of the iterator, making it easier to use. 14 | // 15 | // In C++11, auto + make_iterator_range() should largely eliminate the 16 | // need for explicitly using this class in client code. 17 | boost::sub_range range(s.begin(), s.begin()+5); 18 | std::cout << range << std::endl; 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/random_shuffle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int random_generator(int max) { 7 | return std::rand() % max; 8 | } 9 | 10 | int main() { 11 | std::vector vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 12 | 13 | // random_shuffle() shuffles the input range so the elements have random order. 14 | boost::range::random_shuffle(vec); 15 | 16 | // A custom random number generator can be supplied as well. 17 | boost::range::random_shuffle(vec, random_generator); 18 | 19 | // Display the result. 20 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 21 | std::cout << std::endl; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/is_sorted.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {5, 4, 3, 2, 1}; 8 | 9 | // Test if an input range is sorted. 10 | // Optionally accepts a comparison predicate. 11 | bool is_asc = boost::range::is_sorted(vec); 12 | bool is_desc = boost::range::is_sorted(vec, std::greater()); 13 | 14 | std::cout << "vec(5..1) is sorted in ascending order: " 15 | << (is_asc ? "true" : "false") 16 | << std::endl; 17 | std::cout << "vec(5..1) is sorted in descending order: " 18 | << (is_desc ? "true" : "false") 19 | << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/indirected.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const std::vector vec = { 0, 1, 2 }; 7 | const std::vector ptr_vec = { &vec[0], &vec[1], &vec[2] }; 8 | 9 | @ifdef PIPE 10 | @define INDIRECT indirected 11 | @else 12 | @define INDIRECT indirect 13 | @endif 14 | 15 | int main() { 16 | // INDIRECT() is a good solution for iterating over a container of pointers 17 | // or iterators. It avoids the (*it)->... ideom. 18 | std::cout << "Easy iteration over a vector of pointers" << std::endl; 19 | for (int i : CALL0(boost::adaptors::INDIRECT,ptr_vec)) { 20 | std::cout << i << " "; 21 | } 22 | std::cout << std::endl; 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/remove_erase_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool is_3_or_4(int i) { 8 | return i == 3 || i == 4; 9 | } 10 | 11 | int main() { 12 | std::vector vec = {1, 2, 3, 4, 5}; 13 | 14 | // Remove elements, shrinking the container in the process. 15 | // Encapsulates the common erase-remove idiom. 16 | // Returns a reference to the input container. 17 | boost::range::remove_erase_if(vec, is_3_or_4); 18 | 19 | std::cout << "input vector after remove_erase_if(vec, is_3_or_4): "; 20 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 21 | std::cout << std::endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/reverse_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 2, 3, 4, 5}; 7 | std::vector output; 8 | 9 | // Copies the reversed input range to an output iterator. 10 | // Returns an iterator to the end of the output range. 11 | boost::reverse_copy(vec, std::back_inserter(output)); 12 | 13 | std::cout << "input vector after reverse_copy(): "; 14 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | 17 | std::cout << "output vector after reverse_copy(): "; 18 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 19 | std::cout << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/rotate_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 2, 3, 4, 5}; 7 | std::vector output; 8 | 9 | // Copies a rotated input range to an output iterator. 10 | // Returns an iterator to the end of the output range. 11 | boost::rotate_copy(vec, vec.begin() + 2, std::back_inserter(output)); 12 | 13 | std::cout << "input vector after rotate_copy(): "; 14 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | 17 | std::cout << "output vector after rotate_copy(): "; 18 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 19 | std::cout << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /macros.gpp: -------------------------------------------------------------------------------- 1 | @ifdef PIPE 2 | @define CALL0(func, input) input | func 3 | @define CALL1(func, input, a) input | func(a) 4 | @define CALL2(func, input, a, b) input | func(a, b) 5 | @define CALL3(func, input, a, b, c) input | func(a, b, c) 6 | @define CALL4(func, input, a, b, c, d) input | func(a, b, c, d) 7 | @define CALL5(func, input, a, b, c, d, e) input | func(a, b, c, d, e) 8 | @define PARENWRAP(x) (x) 9 | @else 10 | @define CALL0(func, input) func(input) 11 | @define CALL1(func, input, a) func(input, a) 12 | @define CALL2(func, input, a, b) func(input, a, b) 13 | @define CALL3(func, input, a, b, c) func(input, a, b, c) 14 | @define CALL4(func, input, a, b, c, d) func(input, a, b, c, d) 15 | @define CALL5(func, input, a, b, c, d, e) func(input, a, b, c, d, e) 16 | @define PARENWRAP(x) x 17 | @endif 18 | -------------------------------------------------------------------------------- /src/remove.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | 9 | // remove() is a wrapper for std::remove(). Elements in the input range 10 | // are reordered, but the size of the input container is not changed. 11 | // An iterator to the new end is returned. 12 | std::vector::iterator end_it = boost::range::remove(vec, 2); 13 | 14 | std::cout << "input vector after remove(vec, 2): "; 15 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 16 | std::cout << std::endl; 17 | 18 | std::cout << "Index of the returned iterator: " << (end_it - vec.begin()); 19 | std::cout << std::endl; 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /src/replace_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | std::vector output; 9 | 10 | // replace_copy() wraps std::replace_copy(). 11 | // Returns an iterator to the end of the output range. 12 | boost::replace_copy(vec, std::back_inserter(output), 2, 0); 13 | 14 | std::cout << "input vector after replace_copy(): "; 15 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 16 | std::cout << std::endl; 17 | 18 | std::cout << "output vector after replace_copy(): "; 19 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 20 | std::cout << std::endl; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/size.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | 8 | int main() { 9 | std::string str = "abcde"; 10 | std::vector vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 11 | 12 | // boost::empty() and boost::size() do about what you'd expect. 13 | std::cout << "empty(str): " << boost::empty(str) << std::endl; 14 | std::cout << "size(vec): " << boost::size(vec) << std::endl; 15 | 16 | // Prefer boost::size() over boost::distance(). The former calls the 17 | // .size() member function if available and degrades to boost::distance() 18 | // otherwise. Thus, there's no reason to use boost::distance() directly. 19 | std::cout << "distance(vec): " << boost::distance(vec) << std::endl; 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /src/transformed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const std::vector vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 7 | 8 | @ifdef PIPE 9 | @define TRANSFORM transformed 10 | @else 11 | @define TRANSFORM transform 12 | @endif 13 | 14 | /** Map integers to the alphabet: 0->a, 1->b, ... */ 15 | std::string alphabetize(int i) { 16 | return std::string(1, 'a' + i); 17 | } 18 | 19 | int main() { 20 | // TRANSFORM() is a nice and general way to change elements in a Boost 21 | // Range. Even type conversions work fluently, as shown here: 22 | std::cout << "Transform a vector into letters: " 23 | << (CALL1(boost::adaptors::TRANSFORM,vec,alphabetize)) 24 | << std::endl; 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Boost Range Example Code 6 | 7 | 8 | 9 | 10 |

Boost Range Example Code

11 | {% for category in view %} 12 | {%- if category.level_headers[0] %}

{{category.level_headers[0]}}

{% endif %} 13 | {%- if category.level_headers[1] %}

{{category.level_headers[1]}}

{% endif %} 14 | {%- if category.level_headers[2] %}

{{category.level_headers[2]}}

{% endif %} 15 | 16 |
    17 | {% for fun in category.functions %} 18 |
  • {{fun.name}}
  • 19 | {% endfor %} 20 |
21 | {% endfor %} 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/swap_ranges.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(int i, const std::vector vec) { 7 | std::cout << "vec" << i << ": "; 8 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 9 | std::cout << std::endl; 10 | } 11 | 12 | int main() { 13 | std::vector vec1 = {0, 1, 2, 3, 4}; 14 | std::vector vec2 = {5, 6, 7, 8, 9, 10, 11, 12}; 15 | 16 | // Swap all elements from range1 with the corresponding element of range2. 17 | // size(range2) must be equal or larger than size(range1). 18 | // Returns a reference to range2. 19 | boost::range::swap_ranges(vec1, vec2); 20 | 21 | display_result(1, vec1); 22 | display_result(2, vec2); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /templates/entry.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{view.fun.name}} 6 | 7 | 8 | 9 | 10 | 11 |

{{view.fun.name}}

12 |

Headers

13 | {{view.fun.name}} is available by including any of the following headers: 14 |
    15 | {% for header in view.fun.headers %} 16 |
  • {{header}}
  • 17 | {% endfor %} 18 |
19 |

Examples

20 | {% for example in view.fun.examples %} 21 |

{{example.name}}

22 |
{{example.code}}
23 | Output: 24 |
{{example.output}}
25 | {% endfor %} 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/unique.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 1, 3, 1, 3, 3}; 7 | 8 | // unique() is a wrapper for std::unique(). Elements in the input range 9 | // are reordered, but the size of the input container is not changed. 10 | // Returns the range [begin, unique_end) by default, where unique_end 11 | // points one past the last unique element. 12 | auto unique_rng = boost::range::unique(vec); 13 | 14 | std::cout << "input vector after unique(vec): "; 15 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 16 | std::cout << std::endl; 17 | 18 | std::cout << "Range returned by unique(): "; 19 | boost::range::copy(unique_rng, std::ostream_iterator(std::cout, " ")); 20 | std::cout << std::endl; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /templates/entry.md: -------------------------------------------------------------------------------- 1 | Title: {{view.fun.name}} 2 | Status: hidden 3 | 4 | ## References 5 | 6 | * [Official documentation]({{ BOOST_DOC_URL + view.fun.doclink }}) 7 | * [Source code]({{ BOOST_HEADER_URL + view.fun.main_header }}) 8 | 9 | ## Headers 10 | `{{view.fun.name}}` is available by including 11 | {% if len(view.fun.headers) > 1 %} any of the following headers:{% else %} the following header:{% endif %} 12 | 13 | {% for header in view.fun.headers %} 14 | * `{{header}}`{% if not loop.last %} or{% endif %} 15 | {%- endfor %} 16 | 17 | ## Examples 18 | {% for example in view.fun.examples %} 19 | ### {{example.name.replace('_', '\\_')}} 20 | 21 | 22 | 23 | :::cpp 24 | {{indent(example.code, ' ')}} 25 | 26 | Output: 27 | 28 | {{indent(example.output or '\u200b', ' ')}} 29 | 30 |   31 | 32 | {% endfor %} 33 | -------------------------------------------------------------------------------- /src/remove_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool is_3_or_4(int i) { 7 | return i == 3 || i == 4; 8 | } 9 | 10 | int main() { 11 | std::vector vec = {1, 2, 3, 4, 5}; 12 | 13 | // remove_if() is a wrapper for std::remove_if(). Elements in the input 14 | // range are reordered, but the size of the input container is not changed. 15 | // An iterator to the new end is returned. 16 | std::vector::iterator end_it = boost::range::remove_if(vec, is_3_or_4); 17 | 18 | std::cout << "input vector after remove_if(): "; 19 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 20 | std::cout << std::endl; 21 | 22 | std::cout << "Index of the returned iterator: " << (end_it - vec.begin()); 23 | std::cout << std::endl; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/boost-range-traversal-1.56.hpp: -------------------------------------------------------------------------------- 1 | // Boost.Range library 2 | // 3 | // Copyright Neil Groves 2014. Use, modification and 4 | // distribution is subject to the Boost Software License, Version 5 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at 6 | // http://www.boost.org/LICENSE_1_0.txt) 7 | // 8 | // For more information, see http://www.boost.org/libs/range/ 9 | // 10 | 11 | #ifndef BOOST_RANGE_TRAVERSAL_HPP 12 | #define BOOST_RANGE_TRAVERSAL_HPP 13 | 14 | #if defined(_MSC_VER) 15 | # pragma once 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace boost 23 | { 24 | template 25 | struct range_traversal 26 | : iterator_traversal::type> 27 | { 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/combine.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | int main() { 10 | std::string str = "abcde"; 11 | std::vector vec = {1, 2, 3, 4, 5}; 12 | 13 | // combine() takes several ranges creates a zipped range, that is a range 14 | // of tuples where each tuple contains corresponding elements from each 15 | // input range. 16 | // The input ranges must have the same size! 17 | // Up to Boost 1.55, two input ranges were supported, with Boost 1.56 and 18 | // higher an arbitrary number of input ranges can be used. 19 | for (const auto & zipped : boost::combine(str, vec)) { 20 | char c; int i; 21 | boost::tie(c, i) = zipped; 22 | 23 | std::cout << "(" << c << ", " << i << ")" << std::endl; 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/replace_copy_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool is_3_or_4(int i) { 7 | return i == 3 || i == 4; 8 | } 9 | 10 | int main() { 11 | std::vector vec = {1, 2, 3, 4, 5}; 12 | std::vector output; 13 | 14 | // replace_copy_if() wraps std::replace_copy_if(). 15 | // Returns an iterator to the end of the output range. 16 | boost::replace_copy_if(vec, std::back_inserter(output), is_3_or_4, 0); 17 | 18 | std::cout << "input vector after replace_copy_if(): "; 19 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 20 | std::cout << std::endl; 21 | 22 | std::cout << "output vector after replace_copy_if(): "; 23 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 24 | std::cout << std::endl; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/partial_sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::vector vec = {1, 2, 3, 4, 5}; 9 | std::vector sums; 10 | std::vector products; 11 | 12 | // Straight-forward wrapper around std::partial_sum(). 13 | // Returns an iterator to the end of the output range. 14 | boost::partial_sum(vec, std::back_inserter(sums)); 15 | boost::partial_sum(vec, std::back_inserter(products), std::multiplies()); 16 | 17 | std::cout << "Sums(1..5): "; 18 | boost::copy(sums, std::ostream_iterator(std::cout, " ")); 19 | std::cout << std::endl; 20 | 21 | std::cout << "Products(1..5): "; 22 | boost::copy(products, std::ostream_iterator(std::cout, " ")); 23 | std::cout << std::endl; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/map_adaptors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | const std::map numbermap = { 9 | std::make_pair(1, "one"), 10 | std::make_pair(2, "two"), 11 | std::make_pair(3, "three"), 12 | }; 13 | 14 | @ifdef PIPE 15 | @define KEYS map_keys 16 | @define VALUES map_values 17 | @else 18 | @define KEYS keys 19 | @define VALUES values 20 | @endif 21 | 22 | int main() { 23 | std::cout << "map keys: "; 24 | for (const auto & key : CALL0(boost::adaptors::KEYS,numbermap)) { 25 | std::cout << key << " "; 26 | } 27 | std::cout << std::endl; 28 | 29 | std::cout << "map values: " 30 | << boost::algorithm::join(CALL0(boost::adaptors::VALUES,numbermap), " ") 31 | << std::endl; 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/unique_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector vec = {1, 1, 3, 1, 3, 3}; 7 | std::vector output; 8 | 9 | // unique_copy() wraps std::unique_copy(). Elements in the input 10 | // range are copied to the output iterator if they are not equal to the 11 | // next input value. The input range is not modified. 12 | // Returns an iterator to the end of the output range. 13 | boost::unique_copy(vec, std::back_inserter(output)); 14 | 15 | std::cout << "input vector after unique_copy(): "; 16 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 17 | std::cout << std::endl; 18 | 19 | std::cout << "output vector after unique_copy(): "; 20 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 21 | std::cout << std::endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/remove_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 2, 3, 4, 5}; 8 | std::vector output; 9 | 10 | // remove_copy() wraps std::remove_copy(). Elements in the input 11 | // range are copied to the output iterator if they are not equal to the 12 | // removal value. The input range is not modified. 13 | // Returns an iterator to the end of the output range. 14 | boost::remove_copy(vec, std::back_inserter(output), 2); 15 | 16 | std::cout << "input vector after remove_copy(): "; 17 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 18 | std::cout << std::endl; 19 | 20 | std::cout << "output vector after remove_copy(): "; 21 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 22 | std::cout << std::endl; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/inner_product.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec1 = {1, 2, 2}; 8 | std::vector vec2 = {3, 6, 9}; 9 | 10 | // Straight-forward wrapper around std::inner_product(). 11 | // Returns the inner product of the two input ranges. 12 | int ip = boost::inner_product(vec1, vec2, 0); 13 | 14 | // Optionally, two binary predicates can be specified to be used instead 15 | // of addition and multiplication steps in the calculation. 16 | // The example shown here is equivalent to the three-argument call. 17 | int ip2 = boost::inner_product(vec1, vec2, 0, 18 | std::plus(), std::multiplies()); 19 | 20 | std::cout << "Inner product: " << ip << std::endl; 21 | std::cout << "Inner product (explicit binary operations): " << ip2 << std::endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(const std::vector vec) { 7 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 8 | std::cout << std::endl; 9 | std::cout << "--------- ---------" << std::endl; 10 | std::cout << " < 5 >= 5" << std::endl; 11 | } 12 | 13 | int main() { 14 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 15 | 16 | // partition() reorders the input range so that all elements for which 17 | // the predicate function is true come first. All others come second. 18 | // Returns an iterator to the first element of the second group. 19 | auto middle = boost::range::partition(vec, [](int v) { return v < 5; }); 20 | 21 | std::cout << (middle - vec.begin()) << " elements are < 5" << std::endl << std::endl; 22 | display_result(vec); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/istream_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | 8 | int main() { 9 | // istream_range() turns an input iterator into a range object. 10 | // The template argument type defines the type read from the stream. 11 | // See std::istream_iterator for more information. 12 | std::istringstream ss("The quick brown fox jumps over the lazy dog."); 13 | auto input_range = boost::istream_range(ss); 14 | for (const auto &input : input_range | boost::adaptors::strided(2)) { 15 | std::cout << "[" << input << "] "; 16 | } 17 | std::cout << std::endl; 18 | 19 | std::istringstream ss2("8 2"); 20 | auto input_range2 = boost::istream_range(ss2); 21 | for (int input : input_range2 | boost::adaptors::replaced(8, 4)) { 22 | std::cout << input; 23 | } 24 | std::cout << std::endl; 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(const std::vector vec) { 7 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 8 | std::cout << std::endl; 9 | } 10 | 11 | void sort_without_predicate() { 12 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 13 | 14 | // sort(vec) rearranges vec so that the elements are in ascending order. 15 | // Returns a reference to the input range. 16 | boost::range::sort(vec); 17 | 18 | display_result(vec); 19 | } 20 | 21 | void sort_with_predicate() { 22 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 23 | 24 | // And overload that takes a sorting predicate is also available: 25 | boost::range::sort(vec, std::greater()); 26 | 27 | display_result(vec); 28 | } 29 | 30 | int main() { 31 | sort_without_predicate(); 32 | sort_with_predicate(); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/general.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | int main() { 8 | std::string str = "abcde"; 9 | std::vector vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 10 | 11 | // Convert ranges into begin/end iterators. 12 | // Mainly useful when writing range-based wrappers for functions that take 13 | // begin/end iterators as arguments. 14 | auto str_begin = boost::begin(str); 15 | auto str_end = boost::end(str); 16 | auto vec_rbegin = boost::rbegin(vec); 17 | auto vec_rend = boost::rend(vec); 18 | auto str_cbegin = boost::const_begin(str); 19 | auto str_cend = boost::const_end(str); 20 | auto vec_crbegin = boost::const_rbegin(vec); 21 | auto vec_crend = boost::const_rend(vec); 22 | 23 | // Suppress unused variable warnings. 24 | (void)str_begin; (void)str_end; 25 | (void)vec_rbegin; (void)vec_rend; 26 | (void)str_cbegin; (void)str_cend; 27 | (void)vec_crbegin; (void)vec_crend; 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /src/search_n.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iequals(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) == std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | const std::string haystack = "bbb AAA aaa"; 12 | 13 | // Return an iterator to the first occurance of of repeated elements within 14 | // a range. The repeated elements are passed as count/value arguments, 15 | // like they are in the fill constructors of vectors or strings. 16 | // If the value is not found, the end iterator is returned. 17 | auto it = boost::range::search_n(haystack, 3, 'a'); 18 | auto iit = boost::range::search_n(haystack, 3, 'a', iequals); 19 | 20 | std::cout << "First occurrence of \"aaa\": " 21 | << (it - haystack.begin()) << std::endl; 22 | std::cout << "First occurrence of \"aaa\" (case-insensitive): " 23 | << (iit - haystack.begin()) << std::endl; 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/remove_copy_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool is_3_or_4(int i) { 7 | return i == 3 || i == 4; 8 | } 9 | 10 | int main() { 11 | std::vector vec = {1, 2, 3, 4, 5}; 12 | std::vector output; 13 | 14 | // remove_copy_if() wraps std::remove_copy_if(). Elements in the input 15 | // range are copied to the output iterator if they are not filtered by the 16 | // predicate function. The input is not modified. 17 | // Returns an iterator to the end of the output range. 18 | boost::remove_copy_if(vec, std::back_inserter(output), is_3_or_4); 19 | 20 | std::cout << "input vector after remove_copy_if(): "; 21 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 22 | std::cout << std::endl; 23 | 24 | std::cout << "output vector after remove_copy_if(): "; 25 | boost::range::copy(output, std::ostream_iterator(std::cout, " ")); 26 | std::cout << std::endl; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/stable_partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void display_result(const std::vector vec) { 6 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 7 | std::cout << std::endl; 8 | std::cout << "--------- ---------" << std::endl; 9 | std::cout << " < 5 >= 5" << std::endl; 10 | } 11 | 12 | int main() { 13 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 14 | 15 | // stable_partition() reorders the input range so that all elements for 16 | // which the predicate function is true come first. All others come second. 17 | // Compared to partition(), this function keeps the relative order of 18 | // elements within each group. 19 | // Returns an iterator to the first element of the second group. 20 | auto middle = boost::range::stable_partition(vec, [](int v) { return v < 5; }); 21 | 22 | std::cout << (middle - vec.begin()) << " elements are < 5" << std::endl << std::endl; 23 | display_result(vec); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/inplace_merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec = {1, 3, 5, 2, 4}; 8 | 9 | // vec contains two ordered lists of numbers: one in [0, 3) and one in [3, 5). 10 | // inplace_merge() merges them so that vec contains a single ordered list. 11 | boost::range::inplace_merge(vec, vec.begin() + 3); 12 | 13 | std::cout << "After merging: "; 14 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 15 | std::cout << std::endl; 16 | 17 | 18 | std::vector vec2 = {5, 3, 1, 4, 2}; 19 | 20 | // There is also an overload that accepts an ordering predicate. 21 | // We use this merge lists of integers sorted largest-number-first. 22 | boost::range::inplace_merge(vec2, vec2.begin() + 3, std::greater()); 23 | 24 | std::cout << "After merging (descending): "; 25 | boost::range::copy(vec2, std::ostream_iterator(std::cout, " ")); 26 | std::cout << std::endl; 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/set_union.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iless(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string result, iresult; 12 | 13 | // Copy the sorted union of two sorted input ranges (i.e. elements 14 | // occuring in either range) to an output iterator. Duplicate elements 15 | // are copied only once. 16 | // An optional ordering predicate is supported as well. 17 | // Returns an iterator pointing to the end of the output range. 18 | boost::range::set_union(std::string{"DFae"}, std::string{"AFbc"}, 19 | std::back_inserter(result)); 20 | boost::range::set_union(std::string{"aDeF"}, std::string{"AbcF"}, 21 | std::back_inserter(iresult), 22 | iless); 23 | 24 | std::cout << "Union: " << result << std::endl; 25 | std::cout << "Union (case-insensitive): " << iresult << std::endl; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/set_intersection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iless(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string result, iresult; 12 | 13 | // Copy the sorted intersection of two sorted input ranges (i.e. elements 14 | // occuring in both ranges) to an output iterator. 15 | // An optional ordering predicate is supported as well. 16 | // Returns an iterator pointing to the end of the output range. 17 | boost::range::set_intersection(std::string{"DFae"}, std::string{"AFbc"}, 18 | std::back_inserter(result)); 19 | boost::range::set_intersection(std::string{"aDeF"}, std::string{"AbcF"}, 20 | std::back_inserter(iresult), 21 | iless); 22 | 23 | std::cout << "Intersection: " << result << std::endl; 24 | std::cout << "Intersection (case-insensitive): " << iresult << std::endl; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/set_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iless(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string result, iresult; 12 | 13 | // Copy the sorted difference set of two sorted input ranges (i.e. elements 14 | // occuring in the first but not in the second range) to an output iterator. 15 | // An optional ordering predicate is supported as well. 16 | // Returns an iterator pointing to the end of the output range. 17 | boost::range::set_difference(std::string{"DFae"}, std::string{"AFbc"}, 18 | std::back_inserter(result)); 19 | boost::range::set_difference(std::string{"aDeF"}, std::string{"AbcF"}, 20 | std::back_inserter(iresult), 21 | iless); 22 | 23 | std::cout << "Difference: " << result << std::endl; 24 | std::cout << "Difference (case-insensitive): " << iresult << std::endl; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boost Range For Humans 2 | 3 | Source code for [Boost Range For Humans][br4h], a website that has full, 4 | self-contained example code for each function in [Boost Range][br]. 5 | 6 | 7 | ### Building 8 | 9 | Build requirements: libboost-all-dev gpp python3-jinja2 10 | 11 | The documentation is built in Markdown format using a GNU Make. 12 | Full build steps: 13 | 14 | make markdown 15 | 16 | For more details about the available build options, run `make help`. 17 | 18 | 19 | ### Notes about the build process 20 | 21 | Internally, the build process is complicated by the fact that range adaptors 22 | have two different syntaxes: function call and pipe. To avoid 23 | duplicate example code, these two variants are generated by [gpp][] 24 | preprocessing of a common source file. 25 | 26 | Apart from that, the build process is straight-forward: gpp-preprocess sources 27 | – build – run and capture output – generate Markdown. 28 | 29 | [br]: http://www.boost.org/doc/libs/1_61_0/libs/range/doc/html/index.html 30 | [br4h]: https://greek0.net/boost-range/ 31 | [gpp]: http://en.nothingisreal.com/wiki/GPP 32 | -------------------------------------------------------------------------------- /src/copied.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | const std::string str = "abcdef"; 8 | const std::vector vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 9 | 10 | @ifdef PIPE 11 | @define COPY copied 12 | @else 13 | @define COPY copy 14 | @endif 15 | 16 | int main() { 17 | // COPY() is great because the returned range object has a conversion 18 | // operator to any container that supports initialization from a begin/end 19 | // iterator pair. 20 | // Unfortunately, it takes two arguments that define a slice from the input 21 | // range to copy. That's nice if you want to slice, but often you don't. 22 | std::string newstr = CALL2(boost::adaptors::COPY,str,0,4); 23 | std::vector newvec = CALL2(boost::adaptors::COPY,vec,3,6); 24 | 25 | std::cout << "Copied str[0:4] to new string: " << newstr << std::endl; 26 | std::cout << "Copied vec[3:6] to new vector: "; 27 | for (const int i : newvec) { 28 | std::cout << i << " "; 29 | } 30 | std::cout << std::endl; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/numeric_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | void irange_demo() { 8 | // irange() returns a random-access range of numbers from the half-open 9 | // interval [begin, end). 10 | for (int i : boost::irange(5, 10)) { 11 | std::cout << i << " "; 12 | } 13 | std::cout << std::endl; 14 | 15 | // In addition to the two parameter version, there's also a three-parameter 16 | // overload that takes a step size. 17 | for (int i : boost::irange(1, 10, 2)) { 18 | std::cout << i << " "; 19 | } 20 | std::cout << std::endl; 21 | } 22 | 23 | void counting_range_demo() { 24 | // counting_range() returns a range of numbers from the half-open interval 25 | // [begin, end). For typical value types (int, unsigned, ...), a 26 | // RandomAccessRange is returned. 27 | for (int i : boost::counting_range(5, 10)) { 28 | std::cout << i << " "; 29 | } 30 | std::cout << std::endl; 31 | } 32 | 33 | int main() { 34 | irange_demo(); 35 | counting_range_demo(); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/stable_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(const std::vector vec) { 7 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 8 | std::cout << std::endl; 9 | } 10 | 11 | void stable_sort_without_predicate() { 12 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 13 | 14 | // stable_sort(...) rearranges vec so that the elements are in ascending 15 | // order. Equal elements are retain the relative order they had in the 16 | // input range. 17 | // Returns a reference to the input range. 18 | boost::range::stable_sort(vec); 19 | 20 | display_result(vec); 21 | } 22 | 23 | void stable_sort_with_predicate() { 24 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 25 | 26 | // And overload that takes a sorting predicate is also available: 27 | boost::range::stable_sort(vec, std::greater()); 28 | 29 | display_result(vec); 30 | } 31 | 32 | int main() { 33 | stable_sort_without_predicate(); 34 | stable_sort_with_predicate(); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/set_symmetric_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iless(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string result, iresult; 12 | 13 | // Copy the sorted symmetric difference set of two sorted input ranges 14 | // (i.e. elements occuring in either range but not in both) to an 15 | // output iterator. 16 | // An optional ordering predicate is supported as well. 17 | // Returns an iterator pointing to the end of the output range. 18 | boost::range::set_symmetric_difference(std::string{"DFae"}, std::string{"AFbc"}, 19 | std::back_inserter(result)); 20 | boost::range::set_symmetric_difference(std::string{"aDeF"}, std::string{"AbcF"}, 21 | std::back_inserter(iresult), 22 | iless); 23 | 24 | std::cout << "Symmetric difference: " << result << std::endl; 25 | std::cout << "Symmetric difference (case-insensitive): " << iresult << std::endl; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/adjacent_difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | std::vector vec = {1, 2, 4, 6, 9}; 9 | std::vector differences; 10 | std::vector fractions; 11 | 12 | // Wrapper around std::adjacent_difference() 13 | // y[0] = x[0] 14 | // y[1] = x[1] - x[0] 15 | // ... 16 | // 17 | // Returns an iterator to the end of the output range. 18 | boost::adjacent_difference(vec, std::back_inserter(differences)); 19 | 20 | // The three-argument version takes a binary predicate to use instead 21 | // of std::minus. 22 | boost::adjacent_difference(vec, std::back_inserter(fractions), 23 | std::divides()); 24 | 25 | std::cout << "Differences between adjacent elements: "; 26 | boost::copy(differences, std::ostream_iterator(std::cout, " ")); 27 | std::cout << std::endl; 28 | 29 | std::cout << "Fractions between adjacent elements: "; 30 | boost::copy(fractions, std::ostream_iterator(std::cout, " ")); 31 | std::cout << std::endl; 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/mismatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | bool iequals(char lhs, char rhs) { 7 | std::locale loc; 8 | return std::toupper(lhs, loc) == std::toupper(rhs, loc); 9 | } 10 | 11 | 12 | int main() { 13 | std::string s1 = "abcdefg"; 14 | std::string s2 = "abCdXfg"; 15 | 16 | // Return an iterator to the first element that differs between two ranges. 17 | // An optional comparison predicate is supported. 18 | auto it_pair = boost::range::mismatch(s1, s2); 19 | auto iit_pair = boost::range::mismatch(s1, s2, iequals); 20 | 21 | std::cout << "s1 and s2 diverge at position " 22 | << (it_pair.first - s1.begin()) 23 | << " with values " 24 | << *(it_pair.first) 25 | << " and " 26 | << *(it_pair.second) 27 | << std::endl; 28 | 29 | std::cout << "s1 and s2 diverge case-insensitively at position " 30 | << (iit_pair.first - s1.begin()) 31 | << " with values " 32 | << *(iit_pair.first) 33 | << " and " 34 | << *(iit_pair.second) 35 | << std::endl; 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/includes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iless(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string s = "DEabc"; 12 | std::vector vec = {'a', 'b', 'c'}; 13 | 14 | // Return true if all of the elements in the second range are included 15 | // in the first range. Both ranges have to be sorted. 16 | // An optional ordering predicate is accepted. 17 | bool has_ab = boost::range::includes(s, std::string{"ab"}); 18 | bool has_de = boost::range::includes(s, std::string{"de"}); 19 | bool has_vec = boost::range::includes(s, vec); 20 | bool ihas_de = boost::range::includes(s, std::string{"de"}, iless); 21 | 22 | std::cout << "'a' and 'b' in s: " << (has_ab ? "true" : "false") << std::endl; 23 | std::cout << "'d' and 'e' in s: " << (has_de ? "true" : "false") << std::endl; 24 | std::cout << "vec{\"abc\"} in s: " 25 | << (has_vec ? "true" : "false") << std::endl; 26 | std::cout << "'d' and 'e' in s (case-insensitive): " 27 | << (ihas_de ? "true" : "false") << std::endl; 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::vector src = {1, 2, 3, 4, 5}; 7 | 8 | // Copy the contents of a range to an output iterator. 9 | // A convenience alias exists in namespace boost: boost::copy(). 10 | boost::range::copy(src, std::ostream_iterator(std::cout, " ")); 11 | std::cout << std::endl; 12 | 13 | // Copy the contents of a range into an empty vector. 14 | std::vector dest1; 15 | boost::range::copy(src, std::back_inserter(dest1)); 16 | 17 | // copy_backward() copies elements from a range, just like copy() does, but: 18 | // - it takes an end iterator as second argument 19 | // - it copies the elements back-to-front (the last element is copied first, 20 | // the first element is copied last) 21 | // 22 | // Due to the first point, it won't work with ostream_iterator or 23 | // back_insert_iterator, so it's of much more limited use than copy(). 24 | std::vector dest(src.size(), 0); 25 | boost::range::copy_backward(src, dest.end()); 26 | for (int i : dest) { 27 | std::cout << i << " "; 28 | } 29 | std::cout << std::endl; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/replaced.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const std::string str = "Boboo"; 7 | 8 | @ifdef PIPE 9 | @define REPLACE replaced 10 | @define REPLACE_IF replaced_if 11 | @define TRANSFORM transformed 12 | @else 13 | @define REPLACE replace 14 | @define REPLACE_IF replace_if 15 | @define TRANSFORM transform 16 | @endif 17 | 18 | bool is_b_ignorecase(char c) { 19 | return c == 'b' || c == 'B'; 20 | } 21 | 22 | int main() { 23 | // REPLACE() is a straight-forward, element-wise replace operation. 24 | // All elements equal to 'o' are replaced with 'a'. 25 | // To get dynamic control over the replacement string, use TRANSFORM(). 26 | std::cout << "Replace 'o' in \"" << str << "\": " 27 | << (CALL2(boost::adaptors::REPLACE,str,'o','a')) 28 | << std::endl; 29 | 30 | // REPLACE_IF() still has a constant replacement value, but whether a 31 | // substitution should be performed is determined by a predicate. 32 | std::cout << "Replace upper and lower case 'b's in \"" << str << "\": " 33 | << (CALL2(boost::adaptors::REPLACE_IF,str,is_b_ignorecase,'j')) 34 | << std::endl; 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/min_max_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const std::string s = "iUaCgT"; 6 | 7 | 8 | bool iless(char lhs, char rhs) { 9 | std::locale loc; 10 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 11 | } 12 | 13 | 14 | void min_demo() { 15 | // Return an iterator pointing to the minimum element in the input range. 16 | // Optionally, an ordering predicate can be provided. 17 | auto min_it = boost::range::min_element(s); 18 | auto imin_it = boost::range::min_element(s, iless); 19 | 20 | std::cout << "min element: " << *min_it << std::endl; 21 | std::cout << "min element (case insenitive): " << *imin_it << std::endl; 22 | } 23 | 24 | void max_demo() { 25 | // Return an iterator pointing to the maximum element in the input range. 26 | // Optionally, an ordering predicate can be provided. 27 | auto max_it = boost::range::max_element(s); 28 | auto imax_it = boost::range::max_element(s, iless); 29 | 30 | std::cout << "max element: " << *max_it << std::endl; 31 | std::cout << "max element (case insenitive): " << *imax_it << std::endl; 32 | } 33 | 34 | int main() { 35 | min_demo(); 36 | max_demo(); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /src/partial_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(const std::vector vec) { 7 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 8 | std::cout << std::endl; 9 | std::cout << "---------" << std::endl; 10 | std::cout << " sorted" << std::endl << std::endl; 11 | } 12 | 13 | void partial_sort_without_predicate() { 14 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 15 | 16 | // partial_sort(..., n) rearranges vec so that [0, n) contains the smallest 17 | // values in vec in sorted order. [n, end) will hold the rest of the 18 | // elements in random order. 19 | boost::range::partial_sort(vec, vec.begin() + 5); 20 | 21 | display_result(vec); 22 | } 23 | 24 | void partial_sort_with_predicate() { 25 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 26 | 27 | // And overload that takes a sorting predicate is also available: 28 | boost::range::partial_sort(vec, vec.begin() + 5, std::greater()); 29 | 30 | display_result(vec); 31 | } 32 | 33 | int main() { 34 | partial_sort_without_predicate(); 35 | partial_sort_with_predicate(); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool iequals(char lhs, char rhs) { 6 | std::locale loc; 7 | return std::toupper(lhs, loc) == std::toupper(rhs, loc); 8 | } 9 | 10 | int main() { 11 | std::string s1 = "abc"; 12 | std::string s2 = "ABC"; 13 | std::string s3 = "ab"; 14 | std::vector vec = {'a', 'b', 'c'}; 15 | 16 | // Return true if the input ranges have the same size and their elements 17 | // are equal. As a range algorithm, it can accept differing underlying 18 | // containers (e.g. string and vector). 19 | // Accepts an optional equality predicate. 20 | bool eq_s1_s2 = boost::range::equal(s1, s2); 21 | bool eq_s1_s3 = boost::range::equal(s1, s3); 22 | bool eq_s1_vec = boost::range::equal(s1, vec); 23 | bool ieq_s1_s2 = boost::range::equal(s1, s2, iequals); 24 | 25 | std::cout << "equal(s1, s2): " << (eq_s1_s2 ? "true" : "false") << std::endl; 26 | std::cout << "equal(s1, s3): " << (eq_s1_s3 ? "true" : "false") << std::endl; 27 | std::cout << "equal(s1, vec): " << (eq_s1_vec ? "true" : "false") << std::endl; 28 | std::cout << "equal(s1, s2, iequals): " << (ieq_s1_s2 ? "true" : "false") 29 | << std::endl; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/indexed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | @ifdef PIPE 5 | @define INDEX indexed 6 | @else 7 | @define INDEX index 8 | @endif 9 | 10 | // The INDEX() implementation in Boost < 1.56 can't be recommended. 11 | // It's clunky and doesn't work with range-based for loops. 12 | // If you can't upgrade, grab the backported "boost-range-indexed-1.56.hpp" and 13 | // "boost-range-traversal-1.56.hpp from this repo. They have to be included 14 | // before other Boost Range headers. 15 | #include "boost-range-indexed-1.56.hpp" 16 | #include 17 | 18 | const std::string str = "beebop"; 19 | 20 | 21 | int main() { 22 | // INDEX() is analogous to Python's enumerate(). Given a Range, 23 | // it gives access to the elements as well as their indices. 24 | // Boost 1.56 or higher is required for this to work properly. 25 | // 26 | // The (optional) parameter sets the index of the first element (default: 0) 27 | std::cout << "Enumeration of a string" << std::endl; 28 | for (const auto & element : CALL1(boost::adaptors::INDEX,str,0)) { 29 | std::cout << element.index() 30 | << " : " 31 | << element.value() 32 | << std::endl; 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/equal_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool iless(char lhs, char rhs) { 7 | std::locale loc; 8 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 9 | } 10 | 11 | int main() { 12 | std::string s = "abbCCCcccd"; // Note: 'C' sorts before 'c'! 13 | 14 | // equal_range() wraps std::equal_range() and has the same interface. 15 | // It expects a sorted input range and returns a range (as std::pair) 16 | // of elements equal to its second argument. 17 | // The optional third parameter is a binary sorting predicate that must 18 | // implement a less-then comparison (not equality comparison). 19 | // The iterator-pair can be used as input for many Boost Range algorithms. 20 | auto c_range = boost::range::equal_range(s, 'c'); 21 | auto cC_range = boost::range::equal_range(s, 'c', iless); 22 | 23 | std::cout << "Range of c's in \"" << s << "\": "; 24 | boost::copy(c_range, std::ostream_iterator(std::cout, " ")); 25 | std::cout << std::endl; 26 | 27 | std::cout << "Range of c's in \"" << s << "\" (case-insensitive): "; 28 | boost::copy(cC_range, std::ostream_iterator(std::cout, " ")); 29 | std::cout << std::endl; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/for_each.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void for_each_unary() { 8 | std::vector vec = {1, 2, 3, 4, 5}; 9 | 10 | // for_each() takes a range and calls a unary function on each element. 11 | // Returns the unary predicate function, for whatever odd reason. 12 | boost::range::for_each(vec, [](int value) { 13 | std::cout << value << std::endl; 14 | }); 15 | } 16 | 17 | void for_each_binary() { 18 | std::vector even = {2, 4, 6, 8, 5}; 19 | std::vector odd = {1, 3, 5, 7}; 20 | 21 | // for_each() takes a two ranges and a binary predicate. The predicate 22 | // function is called with corresponding values from the two ranges. 23 | // Iteration stops at the end of the shorter range. 24 | // Returns the binary predicate function, for whatever odd reason. 25 | boost::range::for_each(even, odd, [](int e, int o) { 26 | std::cout << e << " -- " << o << std::endl; 27 | }); 28 | } 29 | 30 | 31 | int main() { 32 | std::cout << "Unary for_each():" << std::endl; 33 | for_each_unary(); 34 | 35 | std::cout << std::endl; 36 | std::cout << "Binary for_each():" << std::endl; 37 | for_each_binary(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/nth_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void display_result(const std::vector vec) { 7 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 8 | std::cout << std::endl; 9 | std::cout << "--------- ^ -------" << std::endl; 10 | std::cout << "< vec[5] > vec[5]" << std::endl << std::endl; 11 | } 12 | 13 | void nth_element_without_predicate() { 14 | std::vector vec = {3, 9, 0, 6, 4, 8, 2, 5, 7, 1}; 15 | 16 | // nth_element(..., n) arranges so that vec[n] contains the element that 17 | // would be at index n in a sorted vector. All positions before n contain 18 | // smaller values (not necessarily sorted). All positions after n contain 19 | // larger values (not necessarily sorted). 20 | boost::range::nth_element(vec, vec.begin() + 5); 21 | 22 | display_result(vec); 23 | } 24 | 25 | void nth_element_with_predicate() { 26 | std::vector vec = {3, 6, 0, 9, 4, 8, 2, 7, 5, 1}; 27 | 28 | // A version that accepts an explicit ordering predicate is also available. 29 | boost::range::nth_element(vec, vec.begin() + 5, std::less()); 30 | 31 | display_result(vec); 32 | } 33 | 34 | int main() { 35 | nth_element_without_predicate(); 36 | nth_element_with_predicate(); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /src/lexicographical_compare.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool iless(char lhs, char rhs) { 7 | std::locale loc; 8 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 9 | } 10 | 11 | int main() { 12 | std::string s1 = "abc"; 13 | std::string s2 = "ABD"; 14 | std::string s3 = "ab"; 15 | std::vector vec = {'c', 'c'}; 16 | 17 | // Compare two ranges lexicographically, by applying operator<(), or a 18 | // supplied binary predicate to each pair of elements. 19 | // Can be used as a less-than operator for ranges. 20 | bool lt_s1_s2 = boost::range::lexicographical_compare(s1, s2); 21 | bool lt_s1_s3 = boost::range::lexicographical_compare(s1, s3); 22 | bool lt_s1_vec = boost::range::lexicographical_compare(s1, vec); 23 | bool ilt_s1_s2 = boost::range::lexicographical_compare(s1, s2, iless); 24 | 25 | std::cout << "lexicographical_compare(s1, s2): " << (lt_s1_s2 ? "true" : "false") << std::endl; 26 | std::cout << "lexicographical_compare(s1, s3): " << (lt_s1_s3 ? "true" : "false") << std::endl; 27 | std::cout << "lexicographical_compare(s1, vec): " << (lt_s1_vec ? "true" : "false") << std::endl; 28 | std::cout << "lexicographical_compare(s1, s2, iequals): " << (ilt_s1_s2 ? "true" : "false") 29 | << std::endl; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/any_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | 8 | // any_range() is a range object that can represent vectors, lists, or other 9 | // range objects. It can be used in interfaces to hide the type of the 10 | // underlying range, which decouples the interface from the implementation. 11 | // The different internal storage container types can be used without affecting 12 | // the public interface. 13 | // 14 | // Note that any_range() does not copy the input range. The range remains valid 15 | // only as long as the underlying containers exist. In other words, you can't 16 | // return an any_range() of a temporary variable! 17 | // Hence the static list/vector in the example below. 18 | 19 | typedef boost::any_range int_any_range; 24 | 25 | int_any_range make_range(bool use_list) { 26 | static std::vector vec = {1, 2, 3}; 27 | static std::list lst = {1, 2, 3}; 28 | 29 | if (use_list) { 30 | return lst; 31 | } else { 32 | return vec; 33 | } 34 | } 35 | 36 | int main() { 37 | for (const auto & i : make_range(false)) { 38 | std::cout << i << " "; 39 | } 40 | std::cout << std::endl; 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void merge_without_predicate() { 7 | std::vector input1 = {1, 3, 5}; 8 | std::vector input2 = {2, 4}; 9 | std::vector merged; 10 | 11 | // merged() takes two sorted input ranges and combines them into a single 12 | // output range, which is written to the output iterator argument. 13 | // Currently, there's no way to get a merged range directly. 14 | boost::range::merge(input1, input2, std::back_inserter(merged)); 15 | 16 | std::cout << "Merged: "; 17 | boost::range::copy(merged, std::ostream_iterator(std::cout, " ")); 18 | std::cout << std::endl; 19 | } 20 | 21 | void merge_with_predicate() { 22 | std::vector input1 = {5, 3, 1}; 23 | std::vector input2 = {4, 2}; 24 | std::vector merged; 25 | 26 | // There is also an overload which takes a sorting predicate. Here, we 27 | // use it for merging two input ranges sorted largest-number-first. 28 | boost::range::merge(input1, input2, std::back_inserter(merged), std::greater()); 29 | 30 | std::cout << "Merged (descending): "; 31 | boost::range::copy(merged, std::ostream_iterator(std::cout, " ")); 32 | std::cout << std::endl; 33 | } 34 | 35 | int main() { 36 | merge_without_predicate(); 37 | merge_with_predicate(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/upper_bound.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool iless(char lhs, char rhs) { 7 | std::locale loc; 8 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 9 | } 10 | 11 | void upper_bound_without_predicate() { 12 | std::string s = "accceg"; 13 | 14 | // Return an iterator pointing to the first element that is less or equal 15 | // to the value argument. 16 | // Requires a sorted (or at least partitioned) input range. 17 | std::string::iterator it_b = boost::range::upper_bound(s, 'b'); 18 | std::string::iterator it_c = boost::range::upper_bound(s, 'c'); 19 | 20 | std::cout << "Index of upper_bound(s, 'b'): " << (it_b - s.begin()) << std::endl; 21 | std::cout << "Index of upper_bound(s, 'c'): " << (it_c - s.begin()) << std::endl; 22 | } 23 | 24 | void upper_bound_with_predicate() { 25 | std::string s = "aCcCEg"; 26 | 27 | // An overload that takes an ordering predicate is also available. 28 | std::string::iterator it_b = boost::range::upper_bound(s, 'b', iless); 29 | std::string::iterator it_c = boost::range::upper_bound(s, 'c', iless); 30 | 31 | std::cout << "Index of upper_bound(s, 'b', iless): " << (it_b - s.begin()) << std::endl; 32 | std::cout << "Index of upper_bound(s, 'c', iless): " << (it_c - s.begin()) << std::endl; 33 | } 34 | 35 | int main() { 36 | upper_bound_without_predicate(); 37 | upper_bound_with_predicate(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/lower_bound.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool iless(char lhs, char rhs) { 7 | std::locale loc; 8 | return std::toupper(lhs, loc) < std::toupper(rhs, loc); 9 | } 10 | 11 | void lower_bound_without_predicate() { 12 | std::string s = "accceg"; 13 | 14 | // Return an iterator pointing to the first element that is greater 15 | // or equal to the value argument. 16 | // Requires a sorted (or at least partitioned) input range. 17 | std::string::iterator it_b = boost::range::lower_bound(s, 'b'); 18 | std::string::iterator it_c = boost::range::lower_bound(s, 'c'); 19 | 20 | std::cout << "Index of lower_bound(s, 'b'): " << (it_b - s.begin()) << std::endl; 21 | std::cout << "Index of lower_bound(s, 'c'): " << (it_c - s.begin()) << std::endl; 22 | } 23 | 24 | void lower_bound_with_predicate() { 25 | std::string s = "aCcCEg"; 26 | 27 | // An overload that takes an ordering predicate is also available. 28 | std::string::iterator it_b = boost::range::lower_bound(s, 'b', iless); 29 | std::string::iterator it_c = boost::range::lower_bound(s, 'c', iless); 30 | 31 | std::cout << "Index of lower_bound(s, 'b', iless): " << (it_b - s.begin()) << std::endl; 32 | std::cout << "Index of lower_bound(s, 'c', iless): " << (it_c - s.begin()) << std::endl; 33 | } 34 | 35 | int main() { 36 | lower_bound_without_predicate(); 37 | lower_bound_with_predicate(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void display_result(const std::vector vec) { 6 | boost::range::copy(vec, std::ostream_iterator(std::cout, " ")); 7 | std::cout << std::endl; 8 | } 9 | 10 | int sum(int lhs, int rhs) { 11 | return lhs + rhs; 12 | } 13 | 14 | int square(int i) { 15 | return i * i; 16 | } 17 | 18 | void transform_one() { 19 | std::vector input = {0, 1, 2, 3, 4}; 20 | std::vector output; 21 | 22 | // transform() applies a unary predicate function to each element in 23 | // the input range and writes the result to an output iterator. 24 | // Returns an iterator to the end of the output. 25 | boost::range::transform(input, std::back_inserter(output), square); 26 | 27 | display_result(output); 28 | } 29 | 30 | void transform_two() { 31 | std::vector input1 = {0, 1, 2, 3, 4}; 32 | std::vector input2 = {3, 3, 5, 5, 5}; 33 | std::vector output; 34 | 35 | // A version that accepts two ranges and a binary predicate function is 36 | // also available. The two input ranges are combined using the predicate 37 | // and the result is written to the output iterator. 38 | // Returns an iterator to the end of the output. 39 | boost::range::transform(input1, input2, std::back_inserter(output), sum); 40 | 41 | display_result(output); 42 | } 43 | 44 | int main() { 45 | transform_one(); 46 | transform_two(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/iterator_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | 8 | void iterator_range_demo() { 9 | std::stringstream ss("The quick brown fox jumps over the lazy dog."); 10 | auto begin = std::istream_iterator(ss); 11 | auto end = std::istream_iterator(); 12 | 13 | // iterator_range() creates a range object from a begin and end iterator. 14 | // Since ranges are constructed implicitly from containers that have 15 | // .begin() and .end() methods, it's mostly useful for wrapping custom 16 | // iterators (e.g. turning a database_row_iterator into a range). 17 | // 18 | // Note: Contrived example, use istream_range in production code. 19 | auto range = boost::iterator_range(begin, end); 20 | for (const auto & word : range) { 21 | std::cout << "[" << word << "] "; 22 | } 23 | std::cout << std::endl; 24 | } 25 | 26 | void make_iterator_range_demo() { 27 | std::stringstream ss("The quick brown fox jumps over the lazy dog."); 28 | auto begin = std::istream_iterator(ss); 29 | auto end = std::istream_iterator(); 30 | 31 | // In practice, it's more convenient to use the make_iterator_range() 32 | // function that deduces the template type automatically. 33 | for (const auto & word : boost::make_iterator_range(begin, end)) { 34 | std::cout << "[" << word << "] "; 35 | } 36 | std::cout << std::endl; 37 | } 38 | 39 | int main() { 40 | iterator_range_demo(); 41 | make_iterator_range_demo(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | const std::string haystack = "ABC abc abc"; 7 | const std::string needle = "abc"; 8 | 9 | 10 | bool iequals(char lhs, char rhs) { 11 | std::locale loc; 12 | return std::toupper(lhs, loc) == std::toupper(rhs, loc); 13 | } 14 | 15 | 16 | void search_demo() { 17 | // Return an iterator to the first occurance of one range inside another. 18 | // If the value is not found, the end iterator is returned. 19 | auto it = boost::range::search(haystack, needle); 20 | auto iit = boost::range::search(haystack, needle, iequals); 21 | 22 | std::cout << "First occurrence of \"abc\": " << (it - haystack.begin()) << std::endl; 23 | std::cout << "First occurrence of \"abc\" (case-insensitive): " 24 | << (iit - haystack.begin()) << std::endl; 25 | } 26 | 27 | void find_end_demo() { 28 | // Return an iterator to the last occurance of one range inside another. 29 | // If the value is not found, the end iterator is returned. 30 | auto it = boost::range::find_end(haystack, needle); 31 | auto iit = boost::range::find_end(haystack, needle, iequals); 32 | 33 | std::cout << "Last occurrence of \"abc\": " << (it - haystack.begin()) << std::endl; 34 | std::cout << "Last occurrence of \"abc\" (case-insensitive): " 35 | << (iit - haystack.begin()) << std::endl; 36 | } 37 | 38 | int main() { 39 | // Note that search() and find_end() have corresponding functionality. 40 | // This is not to be confused with find_first_of(). 41 | search_demo(); 42 | find_end_demo(); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | void display(const std::string &caption, const std::vector vec) { 7 | std::cout << caption; 8 | boost::copy(vec, std::ostream_iterator(std::cout, " ")); 9 | std::cout << std::endl; 10 | } 11 | 12 | int main() { 13 | std::vector vec = {1, 3, 9, 4, 16, 7}; 14 | 15 | // make_heap() turns the input range to a heap. By default, a max-heap 16 | // is created, but this can be overridden by passing a different ordering 17 | // predicate. 18 | // Returns a reference to the input range. 19 | boost::range::make_heap(vec); 20 | display("Initial heap: ", vec); 21 | 22 | // pop_heap() rearranges the input range so that [0, end-1) is a new 23 | // max-heap and rng[end-1] holds the previous max element. 24 | // Removal of elements from the heap always consists of this 25 | // pop_heap()/pop_back() cascade. 26 | // Returns a reference to the input range. 27 | boost::range::pop_heap(vec); 28 | vec.pop_back(); 29 | display("Heap after pop_heap(): ", vec); 30 | 31 | // push_heap() takes the element at rng[end-1] and inserts it into a 32 | // pre-existing heap in [0, end-1). Heap insertion always consists 33 | // of this push_back/push_heap cascade. 34 | // Returns a reference to the input range. 35 | vec.push_back(32); 36 | boost::range::push_heap(vec); 37 | display("Heap after push_heap(): ", vec); 38 | 39 | // sort_heap() sorts a pre-existing heap in the input range. 40 | // This destroys the heap properties. 41 | boost::range::sort_heap(vec); 42 | display("Heap after sorting: ", vec); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/heap_with_predicate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | void display(const std::string &caption, const std::vector vec) { 7 | std::cout << caption; 8 | boost::copy(vec, std::ostream_iterator(std::cout, " ")); 9 | std::cout << std::endl; 10 | } 11 | 12 | int main() { 13 | std::vector vec = {1, 3, 9, 4, 16, 7}; 14 | 15 | 16 | // make_heap() turns the input range to a heap. By default, a max-heap 17 | // is created, but this can be overridden by passing a different ordering 18 | // predicate. In this case, a min-heap is generated. 19 | // Returns a reference to the input range. 20 | boost::range::make_heap(vec, std::greater()); 21 | display("Initial heap: ", vec); 22 | 23 | // pop_heap() rearranges the input range so that [0, end-1) is a new 24 | // heap and rng[end-1] holds the previous top element. 25 | // Removal of elements from the heap always consists of this 26 | // pop_heap()/pop_back() cascade. 27 | // Returns a reference to the input range. 28 | boost::range::pop_heap(vec, std::greater()); 29 | vec.pop_back(); 30 | display("Heap after pop_heap(): ", vec); 31 | 32 | // push_heap() takes the element at rng[end-1] and inserts it into a 33 | // pre-existing heap in [0, end-1). Heap insertion always consists 34 | // of this push_back/push_heap cascade. 35 | // Returns a reference to the input range. 36 | vec.push_back(32); 37 | boost::range::push_heap(vec, std::greater()); 38 | display("Heap after push_heap(): ", vec); 39 | 40 | // sort_heap() sorts a pre-existing heap in the input range. 41 | // This destroys the heap properties. 42 | boost::range::sort_heap(vec, std::greater()); 43 | display("Heap after sorting: ", vec); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/find.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | const std::string haystack = "ABC abc abc"; 7 | 8 | 9 | bool iequals(char lhs, char rhs) { 10 | std::locale loc; 11 | return std::toupper(lhs, loc) == std::toupper(rhs, loc); 12 | } 13 | 14 | 15 | void find_demo() { 16 | auto it = boost::range::find(haystack, 'a'); 17 | 18 | // Return an iterator to the first occurance of a value in a range. 19 | // If the value is not found, the end iterator is returned. 20 | // No predicate-overload provided, find_if can be used instead. 21 | std::cout << "First 'a' at index: " << (it - haystack.begin()) << std::endl; 22 | } 23 | 24 | void find_if_demo() { 25 | // Return an iterator to the first element in a range that satisfies the 26 | // unary predicate. 27 | // If the value is not found, the end iterator is returned. 28 | auto it = boost::range::find_if(haystack, [](char c) { return iequals(c, 'a'); }); 29 | 30 | std::cout << "First occurrence of 'a' (case-insensitive): " 31 | << (it - haystack.begin()) << std::endl; 32 | } 33 | 34 | void find_first_of_demo() { 35 | // Return an iterator to the first occurance any element from the second 36 | // range within the first. 37 | // If the value is not found, the end iterator is returned. 38 | auto it = boost::range::find_first_of(haystack, "cb"); 39 | auto iit = boost::range::find_first_of(haystack, "cb", iequals); 40 | 41 | std::cout << "First occurrence of either 'b' or 'c': " 42 | << (it - haystack.begin()) << std::endl; 43 | std::cout << "First occurrence of either 'b' or 'c' (case-insensitive): " 44 | << (iit - haystack.begin()) << std::endl; 45 | } 46 | 47 | int main() { 48 | find_demo(); 49 | find_if_demo(); 50 | find_first_of_demo(); 51 | 52 | // std::find_last_of() is currently not wrapped in Boost Range. 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/string_conversions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | // as_literal() and as_array() need explicit imports. 7 | #include 8 | #include 9 | 10 | using std::cout; 11 | using std::endl; 12 | 13 | const char * const csptr = "BOOST"; 14 | const char csarr[] = "boost"; 15 | 16 | 17 | void raw_pointer_demo() { 18 | // Calling Boost Range functions on cstrings doesn't work very well. 19 | // The first doesn't compile, the second gives size() == 6, as it counts 20 | // the terminal \0: 21 | cout << "size(csptr): doesn't compile" /* << boost::size(csptr) */ << endl; 22 | cout << "size(csarr): " << boost::size(csarr) << endl; 23 | } 24 | 25 | void as_literal_demo() { 26 | // boost::as_literal() solves both of these problems by converting the 27 | // cstrings to a string range. The size is 5, as you'd expect from a string. 28 | cout << "size(as_literal(csptr)): " << boost::size(boost::as_literal(csptr)) << endl; 29 | cout << "size(as_literal(csarr)): " << boost::size(boost::as_literal(csarr)) << endl; 30 | } 31 | 32 | void as_array_demo() { 33 | // boost::as_array() serves only a documentary purpose. 34 | // Calling it indicates that the author realizes that the argument is a 35 | // character array, but explicitly wants to treat it as an array as 36 | // opposed to a string. 37 | // Note that the behavior is exactly the same as in raw_pointer_demo(). 38 | cout << "size(as_array(csptr)): doesn't compile" 39 | /* << boost::size(boost::as_array(csptr)) */ << endl; 40 | cout << "size(as_array(csarr)): " << boost::size(boost::as_array(csarr)) << endl; 41 | } 42 | 43 | int main() { 44 | cout << "csptr = (const char *)\"boost\"" << endl; 45 | cout << "csarr = \"boost\"" << endl; 46 | 47 | raw_pointer_demo(); 48 | as_literal_demo(); 49 | as_array_demo(); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/adjacent_filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | const std::vector vec = { 0, 1, 2, 3, 4 }; 8 | 9 | @ifdef PIPE 10 | @define ADJACENT_FILTER adjacent_filtered 11 | @else 12 | @define ADJACENT_FILTER adjacent_filter 13 | @endif 14 | 15 | /** Binary predicate that returns true as long as lhs != constructor_arg */ 16 | class lhs_neq { 17 | public: 18 | explicit lhs_neq(int n) : _n(n) {} 19 | 20 | bool operator()(int lhs, int rhs) { 21 | bool result = (lhs != _n); 22 | std::cout << " called lhs_neq(" << lhs << ", " << rhs << ") -> " 23 | << (result ? "true" : "false") << std::endl; 24 | return result; 25 | } 26 | 27 | private: 28 | int _n; 29 | }; 30 | 31 | 32 | /** Print the results of the ADJACENT_FILTER calls in a readable way */ 33 | void print_result(int n, const std::set &seen_values) { 34 | std::cout << "Pair where lhs = " << n << " removed. Result = {"; 35 | for (int i : vec) { 36 | if (seen_values.count(i)) { 37 | std::cout << i << ", "; 38 | } else { 39 | std::cout << " "; 40 | } 41 | } 42 | std::cout << "}" << std::endl; 43 | } 44 | 45 | 46 | int main() { 47 | for (int n : {0, 1, 2, 3, 4}) { 48 | std::set seen_values; 49 | 50 | // ADJACENT_FILTER() calls the binary predicate for every consecutive 51 | // pair of values in the input range. If the predicate returns false, 52 | // the first value of the pair is removed from the result range. 53 | // 54 | // The last value in the input range is always included (there is no 55 | // pair where it's the first of the two values). 56 | for (int i : CALL1(boost::adaptors::ADJACENT_FILTER,vec,lhs_neq(n))) { 57 | seen_values.insert(i); 58 | } 59 | print_result(n, seen_values); 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /NOTES: -------------------------------------------------------------------------------- 1 | * Currently missing: `type_erased` 2 | See http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html 3 | * Single-pass ranges not supported by `adjacent_filtered` and `uniqued`. 4 | See `src/adjacent_filtered_bug.cpp`. 5 | 6 | ######## 7 | ADAPTORS 8 | ######## 9 | 10 | tokenized 11 | reversed 12 | indirected 13 | indexed 14 | transformed 15 | adjacent_filtered // Bug with single-pass-ranges 16 | filtered 17 | uniqued // Bug with single-pass-ranges 18 | copied 19 | replaced 20 | replaced_if 21 | 22 | map_keys 23 | map_values 24 | sliced 25 | strided 26 | 27 | 28 | 29 | ########## 30 | ALGORITHMS 31 | ########## 32 | 33 | MUTATING 34 | -------- 35 | 36 | copy 37 | copy_backward 38 | fill 39 | fill_n 40 | generate 41 | inplace_merge // https://stackoverflow.com/questions/21624268 42 | merge 43 | nth_element 44 | partial_sort 45 | partition 46 | random_shuffle 47 | remove 48 | remove_if 49 | remove_copy_if // In boost::, not in boost::range:: ! 50 | remove_copy // In boost::, not in boost::range:: ! 51 | replace 52 | replace_copy 53 | replace_copy_if 54 | replace_if 55 | reverse 56 | reverse_copy 57 | rotate 58 | rotate_copy 59 | sort 60 | stable_partition 61 | stable_sort 62 | swap_ranges // requires include 63 | transform 64 | unique 65 | unique_copy 66 | 67 | 68 | 69 | NON-MUTATING 70 | ------------ 71 | 72 | adjacent_find 73 | binary_search 74 | count 75 | count_if 76 | equal 77 | equal_range 78 | for_each 79 | find 80 | find_end 81 | find_first_of 82 | find_if 83 | lexicographical_compare 84 | lower_bound 85 | max_element 86 | min_element 87 | mismatch 88 | search 89 | search_n 90 | upper_bound 91 | 92 | 93 | SET 94 | --- 95 | 96 | includes 97 | set_union 98 | set_intersection 99 | set_difference 100 | set_symmetric_difference 101 | 102 | 103 | HEAP 104 | ---- 105 | 106 | push_heap 107 | pop_heap 108 | make_heap 109 | sort_heap 110 | 111 | 112 | PERMUTATIONS 113 | ------------ 114 | 115 | next_permutation 116 | prev_permutation 117 | 118 | 119 | NEW 120 | --- 121 | 122 | copy_n 123 | erase 124 | for_each 125 | insert 126 | iota 127 | is_sorted 128 | overwrite 129 | push_back 130 | push_front 131 | remove_erase 132 | remove_erase_if 133 | 134 | 135 | NUMERIC 136 | ------- 137 | 138 | accumulate 139 | adjacent_difference 140 | inner_product 141 | partial_sum 142 | -------------------------------------------------------------------------------- /headertree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | import os 5 | import re 6 | 7 | BOOST_MAIN_HEADER = '/usr/include/boost/range.hpp' 8 | BOOST_PATH = '/usr/include/boost/range/' 9 | PREFIX = '/usr/include/' 10 | INCLUDE_RE = re.compile(r'\s*#\s*include\s+<([^>]*)>\s*(//.*)?$') 11 | 12 | 13 | class Includes(object): 14 | def __init__(self, prefix): 15 | self.prefix = prefix 16 | self.includes = dict() 17 | self.included_by = dict() 18 | 19 | def add(self, path): 20 | assert path not in self.includes 21 | 22 | self.includes[path] = set() 23 | with open(path, 'r') as f: 24 | for line in f: 25 | line = line.strip() 26 | m = INCLUDE_RE.match(line) 27 | if not m: 28 | continue 29 | 30 | includename = os.path.join(self.prefix, m.group(1)) 31 | self.includes[path].add(includename) 32 | self.included_by.setdefault(includename, set()).add(path) 33 | 34 | def add_recursive(self, path): 35 | for dirpath, dnames, fnames in os.walk(path): 36 | for f in fnames: 37 | if f.endswith(".hpp"): 38 | self.add(os.path.join(dirpath, f)) 39 | 40 | def _lookup(self, path, result): 41 | if path in result: 42 | return 43 | 44 | if os.path.exists(path): 45 | result.append(path) 46 | 47 | included_by = self.included_by.get(path, set()) 48 | for fname in included_by: 49 | self._lookup(fname, result) 50 | 51 | def _remove_prefix(self, text, prefix): 52 | if text.startswith(prefix): 53 | return text[len(prefix):] 54 | return text 55 | 56 | def lookup(self, path): 57 | if not path.startswith(PREFIX): 58 | path = os.path.join(PREFIX, path) 59 | 60 | result = list() 61 | self._lookup(path, result) 62 | return [self._remove_prefix(p, PREFIX) for p in result] 63 | 64 | def lookup_sensible(self, path): 65 | # Don't return subdirectory headers when looking up parent headers. 66 | headers = self.lookup(path) 67 | if not headers: 68 | return headers 69 | 70 | max_slashes = headers[0].count('/') 71 | return [h for h in headers if h.count('/') <= max_slashes] 72 | 73 | 74 | def main(): 75 | includes = Includes(PREFIX) 76 | includes.add(BOOST_MAIN_HEADER) 77 | includes.add_recursive(BOOST_PATH) 78 | 79 | print('\n'.join(includes.lookup(sys.argv[1]))) 80 | 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /src/tokenized.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const auto WORD_RE = boost::regex("\\w+"); 7 | const auto WHITESPACE_RE = boost::regex("\\s+"); 8 | const auto SUBMATCH_RE = boost::regex("(\\w\\w)(\\w+)"); 9 | 10 | const std::string str = "Lorem ipsum dolor sit amet"; 11 | 12 | 13 | // For tokenization, pipe variant is preferable because it offers sane 14 | // default parameters. In contrast, the tokenize() function does not 15 | // have default parameter values, which makes it more painful to use. 16 | // 17 | // The iterator/range value type is boost::sub_match, which is equivalent 18 | // to std::sub_match. The best documentation for those classes I've found 19 | // is this: http://www.cplusplus.com/sub_match 20 | // 21 | // More in-depth information can be found on: 22 | // http://www.cplusplus.com/reference/regex/regex_token_iterator/regex_token_iterator/ 23 | 24 | 25 | void whole_match_demo() { 26 | // A sub-match index of 0 (the default) indicates "give me each match of 27 | // the RE as a single sub_match object". 28 | std::cout << "Whole word matches, showing off sub_match objects:" << std::endl; 29 | for (const auto & token : str | boost::adaptors::tokenized(WORD_RE)) { 30 | size_t token_begin_idx = token.first - str.begin(); 31 | size_t token_end_idx = token.second - str.begin(); 32 | std::cout << " " 33 | << "token [" << token.str() << "] " 34 | << "begin: " << token_begin_idx << "; " 35 | << "end: " << token_end_idx << "; " 36 | << "length: " << token.length() << ";" 37 | << std::endl; 38 | } 39 | } 40 | 41 | void not_matching_demo() { 42 | // A sub-match index of -1 indicates "give me tokens that don't match the 43 | // regular expression". 44 | std::cout << "Tokens separated by whitespace:" << std::endl << " "; 45 | for (const auto & token : str | boost::adaptors::tokenized(WHITESPACE_RE, -1)) { 46 | std::cout << "[" << token << "] "; 47 | } 48 | std::cout << std::endl; 49 | } 50 | 51 | void one_sub_match_demo() { 52 | // Positive sub-match indices select the corresponding match group from the regex. 53 | std::cout << "First two letters of each word:" << std::endl << " "; 54 | for (const auto & token : str | boost::adaptors::tokenized(SUBMATCH_RE, 1)) { 55 | std::cout << "[" << token << "] "; 56 | } 57 | std::cout << std::endl; 58 | } 59 | 60 | void multi_sub_match_demo() { 61 | // Multiple sub-matches are selected by passing a vector of sub-match 62 | // indices. The resulting range contains one entry for each sub-match 63 | // for every single match. 64 | // I'm not aware of a direct way to get the sub-match index within 65 | // the for loop. A workaround is to use the range adaptor indexed(). 66 | std::vector submaps = {1, 2}; 67 | std::cout << "Full split into sub-matches:" << std::endl << " "; 68 | for (const auto & token : str | boost::adaptors::tokenized(SUBMATCH_RE, submaps)) { 69 | std::cout << "[" << token << "] "; 70 | } 71 | std::cout << std::endl; 72 | } 73 | 74 | int main() { 75 | whole_match_demo(); 76 | not_matching_demo(); 77 | one_sub_match_demo(); 78 | multi_sub_match_demo(); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR := src 2 | PROC_DIR := preprocessed 3 | BIN_DIR := bin 4 | OUT_DIR := output 5 | STAMP_DIR := stamps 6 | MARKDOWN_DIR := markdown 7 | 8 | CXXFLAGS := -Wall -Wextra -Wpedantic -Werror -ggdb -std=c++11 -Isrc 9 | LIBS := -Wl,-lboost_regex 10 | GPP := gpp 11 | GPPMACROS := macros.gpp 12 | GPPFLAGS := -U "" "" "(" "," ")" "(" ")" "@" "" -M "@" "\n" " " " " "\n" "(" ")" -I. --include $(GPPMACROS) 13 | 14 | SRC := $(wildcard $(SRC_DIR)/*.cpp) 15 | SRC_PROC := $(shell grep 'CALL[0-9]' $(SRC) -l ) 16 | SRC_NOPROC := $(shell grep 'CALL[0-9]' $(SRC) -L ) 17 | PROC_FUNC := $(patsubst $(SRC_DIR)/%.cpp,$(PROC_DIR)/%-function.cpp,$(SRC_PROC)) 18 | PROC_PIPE := $(patsubst $(SRC_DIR)/%.cpp,$(PROC_DIR)/%-pipe.cpp,$(SRC_PROC)) 19 | PROC_ALL := $(PROC_FUNC) $(PROC_PIPE) 20 | BINARIES_PROC := $(patsubst $(PROC_DIR)/%.cpp,$(BIN_DIR)/%,$(PROC_ALL)) 21 | BINARIES_NOPROC := $(patsubst $(SRC_DIR)/%.cpp,$(BIN_DIR)/%,$(SRC_NOPROC)) 22 | BINARIES := $(BINARIES_PROC) $(BINARIES_NOPROC) 23 | OUTPUTS := $(patsubst $(BIN_DIR)/%,$(OUT_DIR)/%.out,$(BINARIES)) 24 | COMPARE_STAMPS := $(patsubst $(SRC_DIR)/%.cpp,$(STAMP_DIR)/%-compare.stamp,$(SRC_PROC)) 25 | 26 | 27 | all: markdown 28 | 29 | list-sources: $(SRC_NOPROC) $(PROC_ALL) 30 | @echo $^ 31 | 32 | process: $(PROC_ALL) 33 | 34 | binaries: $(BINARIES) 35 | 36 | outputs: $(OUTPUTS) 37 | 38 | build: outputs $(COMPARE_STAMPS) 39 | 40 | markdown: build 41 | @- mkdir -p $(MARKDOWN_DIR) 42 | $(Q) python3 ./docgen.py --ext md --targetdir $(MARKDOWN_DIR) 43 | 44 | deploy: markdown 45 | $(if $(TARGETDIR),,$(error TARGETDIR is not defined)) 46 | $(Q) cp $(MARKDOWN_DIR)/* $(TARGETDIR) 47 | 48 | clean: 49 | -$(Q) $(RM) $(PROC_DIR)/* $(BIN_DIR)/* $(OUT_DIR)/* $(STAMP_DIR)/* 50 | 51 | help: 52 | @echo 'Makefile for a pelican Web site ' 53 | @echo ' ' 54 | @echo 'Common usage: ' 55 | @echo ' make build build examples and generate output ' 56 | @echo ' make deploy TARGETDIR=~/work/homepage/new/content/pages/boost-range ' 57 | @echo ' deploy markdown doc to TARGETDIR ' 58 | @echo ' ' 59 | @echo 'Other commands: ' 60 | @echo ' make markdown build markdown documentation ' 61 | @echo ' make clean clean autogenerated build files ' 62 | @echo ' make -s list-sources print a list of source files ' 63 | @echo ' ' 64 | @echo 'Options: ' 65 | @echo ' make Q=@ don't show commandlines ' 66 | @echo ' make SHOW_OUTPUT=1 show example binary stdout ' 67 | 68 | 69 | $(PROC_DIR)/%-function.cpp: $(SRC_DIR)/%.cpp $(GPPMACROS) 70 | @- mkdir -p $(PROC_DIR) 71 | $(Q) $(GPP) $(GPPFLAGS) $(GPPEXTRA) $< -o $@ 72 | 73 | $(PROC_DIR)/%-pipe.cpp: $(SRC_DIR)/%.cpp 74 | @- mkdir -p $(PROC_DIR) 75 | $(Q) $(GPP) $(GPPFLAGS) $(GPPEXTRA) $< -o $@ -D PIPE 76 | 77 | $(BIN_DIR)/%: $(PROC_DIR)/%.cpp 78 | @- mkdir -p $(BIN_DIR) 79 | $(Q) $(CXX) $(CXXFLAGS) $(LIBS) -o $@ $< 80 | 81 | $(BIN_DIR)/%: $(SRC_DIR)/%.cpp 82 | @- mkdir -p $(BIN_DIR) 83 | $(Q) $(CXX) $(CXXFLAGS) $(LIBS) -o $@ $< 84 | 85 | $(OUT_DIR)/%.out: $(BIN_DIR)/% 86 | @- mkdir -p $(OUT_DIR) 87 | $(if $(SHOW_OUTPUT),$(Q) echo $<) 88 | $(Q) ./$< > $@ 89 | $(if $(SHOW_OUTPUT),$(Q) cat $@) 90 | 91 | $(STAMP_DIR)/%-compare.stamp: $(OUT_DIR)/%-function.out $(OUT_DIR)/%-pipe.out 92 | @- mkdir -p $(STAMP_DIR) 93 | $(Q) test `md5sum $^ | cut -d ' ' -f 1 | uniq | wc -l` -eq 1 94 | $(Q) touch $@ 95 | 96 | 97 | .PRECIOUS: $(BIN_DIR)/% $(OUT_DIR)/% $(PROC_DIR)/% $(STAMP_DIR)/% 98 | 99 | .PHONY: all list-sources process binaries outputs clean help markdown html deploy 100 | -------------------------------------------------------------------------------- /docgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | '''Generate documentation in markdown or HTML format''' 4 | 5 | import os 6 | import argparse 7 | import csv 8 | import itertools 9 | import subprocess 10 | import textwrap 11 | import types 12 | 13 | import jinja2 14 | 15 | import headertree 16 | 17 | 18 | ENC = 'utf-8' 19 | DEFAULT_INPUT = 'exampletable.txt' 20 | DEFAULT_OUTPUT = 'markdown' 21 | DEFAULT_EXT = 'md' 22 | TEMPLATE_DIR = 'templates' 23 | PROGRAM_STDOUT_DIR = 'output' 24 | 25 | CHECK_FILES_EXCEPTIONS = ['src/adjacent_filtered_bug.cpp'] 26 | CHECK_FUNCTIONS_EXCEPTIONS = [ 27 | 'boost::bidirectional_traversal_tag', # Outside Boost Range 28 | 'boost::regex', # Outside Boost Range 29 | 'boost::tie', # Outside Boost Range 30 | 'boost::copy', # Alias for boost::range::copy 31 | 'boost::sub_match' # Not explicitly documented 32 | ] 33 | 34 | CATEGORY_ORDER = ['General', 35 | 'Ranges', 36 | 'Utilities', 37 | 'Adaptors', 38 | 'Algorithm::Mutating', 39 | 'Algorithm::Non-mutating', 40 | 'Algorithm::Set', 41 | 'Algorithm::Heap', 42 | 'Algorithm::Permutation', 43 | 'Algorithm::New', 44 | 'Algorithm::Numeric', 45 | ] 46 | 47 | 48 | BOOST_VERSION = '1_60_0' 49 | BOOST_HEADER_URL = 'http://www.boost.org/doc/libs/%s/' % BOOST_VERSION 50 | BOOST_DOC_URL = 'http://www.boost.org/doc/libs/%s/libs/range/doc/html/range/reference/' % BOOST_VERSION 51 | 52 | 53 | class Function(object): 54 | def __init__(self, name, category, main_header, headers, doclink, examples): 55 | self.name = name 56 | self.category = Category(category) 57 | self.main_header = main_header 58 | self.headers = headers 59 | self.doclink = doclink 60 | self.examples = [Example(cpp_fname) for cpp_fname in examples] 61 | 62 | @classmethod 63 | def list_from_csv(cls, csv_filename, htree): 64 | functions = list() 65 | with open(csv_filename) as csvfile: 66 | reader = csv.reader(csvfile, delimiter=';') 67 | for row in reader: 68 | name, category, main_header, doclink, examples = row 69 | name = name.strip() 70 | category = category.strip() 71 | main_header = main_header.strip() 72 | doclink = doclink.strip() 73 | examples = examples.strip().split() 74 | 75 | headers = htree.lookup_sensible(main_header) 76 | 77 | fun = cls(name, category, main_header, headers, doclink, 78 | examples) 79 | functions.append(fun) 80 | 81 | # Ensure there are no duplicate function names. 82 | assert len(functions) == len(set(fun.name for fun in functions)) 83 | return functions 84 | 85 | 86 | 87 | 88 | class Example(object): 89 | def __init__(self, cpp_fname): 90 | self.name = os.path.basename(cpp_fname) 91 | self.cpp_fname = cpp_fname 92 | self.output_fname = self._make_output_fname(cpp_fname) 93 | 94 | self.code = open(cpp_fname, encoding=ENC).read() 95 | self.output = open(self.output_fname, encoding=ENC).read() 96 | 97 | def _make_output_fname(self, cpp_fname): 98 | basename = os.path.basename(cpp_fname).replace('.cpp', '.out') 99 | return os.path.join(PROGRAM_STDOUT_DIR, basename) 100 | 101 | 102 | class Category(object): 103 | def __init__(self, category): 104 | self.string = category 105 | self.levels = category.split('::') 106 | 107 | def common_prefix(self, other): 108 | common = [] 109 | for self_lvl, other_lvl in zip(self.levels, other.levels): 110 | if self_lvl != other_lvl: 111 | break 112 | common.append(self_lvl) 113 | 114 | return common 115 | 116 | 117 | def check_all_sources_referenced(functions): 118 | output = subprocess.check_output(['make', '-s', 'list-sources'], 119 | universal_newlines=True) 120 | sources = set(output.split()) 121 | sources -= set(CHECK_FILES_EXCEPTIONS) 122 | 123 | for fun in functions: 124 | sources -= set(ex.cpp_fname for ex in fun.examples) 125 | 126 | if sources: 127 | raise RuntimeError("Not all source files referenced: %r" % sources) 128 | 129 | 130 | def check_all_functions_referenced(functions): 131 | cmd = r"""make -s list-sources | xargs sed -ne 's/.*\(boost::[a-zA-Z0-9_:]*\).*/\1/p'""" 132 | output = subprocess.check_output(cmd, shell=True, universal_newlines=True) 133 | found_functions = set(output.split()) 134 | 135 | found_functions -= set(fun.name for fun in functions) 136 | found_functions -= set(CHECK_FUNCTIONS_EXCEPTIONS) 137 | 138 | if found_functions: 139 | raise RuntimeError("Not all functions referenced: %r" % found_functions) 140 | 141 | 142 | class Writer(object): 143 | def __init__(self, output_directory, ext): 144 | self.output_directory = output_directory 145 | self.ext = ext 146 | 147 | self.environment = jinja2.Environment( 148 | loader=jinja2.FileSystemLoader(TEMPLATE_DIR), 149 | autoescape=self._guess_autoescape, 150 | extensions=['jinja2.ext.autoescape']) 151 | 152 | @staticmethod 153 | def _guess_autoescape(template_name): 154 | if template_name is None or '.' not in template_name: 155 | return False 156 | ext = template_name.rsplit('.', 1)[1] 157 | return ext in ('html', 'htm', 'xml') 158 | 159 | def _group_by_category(self, functions): 160 | def sort_key(fun): 161 | return fun.category.string 162 | 163 | groups = dict() 164 | functions.sort(key=sort_key) 165 | for cat, funs in itertools.groupby(functions, sort_key): 166 | groups[cat] = list(funs) 167 | 168 | return groups 169 | 170 | def _index_fname(self): 171 | return os.path.join(self.output_directory, 'index.' + self.ext) 172 | 173 | def _doc_fname(self, function): 174 | basename = function.name.replace('::', '-') 175 | return os.path.join(self.output_directory, basename + '.' + self.ext) 176 | 177 | def write(self, functions): 178 | self.write_index(functions) 179 | for fun in functions: 180 | self.write_function(fun) 181 | 182 | def write_function(self, fun): 183 | entry_view = types.SimpleNamespace() 184 | entry_view.fun = fun 185 | 186 | template = self.environment.get_template('entry.' + self.ext) 187 | stream = template.stream(view=entry_view, 188 | indent=textwrap.indent, 189 | len=len, 190 | BOOST_HEADER_URL=BOOST_HEADER_URL, 191 | BOOST_DOC_URL=BOOST_DOC_URL 192 | ) 193 | stream.dump(self._doc_fname(fun)) 194 | 195 | def write_index(self, functions): 196 | groups = self._group_by_category(functions) 197 | assert set(groups.keys()) == set(CATEGORY_ORDER) 198 | 199 | index_view = [] 200 | last_cat = Category('') 201 | for cat in CATEGORY_ORDER: 202 | catobj = Category(cat) 203 | common = last_cat.common_prefix(catobj) 204 | common_len = len(common) 205 | last_cat = catobj 206 | 207 | category_view = types.SimpleNamespace() 208 | category_view.level_headers = [None] * 7 209 | 210 | changed = catobj.levels[common_len:] 211 | for i, lvl_name in enumerate(changed): 212 | category_view.level_headers[common_len + i] = lvl_name 213 | 214 | category_view.functions = sorted(groups[cat], 215 | key=lambda fun: fun.name) 216 | 217 | index_view.append(category_view) 218 | 219 | template = self.environment.get_template('index.' + self.ext) 220 | stream = template.stream(view=index_view) 221 | stream.dump(self._index_fname()) 222 | 223 | 224 | def main(): 225 | parser = argparse.ArgumentParser(description=__doc__) 226 | parser.add_argument('--input', action='store', default=DEFAULT_INPUT, 227 | help='input examples.txt file') 228 | parser.add_argument('--ext', choices=['md', 'html'], default=DEFAULT_EXT, 229 | help='choose output file type') 230 | parser.add_argument('--targetdir', action='store', default=DEFAULT_OUTPUT, 231 | help='set an output directory') 232 | 233 | args = parser.parse_args() 234 | 235 | htree = headertree.Includes(headertree.PREFIX) 236 | htree.add(headertree.BOOST_MAIN_HEADER) 237 | htree.add_recursive(headertree.BOOST_PATH) 238 | 239 | functions = Function.list_from_csv(args.input, htree) 240 | 241 | check_all_sources_referenced(functions) 242 | check_all_functions_referenced(functions) 243 | 244 | w = Writer(args.targetdir, args.ext) 245 | w.write(functions) 246 | 247 | if __name__ == '__main__': 248 | main() 249 | -------------------------------------------------------------------------------- /src/boost-range-indexed-1.56.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Neil Groves 2 | // 3 | // Copyright (c) 2010 Ilya Murav'jov 4 | // 5 | // Use, modification and distribution is subject to the Boost Software License, 6 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 7 | // http://www.boost.org/LICENSE_1_0.txt) 8 | // 9 | // Credits: 10 | // My (Neil's) first indexed adaptor was hindered by having the underlying 11 | // iterator return the same reference as the wrapped iterator. This meant that 12 | // to obtain the index one had to get to the index_iterator and call the 13 | // index() function on it. Ilya politely pointed out that this was useless in 14 | // a number of scenarios since one naturally hides the use of iterators in 15 | // good range-based code. Ilya provided a new interface (which has remained) 16 | // and a first implementation. Much of this original implementation has 17 | // been simplified and now supports more compilers and platforms. 18 | // 19 | #ifndef BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED 20 | #define BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED 21 | #define BOOST_RANGE_ADAPTOR_INDEXED_IMPL_HPP 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | namespace boost 39 | { 40 | namespace adaptors 41 | { 42 | 43 | struct indexed 44 | { 45 | explicit indexed(std::ptrdiff_t x = 0) 46 | : val(x) 47 | { 48 | } 49 | std::ptrdiff_t val; 50 | }; 51 | 52 | } // namespace adaptors 53 | 54 | namespace range 55 | { 56 | 57 | // Why yet another "pair" class: 58 | // - std::pair can't store references 59 | // - no need for typing for index type (default to "std::ptrdiff_t"); this is 60 | // useful in BOOST_FOREACH() expressions that have pitfalls with commas 61 | // ( see http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/pitfalls.html ) 62 | // - meaningful access functions index(), value() 63 | template 64 | class index_value 65 | : public tuple 66 | { 67 | typedef tuple base_t; 68 | 69 | template 70 | struct iv_types 71 | { 72 | typedef typename tuples::element::type n_type; 73 | 74 | typedef typename tuples::access_traits::non_const_type non_const_type; 75 | typedef typename tuples::access_traits::const_type const_type; 76 | }; 77 | 78 | public: 79 | typedef typename iv_types<0>::non_const_type index_type; 80 | typedef typename iv_types<0>::const_type const_index_type; 81 | typedef typename iv_types<1>::non_const_type value_type; 82 | typedef typename iv_types<1>::const_type const_value_type; 83 | 84 | index_value() 85 | { 86 | } 87 | 88 | index_value(typename tuples::access_traits::parameter_type t0, 89 | typename tuples::access_traits::parameter_type t1) 90 | : base_t(t0, t1) 91 | { 92 | } 93 | 94 | // member functions index(), value() (non-const and const) 95 | index_type index() 96 | { 97 | return boost::tuples::get<0>(*this); 98 | } 99 | 100 | const_index_type index() const 101 | { 102 | return boost::tuples::get<0>(*this); 103 | } 104 | 105 | value_type value() 106 | { 107 | return boost::tuples::get<1>(*this); 108 | } 109 | 110 | const_value_type value() const 111 | { 112 | return boost::tuples::get<1>(*this); 113 | } 114 | }; 115 | 116 | } // namespace range 117 | 118 | namespace range_detail 119 | { 120 | 121 | template 122 | struct indexed_iterator_value_type 123 | { 124 | typedef ::boost::range::index_value< 125 | typename iterator_reference::type, 126 | typename iterator_difference::type 127 | > type; 128 | }; 129 | 130 | // Meta-function to get the traversal for the range and therefore iterator 131 | // returned by the indexed adaptor for a specified iterator type. 132 | // 133 | // Random access -> Random access 134 | // Bidirectional -> Forward 135 | // Forward -> Forward 136 | // SinglePass -> SinglePass 137 | // 138 | // The rationale for demoting a Bidirectional input to Forward is that the end 139 | // iterator cannot cheaply have an index computed for it. Therefore I chose to 140 | // demote to forward traversal. I can maintain the ability to traverse randomly 141 | // when the input is Random Access since the index for the end iterator is cheap 142 | // to compute. 143 | template 144 | struct indexed_traversal 145 | { 146 | private: 147 | typedef typename iterator_traversal::type wrapped_traversal; 148 | 149 | public: 150 | 151 | typedef typename mpl::if_< 152 | is_convertible, 153 | random_access_traversal_tag, 154 | typename mpl::if_< 155 | is_convertible, 156 | forward_traversal_tag, 157 | wrapped_traversal 158 | >::type 159 | >::type type; 160 | }; 161 | 162 | template 163 | class indexed_iterator 164 | : public iterator_facade< 165 | indexed_iterator, 166 | typename indexed_iterator_value_type::type, 167 | typename indexed_traversal::type, 168 | typename indexed_iterator_value_type::type, 169 | typename iterator_difference::type 170 | > 171 | { 172 | public: 173 | typedef Iter wrapped; 174 | 175 | private: 176 | typedef iterator_facade< 177 | indexed_iterator, 178 | typename indexed_iterator_value_type::type, 179 | typename indexed_traversal::type, 180 | typename indexed_iterator_value_type::type, 181 | typename iterator_difference::type 182 | > base_t; 183 | 184 | public: 185 | typedef typename base_t::difference_type difference_type; 186 | typedef typename base_t::reference reference; 187 | typedef typename base_t::difference_type index_type; 188 | 189 | indexed_iterator() 190 | : m_it() 191 | , m_index() 192 | { 193 | } 194 | 195 | template 196 | indexed_iterator( 197 | const indexed_iterator& other, 198 | typename enable_if >::type* = 0 199 | ) 200 | : m_it(other.get()) 201 | , m_index(other.get_index()) 202 | { 203 | } 204 | 205 | explicit indexed_iterator(wrapped it, index_type index) 206 | : m_it(it) 207 | , m_index(index) 208 | { 209 | } 210 | 211 | wrapped get() const 212 | { 213 | return m_it; 214 | } 215 | 216 | index_type get_index() const 217 | { 218 | return m_index; 219 | } 220 | 221 | private: 222 | friend class boost::iterator_core_access; 223 | 224 | reference dereference() const 225 | { 226 | return reference(m_index, *m_it); 227 | } 228 | 229 | bool equal(const indexed_iterator& other) const 230 | { 231 | return m_it == other.m_it; 232 | } 233 | 234 | void increment() 235 | { 236 | ++m_index; 237 | ++m_it; 238 | } 239 | 240 | void decrement() 241 | { 242 | BOOST_ASSERT_MSG(m_index > 0, "indexed Iterator out of bounds"); 243 | --m_index; 244 | --m_it; 245 | } 246 | 247 | void advance(index_type n) 248 | { 249 | m_index += n; 250 | BOOST_ASSERT_MSG(m_index >= 0, "indexed Iterator out of bounds"); 251 | m_it += n; 252 | } 253 | 254 | difference_type distance_to(const indexed_iterator& other) const 255 | { 256 | return other.m_it - m_it; 257 | } 258 | 259 | wrapped m_it; 260 | index_type m_index; 261 | }; 262 | 263 | template 264 | struct indexed_range 265 | : iterator_range< 266 | indexed_iterator< 267 | typename range_iterator::type 268 | > 269 | > 270 | { 271 | typedef iterator_range< 272 | indexed_iterator< 273 | typename range_iterator::type 274 | > 275 | > base_t; 276 | 277 | BOOST_RANGE_CONCEPT_ASSERT(( 278 | boost::SinglePassRangeConcept)); 279 | public: 280 | typedef indexed_iterator< 281 | typename range_iterator::type 282 | > iterator; 283 | 284 | // Constructor for non-random access iterators. 285 | // This sets the end iterator index to i despite this being incorrect it 286 | // is never observable since bidirectional iterators are demoted to 287 | // forward iterators. 288 | indexed_range( 289 | typename base_t::difference_type i, 290 | SinglePassRange& r, 291 | single_pass_traversal_tag 292 | ) 293 | : base_t(iterator(boost::begin(r), i), 294 | iterator(boost::end(r), i)) 295 | { 296 | } 297 | 298 | indexed_range( 299 | typename base_t::difference_type i, 300 | SinglePassRange& r, 301 | random_access_traversal_tag 302 | ) 303 | : base_t(iterator(boost::begin(r), i), 304 | iterator(boost::end(r), i + boost::size(r))) 305 | { 306 | } 307 | }; 308 | 309 | } // namespace range_detail 310 | 311 | using range_detail::indexed_range; 312 | 313 | namespace adaptors 314 | { 315 | 316 | template 317 | inline indexed_range 318 | operator|(SinglePassRange& r, indexed e) 319 | { 320 | BOOST_RANGE_CONCEPT_ASSERT(( 321 | boost::SinglePassRangeConcept 322 | )); 323 | return indexed_range( 324 | e.val, r, 325 | typename range_traversal::type()); 326 | } 327 | 328 | template 329 | inline indexed_range 330 | operator|(const SinglePassRange& r, indexed e) 331 | { 332 | BOOST_RANGE_CONCEPT_ASSERT(( 333 | boost::SinglePassRangeConcept 334 | )); 335 | return indexed_range( 336 | e.val, r, 337 | typename range_traversal::type()); 338 | } 339 | 340 | template 341 | inline indexed_range 342 | index( 343 | SinglePassRange& rng, 344 | typename range_difference::type index_value = 0) 345 | { 346 | BOOST_RANGE_CONCEPT_ASSERT(( 347 | boost::SinglePassRangeConcept 348 | )); 349 | return indexed_range( 350 | index_value, rng, 351 | typename range_traversal::type()); 352 | } 353 | 354 | template 355 | inline indexed_range 356 | index( 357 | const SinglePassRange& rng, 358 | typename range_difference::type index_value = 0) 359 | { 360 | BOOST_RANGE_CONCEPT_ASSERT(( 361 | boost::SinglePassRangeConcept 362 | )); 363 | return indexed_range( 364 | index_value, rng, 365 | typename range_traversal::type()); 366 | } 367 | 368 | } // namespace adaptors 369 | } // namespace boost 370 | 371 | #endif // include guard 372 | -------------------------------------------------------------------------------- /exampletable.txt: -------------------------------------------------------------------------------- 1 | boost::accumulate ;Algorithm::Numeric ;boost/range/numeric.hpp ;algorithms/numeric/accumulate.html ;src/accumulate.cpp 2 | boost::adaptors::adjacent_filter ;Adaptors ;boost/range/adaptor/adjacent_filtered.hpp ;adaptors/reference/adjacent_filtered.html ;preprocessed/adjacent_filter-function.cpp 3 | boost::adaptors::adjacent_filtered ;Adaptors ;boost/range/adaptor/adjacent_filtered.hpp ;adaptors/reference/adjacent_filtered.html ;preprocessed/adjacent_filter-pipe.cpp 4 | boost::adaptors::copied ;Adaptors ;boost/range/adaptor/copied.hpp ;adaptors/reference/copied.html ;preprocessed/copied-pipe.cpp 5 | boost::adaptors::copy ;Adaptors ;boost/range/adaptor/copied.hpp ;adaptors/reference/copied.html ;preprocessed/copied-function.cpp 6 | boost::adaptors::filter ;Adaptors ;boost/range/adaptor/filtered.hpp ;adaptors/reference/filtered.html ;preprocessed/filter-function.cpp 7 | boost::adaptors::filtered ;Adaptors ;boost/range/adaptor/filtered.hpp ;adaptors/reference/filtered.html ;preprocessed/filter-pipe.cpp 8 | boost::adaptors::index ;Adaptors ;boost/range/adaptor/indexed.hpp ;adaptors/reference/indexed.html ;preprocessed/indexed-function.cpp 9 | boost::adaptors::indexed ;Adaptors ;boost/range/adaptor/indexed.hpp ;adaptors/reference/indexed.html ;preprocessed/indexed-pipe.cpp 10 | boost::adaptors::indirect ;Adaptors ;boost/range/adaptor/indirected.hpp ;adaptors/reference/indirected.html ;preprocessed/indirected-function.cpp 11 | boost::adaptors::indirected ;Adaptors ;boost/range/adaptor/indirected.hpp ;adaptors/reference/indirected.html ;preprocessed/indirected-pipe.cpp 12 | boost::adaptors::keys ;Adaptors ;boost/range/adaptor/map.hpp ;adaptors/reference/map_keys.html ;preprocessed/map_adaptors-function.cpp 13 | boost::adaptors::map_keys ;Adaptors ;boost/range/adaptor/map.hpp ;adaptors/reference/map_keys.html ;preprocessed/map_adaptors-pipe.cpp 14 | boost::adaptors::map_values ;Adaptors ;boost/range/adaptor/map.hpp ;adaptors/reference/map_values.html ;preprocessed/map_adaptors-pipe.cpp 15 | boost::adaptors::replace ;Adaptors ;boost/range/adaptor/replaced.hpp ;adaptors/reference/replaced.html ;preprocessed/replaced-function.cpp 16 | boost::adaptors::replace_if ;Adaptors ;boost/range/adaptor/replaced_if.hpp ;adaptors/reference/replaced_if.html ;preprocessed/replaced-function.cpp 17 | boost::adaptors::replaced ;Adaptors ;boost/range/adaptor/replaced.hpp ;adaptors/reference/replaced.html ;preprocessed/replaced-pipe.cpp src/istream_range.cpp 18 | boost::adaptors::replaced_if ;Adaptors ;boost/range/adaptor/replaced_if.hpp ;adaptors/reference/replaced_if.html ;preprocessed/replaced-pipe.cpp 19 | boost::adaptors::reverse ;Adaptors ;boost/range/adaptor/reversed.hpp ;adaptors/reference/reversed.html ;preprocessed/reversed-function.cpp 20 | boost::adaptors::reversed ;Adaptors ;boost/range/adaptor/reversed.hpp ;adaptors/reference/reversed.html ;preprocessed/reversed-pipe.cpp 21 | boost::adaptors::slice ;Adaptors ;boost/range/adaptor/sliced.hpp ;adaptors/reference/sliced.html ;preprocessed/slice_stride-function.cpp 22 | boost::adaptors::sliced ;Adaptors ;boost/range/adaptor/sliced.hpp ;adaptors/reference/sliced.html ;preprocessed/slice_stride-pipe.cpp 23 | boost::adaptors::stride ;Adaptors ;boost/range/adaptor/strided.hpp ;adaptors/reference/strided.html ;preprocessed/slice_stride-function.cpp 24 | boost::adaptors::strided ;Adaptors ;boost/range/adaptor/strided.hpp ;adaptors/reference/strided.html ;preprocessed/slice_stride-pipe.cpp src/istream_range.cpp 25 | boost::adaptors::tokenized ;Adaptors ;boost/range/adaptor/tokenized.hpp ;adaptors/reference/tokenized.html ;src/tokenized.cpp 26 | boost::adaptors::transform ;Adaptors ;boost/range/adaptor/transformed.hpp ;adaptors/reference/transformed.html ;preprocessed/transformed-function.cpp 27 | boost::adaptors::transformed ;Adaptors ;boost/range/adaptor/transformed.hpp ;adaptors/reference/transformed.html ;preprocessed/transformed-pipe.cpp 28 | boost::adaptors::unique ;Adaptors ;boost/range/adaptor/uniqued.hpp ;adaptors/reference/uniqued.html ;preprocessed/uniqued-function.cpp 29 | boost::adaptors::uniqued ;Adaptors ;boost/range/adaptor/uniqued.hpp ;adaptors/reference/uniqued.html ;preprocessed/uniqued-pipe.cpp 30 | boost::adaptors::values ;Adaptors ;boost/range/adaptor/map.hpp ;adaptors/reference/map_values.html ;preprocessed/map_adaptors-function.cpp 31 | boost::adjacent_difference ;Algorithm::Numeric ;boost/range/numeric.hpp ;algorithms/numeric/adjacent_difference.html ;src/adjacent_difference.cpp 32 | boost::any_range ;Ranges ;boost/range/any_range.hpp ;ranges/any_range.html ;src/any_range.cpp 33 | boost::as_array ;General ;boost/range/as_array.hpp ;concept_implementation/semantics/functions.html ;src/string_conversions.cpp 34 | boost::as_literal ;General ;boost/range/as_literal.hpp ;concept_implementation/semantics/functions.html ;src/string_conversions.cpp 35 | boost::begin ;General ;boost/range/begin.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 36 | boost::combine ;Utilities ;boost/range/combine.hpp ;utilities/combine.html ;src/combine.cpp 37 | boost::const_begin ;General ;boost/range/begin.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 38 | boost::const_end ;General ;boost/range/end.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 39 | boost::const_rbegin ;General ;boost/range/rbegin.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 40 | boost::const_rend ;General ;boost/range/rend.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 41 | boost::counting_range ;Ranges ;boost/range/counting_range.hpp ;ranges/counting_range.html ;src/numeric_range.cpp 42 | boost::distance ;General ;boost/range/distance.hpp ;concept_implementation/semantics/functions.html ;src/size.cpp 43 | boost::empty ;General ;boost/range/empty.hpp ;concept_implementation/semantics/functions.html ;src/size.cpp 44 | boost::end ;General ;boost/range/end.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 45 | boost::inner_product ;Algorithm::Numeric ;boost/range/numeric.hpp ;algorithms/numeric/inner_product.html ;src/inner_product.cpp 46 | boost::irange ;Ranges ;boost/range/irange.hpp ;ranges/irange.html ;src/numeric_range.cpp 47 | boost::istream_range ;Ranges ;boost/range/istream_range.hpp ;ranges/istream_range.html ;src/istream_range.cpp 48 | boost::iterator_range ;Utilities ;boost/range/iterator_range.hpp ;utilities/iterator_range.html ;src/iterator_range.cpp 49 | boost::join ;Utilities ;boost/range/join.hpp ;utilities/join.html ;src/join.cpp 50 | boost::make_iterator_range ;Utilities ;boost/range/iterator_range.hpp ;utilities/iterator_range.html ;src/iterator_range.cpp 51 | boost::partial_sum ;Algorithm::Numeric ;boost/range/numeric.hpp ;algorithms/numeric/partial_sum.html ;src/partial_sum.cpp 52 | boost::range::adjacent_find ;Algorithm::Non-mutating ;boost/range/algorithm/adjacent_find.hpp ;algorithms/non_mutating/adjacent_find.html ;src/adjacent_find.cpp 53 | boost::range::binary_search ;Algorithm::Non-mutating ;boost/range/algorithm/binary_search.hpp ;algorithms/non_mutating/binary_search.html ;src/binary_search.cpp 54 | boost::range::copy ;Algorithm::Mutating ;boost/range/algorithm/copy.hpp ;algorithms/mutating/copy.html ;src/copy.cpp 55 | boost::range::copy_backward ;Algorithm::Mutating ;boost/range/algorithm/copy_backward.hpp ;algorithms/mutating/copy_backward.html ;src/copy.cpp 56 | boost::range::copy_n ;Algorithm::New ;boost/range/algorithm_ext/copy_n.hpp ;algorithms/new/copy_n.html ;src/copy_n.cpp 57 | boost::range::count ;Algorithm::Non-mutating ;boost/range/algorithm/count.hpp ;algorithms/non_mutating/count.html ;src/count.cpp 58 | boost::range::count_if ;Algorithm::Non-mutating ;boost/range/algorithm/count_if.hpp ;algorithms/non_mutating/count_if.html ;src/count.cpp 59 | boost::range::equal ;Algorithm::Non-mutating ;boost/range/algorithm/equal.hpp ;algorithms/non_mutating/equal.html ;src/equal.cpp 60 | boost::range::equal_range ;Algorithm::Non-mutating ;boost/range/algorithm/equal_range.hpp ;algorithms/non_mutating/equal_range.html ;src/equal_range.cpp 61 | boost::range::erase ;Algorithm::New ;boost/range/algorithm_ext/erase.hpp ;algorithms/new/erase.html ;src/erase.cpp 62 | boost::range::fill ;Algorithm::Mutating ;boost/range/algorithm/fill.hpp ;algorithms/mutating/fill.html ;src/fill.cpp 63 | boost::range::fill_n ;Algorithm::Mutating ;boost/range/algorithm/fill_n.hpp ;algorithms/mutating/fill_n.html ;src/fill.cpp 64 | boost::range::find ;Algorithm::Non-mutating ;boost/range/algorithm/find.hpp ;algorithms/non_mutating/find.html ;src/find.cpp 65 | boost::range::find_end ;Algorithm::Non-mutating ;boost/range/algorithm/find_end.hpp ;algorithms/non_mutating/find_end.html ;src/search.cpp 66 | boost::range::find_first_of ;Algorithm::Non-mutating ;boost/range/algorithm/find_first_of.hpp ;algorithms/non_mutating/find_first_of.html ;src/find.cpp 67 | boost::range::find_if ;Algorithm::Non-mutating ;boost/range/algorithm/find_if.hpp ;algorithms/non_mutating/find_if.html ;src/find.cpp 68 | boost::range::for_each ;Algorithm::New ;boost/range/algorithm_ext/for_each.hpp ;algorithms/new/for_each.html ;src/for_each.cpp 69 | boost::range::generate ;Algorithm::Mutating ;boost/range/algorithm/generate.hpp ;algorithms/mutating/generate.html ;src/generate.cpp 70 | boost::range::includes ;Algorithm::Set ;boost/range/algorithm/set_algorithm.hpp ;algorithms/set/includes.html ;src/includes.cpp 71 | boost::range::inplace_merge ;Algorithm::Mutating ;boost/range/algorithm/inplace_merge.hpp ;algorithms/mutating/inplace_merge.html ;src/inplace_merge.cpp 72 | boost::range::insert ;Algorithm::New ;boost/range/algorithm_ext/insert.hpp ;algorithms/new/insert.html ;src/insert.cpp 73 | boost::range::iota ;Algorithm::New ;boost/range/algorithm_ext/iota.hpp ;algorithms/new/iota.html ;src/iota.cpp 74 | boost::range::is_sorted ;Algorithm::New ;boost/range/algorithm_ext/is_sorted.hpp ;algorithms/new/is_sorted.html ;src/is_sorted.cpp 75 | boost::range::lexicographical_compare ;Algorithm::Non-mutating ;boost/range/algorithm/lexicographical_compare.hpp ;algorithms/non_mutating/lexicographical_compare.html ;src/lexicographical_compare.cpp 76 | boost::range::lower_bound ;Algorithm::Non-mutating ;boost/range/algorithm/lower_bound.hpp ;algorithms/non_mutating/lower_bound.html ;src/lower_bound.cpp 77 | boost::range::make_heap ;Algorithm::Heap ;boost/range/algorithm/heap_algorithm.hpp ;algorithms/heap/make_heap.html ;src/heap.cpp src/heap_with_predicate.cpp 78 | boost::range::max_element ;Algorithm::Non-mutating ;boost/range/algorithm/max_element.hpp ;algorithms/non_mutating/max_element.html ;src/min_max_element.cpp 79 | boost::range::merge ;Algorithm::Mutating ;boost/range/algorithm/merge.hpp ;algorithms/mutating/merge.html ;src/merge.cpp 80 | boost::range::min_element ;Algorithm::Non-mutating ;boost/range/algorithm/min_element.hpp ;algorithms/non_mutating/min_element.html ;src/min_max_element.cpp 81 | boost::range::mismatch ;Algorithm::Non-mutating ;boost/range/algorithm/mismatch.hpp ;algorithms/non_mutating/mismatch.html ;src/mismatch.cpp 82 | boost::range::next_permutation ;Algorithm::Permutation ;boost/range/algorithm/permutation.hpp ;algorithms/permutation/next_permutation.html ;src/next_permutation.cpp 83 | boost::range::nth_element ;Algorithm::Mutating ;boost/range/algorithm/nth_element.hpp ;algorithms/mutating/nth_element.html ;src/nth_element.cpp 84 | boost::range::overwrite ;Algorithm::New ;boost/range/algorithm_ext/overwrite.hpp ;algorithms/new/overwrite.html ;src/overwrite.cpp 85 | boost::range::partial_sort ;Algorithm::Mutating ;boost/range/algorithm/partial_sort.hpp ;algorithms/mutating/partial_sort.html ;src/partial_sort.cpp 86 | boost::range::partition ;Algorithm::Mutating ;boost/range/algorithm/partition.hpp ;algorithms/mutating/partition.html ;src/partition.cpp 87 | boost::range::pop_heap ;Algorithm::Heap ;boost/range/algorithm/heap_algorithm.hpp ;algorithms/heap/pop_heap.html ;src/heap.cpp src/heap_with_predicate.cpp 88 | boost::range::prev_permutation ;Algorithm::Permutation ;boost/range/algorithm/permutation.hpp ;algorithms/permutation/prev_permutation.html ;src/prev_permutation.cpp 89 | boost::range::push_back ;Algorithm::New ;boost/range/algorithm_ext/push_back.hpp ;algorithms/new/push_back.html ;src/push_back.cpp 90 | boost::range::push_front ;Algorithm::New ;boost/range/algorithm_ext/push_front.hpp ;algorithms/new/push_front.html ;src/push_front.cpp 91 | boost::range::push_heap ;Algorithm::Heap ;boost/range/algorithm/heap_algorithm.hpp ;algorithms/heap/push_heap.html ;src/heap.cpp src/heap_with_predicate.cpp 92 | boost::range::random_shuffle ;Algorithm::Mutating ;boost/range/algorithm/random_shuffle.hpp ;algorithms/mutating/random_shuffle.html ;src/random_shuffle.cpp 93 | boost::range::remove ;Algorithm::Mutating ;boost/range/algorithm/remove.hpp ;algorithms/mutating/remove.html ;src/remove.cpp 94 | boost::range::remove_erase ;Algorithm::New ;boost/range/algorithm_ext/erase.hpp ;algorithms/new/remove_erase.html ;src/remove_erase.cpp 95 | boost::range::remove_erase_if ;Algorithm::New ;boost/range/algorithm_ext/erase.hpp ;algorithms/new/remove_erase_if.html ;src/remove_erase_if.cpp 96 | boost::range::remove_if ;Algorithm::Mutating ;boost/range/algorithm/remove_if.hpp ;algorithms/mutating/remove_if.html ;src/remove_if.cpp 97 | boost::range::replace ;Algorithm::Mutating ;boost/range/algorithm/replace.hpp ;algorithms/mutating/replace.html ;src/replace.cpp 98 | boost::range::replace_if ;Algorithm::Mutating ;boost/range/algorithm/replace_if.hpp ;algorithms/mutating/replace_if.html ;src/replace_if.cpp 99 | boost::range::reverse ;Algorithm::Mutating ;boost/range/algorithm/reverse.hpp ;algorithms/mutating/reverse.html ;src/reverse.cpp 100 | boost::range::rotate ;Algorithm::Mutating ;boost/range/algorithm/rotate.hpp ;algorithms/mutating/rotate.html ;src/rotate.cpp 101 | boost::range::search ;Algorithm::Non-mutating ;boost/range/algorithm/search.hpp ;algorithms/non_mutating/search.html ;src/search.cpp 102 | boost::range::search_n ;Algorithm::Non-mutating ;boost/range/algorithm/search_n.hpp ;algorithms/non_mutating/search_n.html ;src/search_n.cpp 103 | boost::range::set_difference ;Algorithm::Set ;boost/range/algorithm/set_algorithm.hpp ;algorithms/set/set_difference.html ;src/set_difference.cpp 104 | boost::range::set_intersection ;Algorithm::Set ;boost/range/algorithm/set_algorithm.hpp ;algorithms/set/set_intersection.html ;src/set_intersection.cpp 105 | boost::range::set_symmetric_difference ;Algorithm::Set ;boost/range/algorithm/set_algorithm.hpp ;algorithms/set/set_symmetric_difference.html ;src/set_symmetric_difference.cpp 106 | boost::range::set_union ;Algorithm::Set ;boost/range/algorithm/set_algorithm.hpp ;algorithms/set/set_union.html ;src/set_union.cpp 107 | boost::range::sort ;Algorithm::Mutating ;boost/range/algorithm/sort.hpp ;algorithms/mutating/sort.html ;src/sort.cpp 108 | boost::range::sort_heap ;Algorithm::Heap ;boost/range/algorithm/heap_algorithm.hpp ;algorithms/heap/sort_heap.html ;src/heap.cpp src/heap_with_predicate.cpp 109 | boost::range::stable_partition ;Algorithm::Mutating ;boost/range/algorithm/stable_partition.hpp ;algorithms/mutating/stable_partition.html ;src/stable_partition.cpp 110 | boost::range::stable_sort ;Algorithm::Mutating ;boost/range/algorithm/stable_sort.hpp ;algorithms/mutating/stable_sort.html ;src/stable_sort.cpp 111 | boost::range::swap_ranges ;Algorithm::Mutating ;boost/range/algorithm/swap_ranges.hpp ;algorithms/mutating/swap_ranges.html ;src/swap_ranges.cpp 112 | boost::range::transform ;Algorithm::Mutating ;boost/range/algorithm/transform.hpp ;algorithms/mutating/transform.html ;src/transform.cpp 113 | boost::range::unique ;Algorithm::Mutating ;boost/range/algorithm/unique.hpp ;algorithms/mutating/unique.html ;src/unique.cpp 114 | boost::range::upper_bound ;Algorithm::Non-mutating ;boost/range/algorithm/upper_bound.hpp ;algorithms/non_mutating/upper_bound.html ;src/upper_bound.cpp 115 | boost::rbegin ;General ;boost/range/rbegin.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 116 | boost::remove_copy ;Algorithm::Mutating ;boost/range/algorithm/remove_copy.hpp ;algorithms/mutating/remove_copy.html ;src/remove_copy.cpp 117 | boost::remove_copy_if ;Algorithm::Mutating ;boost/range/algorithm/remove_copy_if.hpp ;algorithms/mutating/remove_copy_if.html ;src/remove_copy_if.cpp 118 | boost::rend ;General ;boost/range/rend.hpp ;concept_implementation/semantics/functions.html ;src/general.cpp 119 | boost::replace_copy ;Algorithm::Mutating ;boost/range/algorithm/replace_copy.hpp ;algorithms/mutating/replace_copy.html ;src/replace_copy.cpp 120 | boost::replace_copy_if ;Algorithm::Mutating ;boost/range/algorithm/replace_copy_if.hpp ;algorithms/mutating/replace_copy_if.html ;src/replace_copy_if.cpp 121 | boost::reverse_copy ;Algorithm::Mutating ;boost/range/algorithm/reverse_copy.hpp ;algorithms/mutating/reverse_copy.html ;src/reverse_copy.cpp 122 | boost::rotate_copy ;Algorithm::Mutating ;boost/range/algorithm/rotate_copy.hpp ;algorithms/mutating/rotate_copy.html ;src/rotate_copy.cpp 123 | boost::size ;General ;boost/range/size.hpp ;concept_implementation/semantics/functions.html ;src/size.cpp src/string_conversions.cpp 124 | boost::sub_range ;Utilities ;boost/range/sub_range.hpp ;utilities/sub_range.html ;src/sub_range.cpp 125 | boost::unique_copy ;Algorithm::Mutating ;boost/range/algorithm/unique_copy.hpp ;algorithms/mutating/unique_copy.html ;src/unique_copy.cpp 126 | --------------------------------------------------------------------------------