<commit_before>/// @file
/// @author uentity
/// @date 14.07.2019
/// @brief Implementataion of node actor
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include "node_impl.h"
#include "link_impl.h"
#include "node_actor.h"
#include "nil_engine.h"

#include <bs/log.h>
#include <bs/tree/tree.h>
#include <bs/detail/tuple_utils.h>
#include <bs/serialize/cafbind.h>
#include <bs/serialize/tree.h>
#include "../serialize/tree_impl.h"

NAMESPACE_BEGIN(blue_sky::tree)
using bs_detail::shared;
	
ENGINE_TYPE_DEF(node_impl, "node")

auto node_impl::clone(node_actor*, bool deep) const -> caf::result<sp_nimpl> {
	// [TODO] write async version of this
	// [NOTE] can do this without transactions for each link, because cloned link is not shared
	auto res = std::make_shared<node_impl>();
	auto& res_leafs = res->links_.get<Key_tag<Key::AnyOrder>>();
	for(const auto& leaf : links_.get<Key_tag<Key::AnyOrder>>())
		res_leafs.insert(res_leafs.end(), leaf.clone(deep));
	return res;
}

auto node_impl::handle() const -> link {
	auto guard = lock(shared);
	return handle_.lock();
}

auto node_impl::set_handle(const link& new_handle) -> void {
	auto guard = lock();
	// remove node from existing owner if it differs from owner of new handle
	// [NOTE] don't call `handle()` here, because mutex is already locked
	if(const auto old_handle = handle_.lock()) {
		const auto owner = old_handle.owner();
		if(owner && (!new_handle || owner != new_handle.owner()))
			caf::anon_send(
				node_impl::actor(owner), a_node_erase(), old_handle.id(), EraseOpts::Normal
			);
	}
<commit_msg>tree/node_impl: implement async clone<commit_after>/// @file
/// @author uentity
/// @date 14.07.2019
/// @brief Implementataion of node actor
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include "node_impl.h"
#include "link_impl.h"
#include "node_actor.h"
#include "nil_engine.h"

#include <bs/log.h>
#include <bs/tree/tree.h>
#include <bs/detail/tuple_utils.h>
#include <bs/serialize/cafbind.h>
#include <bs/serialize/tree.h>
#include "../serialize/tree_impl.h"

#include <algorithm>

NAMESPACE_BEGIN(blue_sky::tree)
using bs_detail::shared;
	
ENGINE_TYPE_DEF(node_impl, "node")

auto node_impl::clone(node_actor* papa, bool deep) const -> caf::result<sp_nimpl> {
	auto res_promise = papa->make_response_promise<sp_nimpl>();
	auto do_clone = [=](auto&& self, auto work, auto res) mutable {
		if(work.empty()) {
			res_promise.deliver(std::move(res));
			return;
		}

		auto leaf = work.back();
		work.pop_back();
		// [NOTE] use `await` to ensure node is not modified while cloning leafs
		papa->request(leaf.actor(), kernel::radio::timeout(true), a_clone{}, deep)
		.await(
			[=, work = std::move(work)](const link& leaf_clone) mutable {
				auto& res_leafs = res->links_.template get<Key_tag<Key::AnyOrder>>();
				res_leafs.insert(res_leafs.end(), leaf_clone);
				self(self, std::move(work), std::move(res));
			},
			// stop process on error & return existing result
			[=](const caf::error& er) mutable {
				forward_caf_error(er, "in node_impl::clone()").dump();
				res_promise.deliver(std::move(res));
			}
		);
	};

	auto work = leafs(Key::AnyOrder);
	std::reverse(work.begin(), work.end());
	do_clone(do_clone, std::move(work), std::make_shared<node_impl>());
	return res_promise;
}

auto node_impl::handle() const -> link {
	auto guard = lock(shared);
	return handle_.lock();
}

auto node_impl::set_handle(const link& new_handle) -> void {
	auto guard = lock();
	// remove node from existing owner if it differs from owner of new handle
	// [NOTE] don't call `handle()` here, because mutex is already locked
	if(const auto old_handle = handle_.lock()) {
		const auto owner = old_handle.owner();
		if(owner && (!new_handle || owner != new_handle.owner()))
			caf::anon_send(
				node_impl::actor(owner), a_node_erase(), old_handle.id(), EraseOpts::Normal
			);
	}

{'fraction_non_alphanumeric': 0.1613056945437217, 'fraction_numerical': 0.005718370264474625, 'mean_word_length': 4.459037711313394, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 35, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4797208', 'n_tokens_mistral': 1541, 'n_tokens_neox': 1451, 'n_words': 384}