OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-sensory / opencog / atoms / sensory / SensoryNode.cc

176 lines · cc ref:
/*
 * opencog/atoms/sensory/SensoryNode.cc
 *
 * Copyright (c) 2008-2010 OpenCog Foundation
 * Copyright (c) 2009,2013,2020,2022,2025 Linas Vepstas
 * All Rights Reserved
 *
 * 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 <string>

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/value/BoolValue.h>
#include <opencog/atoms/value/StringValue.h>
#include <opencog/atoms/value/VoidValue.h>
#include "SensoryNode.h"

using namespace opencog;

// ====================================================================

template class ObjectCRTP<SensoryNode>;

SensoryNode::SensoryNode(Type t, const std::string&& uri) :
	ObjectCRTP<SensoryNode>(t, std::move(uri))
{
	if (not nameserver().isA(t, SENSORY_NODE))
		throw RuntimeException(TRACE_INFO, "Bad inheritance!");
}

SensoryNode::~SensoryNode()
{
}

void SensoryNode::barrier(AtomSpace* as)
{
	if (nullptr == as) as = getAtomSpace();
	as->barrier();
}

void SensoryNode::follow(const ValuePtr& value)
{
	// Default: do nothing. Derived classes can override.
}

// The open, close and write messages are hopefully self-explanatory.
//
// The barrier message is a multi-threading ordering message, so that
// everything before is ordered to happen before everything after.
//
// The follow message is initially for tailing a file, but seems to be
// a sufficiently generic concept that "anything" could be tailed.
// The name "tail" is avoided to avoid head/tail confusion. The word
// "follow" is rare in unix/comp-sci but seems appropriate for the idea.
void SensoryNode::setValue(const Handle& key, const ValuePtr& value)
{
	// The value must be store only if it is not one of the values
	// that causes an action to be taken. Action messages must not be
	// recorded, as otherwise, restore from disk/net will cause the
	// action to be triggered!
	if (PREDICATE_NODE != key->get_type())
	{
		Atom::setValue(key, value);
		return;
	}

	// Create a fast dispatch table using case-statement branching.
	static constexpr uint32_t p_open = dispatch_hash("*-open-*");
	static constexpr uint32_t p_close = dispatch_hash("*-close-*");
	static constexpr uint32_t p_write = dispatch_hash("*-write-*");
	static constexpr uint32_t p_barrier = dispatch_hash("*-barrier-*");
	static constexpr uint32_t p_follow = dispatch_hash("*-follow-*");

// There's almost no chance at all that any user will use some key
// that is a PredicateNode that has a string name that collides with
// one of the above. That's because there's really no reason to set
// static values on a SensoryNode. That I can think of. Still there's
// some chance of a hash collision. In this case, define
// COLLISION_PROOF, and recompile. Sorry in advance for the awful
// debug session you had that caused you to discover this comment!
//
// #define COLLISION_PROOF
#ifdef COLLISION_PROOF
	#define COLL(STR) if (0 != pred.compare(STR)) break;
#else
	#define COLL(STR)
#endif

	const std::string& pred = key->get_name();
	switch (dispatch_hash(pred.c_str()))
	{
		case p_open:
			COLL("*-open-*");
			open(value);
			return;
		case p_close:
			COLL("*-close-*");
			close(value);
			return;
		case p_write:
			COLL("*-write-*");
			write(value);
			return;
		case p_barrier:
			COLL("*-barrier-*");
			barrier(AtomSpaceCast(value).get());
			return;
		case p_follow:
			COLL("*-follow-*");
			follow(value);
			return;
		default:
			break;
	}

	// Some other predicate. Store it.
	Atom::setValue(key, value);
}

ValuePtr SensoryNode::getValue(const Handle& key) const
{
	if (PREDICATE_NODE != key->get_type())
		return Atom::getValue(key);

	// Create a fast dispatch table using case-statement branching.
	static constexpr uint32_t p_connected_p =
		dispatch_hash("*-connected?-*");
	static constexpr uint32_t p_read =
		dispatch_hash("*-read-*");
	static constexpr uint32_t p_stream =
		dispatch_hash("*-stream-*");
	static constexpr uint32_t p_monitor =
		dispatch_hash("*-monitor-*");

	const std::string& pred(key->get_name());
	switch (dispatch_hash(pred.c_str()))
	{
		case p_read:
			COLL("*-read-*");
			return read();
		case p_stream:
			COLL("*-stream-*");
			return stream();
		case p_connected_p:
			COLL("*-connected?-*");
			return createBoolValue(connected());
		case p_monitor:
			COLL("*-monitor-*");
			return createStringValue(monitor());
		default:
			break;
	}
	return Atom::getValue(key);
}

// ====================================================================

void opencog_sensory_init(void)
{
	// Force shared lib ctors to run
};