/*
* IncrementValueLink.cc
*
* Copyright (C) 2015, 2018, 2020 Linas Vepstas
*
* Author: Linas Vepstas <linasvepstas@gmail.com> January 2009
*
* 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 <opencog/atoms/core/NumberNode.h>
#include <opencog/atoms/value/FloatValue.h>
#include "IncrementValueLink.h"
using namespace opencog;
IncrementValueLink::IncrementValueLink(const HandleSeq&& oset, Type t)
: FunctionLink(std::move(oset), t)
{
if (not nameserver().isA(t, INCREMENT_VALUE_LINK))
{
const std::string& tname = nameserver().getTypeName(t);
throw InvalidParamException(TRACE_INFO,
"Expecting an IncrementValueLink, got %s", tname.c_str());
}
size_t ary = _outgoing.size();
if (is_type(INCREMENT_VALUE_LINK) and 3 != ary)
throw SyntaxException(TRACE_INFO, "Expecting three atoms!");
}
// ---------------------------------------------------------------
// IncrementValue must work in the local AtomSpace. This includes
// the evaluation of keys, as needed.
Handle IncrementValueLink::localize(AtomSpace* as, bool silent, const Handle& h) const
{
if (not h->is_executable())
return as->add_atom(h);
ValuePtr pap(h->execute(as, silent));
if (pap and pap->is_atom())
return as->add_atom(HandleCast(pap));
return h;
}
/// When executed, this will execute the third argument to obtain
/// a FloatValue or NumberNode, and then use those numbers to atomically
/// increment the FloatValue at the indicated key on the indicated
/// first argument. The updated value is returned.
///
/// The IncrementValueOnLink returns the Atom instead of the FloatValue.
///
/// If there is no Value at the indicated key, a new FloatValue is
/// created (assuming an initial value of all zeros.) If there is an
/// existing Value, and its not a Float, then no increment is performed.
ValuePtr IncrementValueLink::execute(AtomSpace* as, bool silent)
{
// Avoid null-pointer deref due to user error.
// This can happen with improperly built FilterLinks.
// See commentary in ValueOfLink::do_execute() about why
// we want an AtomSpace.
if (nullptr == as)
throw RuntimeException(TRACE_INFO,
"Expecting AtomSpace, got null pointer for %s\n",
to_string().c_str());
Handle ah(localize(as, silent, _outgoing[0]));
Handle ak(localize(as, silent, _outgoing[1]));
// Copy-on-write semantics means as->increment_count() might return
// a different Atom than the current ah.
ValuePtr vp(_outgoing[2]->execute(as, silent));
if (vp->is_type(FLOAT_VALUE))
{
ah = as->increment_count(ah, ak, FloatValueCast(vp)->value());
if (INCREMENT_VALUE_ON_LINK == get_type())
return ah;
return ah->getValue(ak);
}
if (vp->is_type(NUMBER_NODE))
{
ah = as->increment_count(ah, ak, NumberNodeCast(vp)->value());
if (INCREMENT_VALUE_ON_LINK == get_type())
return ah;
return ah->getValue(ak);
}
throw RuntimeException(TRACE_INFO,
"Expecting numeric value, got %s\n",
vp->to_string().c_str());
}
DEFINE_LINK_FACTORY(IncrementValueLink, INCREMENT_VALUE_LINK)
/* ===================== END OF FILE ===================== */