// Copyright 2015, Tobias Hermann and the FunctionalPlus contributors. // https://github.com/Dobiasd/FunctionalPlus // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #pragma once #include #include namespace fplus { template struct tree { tree (const T& value, const std::vector>& children) : value_(value), children_(children) {} T value_; std::vector> children_; }; namespace internal { template tree make_singleton_tree(const T& x) { return {x, {}}; } } // namespace internal namespace internal { template std::vector> presort_trees(BinaryPredicate tree_is_child_of, std::vector> xs_orig) { auto xs = fplus::convert_container>>(xs_orig); std::vector> result; while (!xs.empty()) { for (auto it = std::begin(xs); it != std::end(xs);) { bool has_children = false; for (auto it_rest = std::begin(xs); it_rest != std::end(xs); ++it_rest) { if (it_rest != it && tree_is_child_of(*it_rest, *it)) { has_children = true; } } if (!has_children) { result.push_back(*it); it = xs.erase(it); } else { ++it; } } } return result; } template // todo: name? TreeCont trees_from_sequence_helper( BinaryPredicate tree_is_child_of, TreeCont xs_unsorted) { TreeCont result; auto xs = presort_trees(tree_is_child_of, xs_unsorted); for (auto it = std::begin(xs); it != std::end(xs); ++it) { const auto find_pred = bind_1st_of_2(tree_is_child_of, *it); auto it_find_begin = it; internal::advance_iterator(it_find_begin, 1); auto parent_it = std::find_if(it_find_begin, std::end(xs), find_pred); if (parent_it != std::end(xs)) { parent_it->children_.push_back(*it); } else { result.push_back(*it); } } return result; } } // namespace internal // API search type: trees_from_sequence : (((a, a) -> Bool), [a]) -> [Tree a] // fwd bind count: 1 // Converts the sequence into a tree considering the given binary predicate. template // todo: name? std::vector> trees_from_sequence( BinaryPredicate is_child_of, const Container& xs) { internal::check_binary_predicate_for_container(); typedef typename Container::value_type T; typedef tree Tree; const auto singletons = transform_convert>( internal::make_singleton_tree, xs); const auto tree_is_child_of = [is_child_of](const tree& a, const tree& b) -> bool { return is_child_of(a.value_, b.value_); }; return internal::trees_from_sequence_helper( tree_is_child_of, std::move(singletons)); } namespace internal { // -1 = a < b // 0 = a == b // 1 = b < a template int tree_cmp(const tree& a, const tree& b) { if(a.value_ < b.value_) { return -1; } else if(b.value_ < a.value_) { return 1; } else { const auto results = zip_with(tree_cmp, sort_by(tree_cmp, a.children_), sort_by(tree_cmp, b.children_)); return just_with_default(0, find_first_by( bind_1st_of_2(is_not_equal, 0), results)); } } template bool tree_less(const tree& a, const tree& b) { return tree_cmp(a, b) < 0; } } // namespace internal namespace internal { template bool are_normalized_trees_equal(const tree& a, const tree& b) { if (a.value_ != b.value_ || a.children_.size() != b.children_.size()) { return false; } else { return all(zip_with(are_normalized_trees_equal, a.children_, b.children_)); } } template tree normalize_tree(tree x) { x.children_ = sort_by( internal::tree_less, transform(normalize_tree, x.children_)); return x; } } // namespace internal // API search type: are_trees_equal : (Tree a, Tree a) -> Bool // fwd bind count: 1 template bool are_trees_equal(const tree& a, const tree& b) { return internal::are_normalized_trees_equal( internal::normalize_tree(a), internal::normalize_tree(b)); } // API search type: tree_size : Tree a -> Int // fwd bind count: 0 // A tree with only one element (root) has size 1. template std::size_t tree_size(const tree& x) { return 1 + sum(transform(tree_size, x.children_)); } // API search type: tree_depth : Tree a -> Int // fwd bind count: 0 // A tree with only one element (root) has depth 1. template std::size_t tree_depth(const tree& x) { return 1 + just_with_default(0, maximum_maybe(transform(tree_depth, x.children_))); } // API search type: flatten_tree_depth_first : Tree a -> [a] // fwd bind count: 0 template std::vector flatten_tree_depth_first(const tree& x) { return prepend_elem(x.value_, transform_and_concat(flatten_tree_depth_first, x.children_)); } // API search type: flatten_tree_breadth_first : Tree a -> [a] // fwd bind count: 0 template std::vector flatten_tree_breadth_first(const tree& x) { std::vector result; result.reserve(tree_size(x)); std::queue*> q; q.push(&x); while (!q.empty()) { const auto current = q.front(); q.pop(); result.push_back(current->value_); for (const auto& c : current->children_) { q.push(&c); } } return result; } } // namespace fplus