OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / opencog / atoms / grant / StateLink.cc

137 lines · cc ref:
/*
 * StateLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * Author: Linas Vepstas <linasvepstas@gmail.com>  May 2015
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atomspace/AtomSpace.h>
#include "StateLink.h"

using namespace opencog;

void StateLink::init()
{
	// Must have name and body
	if (2 != _outgoing.size())
		throw InvalidParamException(TRACE_INFO,
			"Expecting name and state, got size %d", _outgoing.size());

	UniqueLink::init();
}

StateLink::StateLink(const HandleSeq&& oset, Type t)
	: UniqueLink(std::move(oset), t)
{
	init();
}

StateLink::StateLink(const Handle& name, const Handle& defn)
	: UniqueLink({name, defn}, STATE_LINK)
{
	init();
}

/**
 * Get the state associated with the alias.
 * This will be the second atom of some StateLink, where
 * `alias` is the first.
 */
Handle StateLink::get_state(const Handle& alias, const AtomSpace* as)
{
	Handle uniq(get_unique(alias, STATE_LINK, true, as));
	return uniq->getOutgoingAtom(1);
}

/**
 * Get the link associated with the alias.  This will be the StateLink
 * which has `alias` as the first member of the outgoing set.
 */
Handle StateLink::get_link(const Handle& alias, const AtomSpace* as)
{
	return get_unique(alias, STATE_LINK, true, as);
}

/// Return this if not found.
Handle StateLink::get_link(const AtomSpace* as)
{
	Handle shallowest(get_unique_nt(_outgoing[0], STATE_LINK, true, as));
	if (shallowest) return shallowest;
	return get_handle();
}

// Over-ride what UniqueLink is doing, set it back to default.
// We handle uniqueness slightly later, at the install() step.
void StateLink::setAtomSpace(AtomSpace* as)
{
	Link::setAtomSpace(as);
}

void StateLink::install(void)
{
	// If the handlset is not closed (if it has free variables in it),
	// then allow it in. This allows query patterns for StateLinks.
	if (not is_closed())
	{
		Link::install();
		return;
	}

	// Find all existing copies of this particular StateLink.
	// There should be only one, **in this atomspace**.
	// We do allow child atomspaces (child frames) to over-ride the
	// state in the parent; the net effect is that the state in the
	// child will hide the state in the parent.
	//
	// Perform an atomic swap, replacing the old with the new.
	bool swapped = false;
	const Handle& alias = get_alias();
	IncomingSet defs = alias->getIncomingSetByType(STATE_LINK);
	for (const Handle& defl : defs)
	{
		if (defl.get() == this) continue;
		if (defl->getOutgoingAtom(0) != alias) continue;
		if (defl->getAtomSpace() != getAtomSpace()) continue;

		StateLinkPtr old_state(StateLinkCast(defl));
		if (not old_state->is_closed()) continue;

		// Make sure we are visible in the atomspace, before the swap.
		AtomSpace *as = old_state->getAtomSpace();
		setAtomSpace(as);

		// Atomic update of the incoming set.
		const Handle& new_state(get_handle());
		alias->swap_atom(defl, new_state);

		// Install the other atom as well.
		_outgoing[1]->insert_atom(new_state);

		// Remove the old StateLink too. It must be no more.
		as->extract_atom(defl, true);
		swapped = true;
	}

	if (not swapped) Link::install();
}

DEFINE_LINK_FACTORY(StateLink, STATE_LINK);

/* ===================== END OF FILE ===================== */