OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / opencog / atoms / value / Value.h

210 lines · c ref:
/*
 * opencog/atoms/value/Value.h
 *
 * Copyright (C) 2015 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.
 */

#ifndef _OPENCOG_VALUE_H
#define _OPENCOG_VALUE_H

#include <memory>
#include <string>

#include <opencog/util/empty_string.h>
#include <opencog/atoms/atom_types/types.h>
#include <opencog/atoms/atom_types/NameServer.h>
#include <opencog/atoms/base/Handle.h>

namespace opencog
{

/** \addtogroup grp_atomspace
 *  @{
 */

class Value;
typedef std::shared_ptr<Value> ValuePtr;

/**
 * Values are the base class for the Atom shared pointer.
 */
class Value
	: public std::enable_shared_from_this<Value>
{
protected:
	// We store the type locally, to avoid the overhead of
	// turning getType into a virtual method.
	Type _type;

public:
	Value(Type t) : _type(t) {}

	virtual ~Value() {}

	inline Type get_type() const { return _type; }

	virtual bool is_atom() const { return false; }
	virtual bool is_node() const { return false; }
	virtual bool is_link() const { return false; }
	virtual bool is_unordered_link() const { return false; }
	virtual size_t size() const { return 0; }

	/** Basic predicate */
	bool is_type(Type t, bool subclass = true) const
	{
		Type at(get_type());
		if (not subclass) return t == at;
		return nameserver().isA(at, t);
	}

	/**
	 * Returns a string representation of the value.
	 * The short string is used as a globally unique identifier, used
	 * by StorageNodes as the UUID for Atoms, and plain UID for Values.
	 * It should not contain any newlines or useless whitespace.
	 */
	virtual std::string to_string(const std::string& indent) const = 0;
	virtual std::string to_short_string(const std::string& indent) const
		{ return to_string(indent); }

	// Work around gdb's inability to build a string on the fly,
	// see http://stackoverflow.com/questions/16734783 for more
	// explanation.
	std::string to_string() const { return to_string(""); }
	std::string to_short_string() const { return to_short_string(""); }

	/**
	 * Returns whether two values are equal.
	 *
	 * @return true if the values are equal, false otherwise.
	 */
	virtual bool operator==(const Value&) const = 0;

	/**
	 * Returns whether two values are different.
	 *
	 * @return true if the values are different, false otherwise.
	 */
	bool operator!=(const Value& other) const
		{ return not operator==(other); }

	/**
	 * Returns whether this value is less than another.
	 * Used for ordering values in sets and maps, and specifically
	 * for deduplication in UnisetValue.
	 *
	 * @return true if this value is less than other, false otherwise.
	 */
	virtual bool operator<(const Value& other) const
		{ return to_string() < other.to_string(); }
};

// update() might throw an exception, e.g. an IOException if a
// StorageNode is not open. The problem is that if this was called
// from the guile shell, there is no handler that can catch this,
// and so guile will core-dump. So we install a handler now, and
// avoid this ugly fate.
#define SAFE_UPDATE(PRTSTR,PRINTER) \
try { \
	update(); \
	{ PRINTER; } \
} catch (const StandardException& ex) { \
	PRTSTR += " \""; \
	PRTSTR += ex.what(); \
	PRTSTR += "\""; \
}

typedef std::vector<ValuePtr> ValueSeq;
typedef std::set<ValuePtr> ValueSet;
typedef std::map<Handle, ValuePtr> ValueMap;

} // namespace opencog

// Specialize std::less for ValuePtr to compare by content, not pointer address
namespace std {
	template<>
	struct less<opencog::ValuePtr>
	{
		bool operator()(const opencog::ValuePtr& lhs, const opencog::ValuePtr& rhs) const
		{
			if (!lhs) return bool(rhs);  // null < non-null
			if (!rhs) return false;       // non-null >= null
			return *lhs < *rhs;           // compare content
		}
	};
}

namespace opencog {

// Debugging helpers see
// http://wiki.opencog.org/w/Development_standards#Print_OpenCog_Objects
// The reason indent is not an optional argument with default is
// because gdb doesn't support that, see
// http://stackoverflow.com/questions/16734783 for more explanation.
std::string oc_to_string(const ValuePtr& vp,
                         const std::string& indent=empty_string);
std::string oc_to_string(const ValueSeq& vs,
                         const std::string& indent=empty_string);
std::string oc_to_string(const ValueMap& vs,
                         const std::string& indent=empty_string);

class Atom;

/**
 * createValue() function. Creates Values of a specific type, using
 * the appropriate constructor. This function is defined only for
 * C++ types T which are subclasses of Value.
 */
template<typename T, typename ... Args>
static inline
typename std::enable_if<
	std::is_base_of<Value, T>::value && !std::is_base_of<Atom, T>::value,
	std::shared_ptr<T> >::type
createValue(Args&&... args) {
	return std::make_shared<T>(std::forward<Args>(args)...);
}

#define VALUE_PTR_DECL(CNAME) \
	typedef std::shared_ptr<CNAME> CNAME##Ptr; \
	static inline CNAME##Ptr CNAME##Cast(const ValuePtr& a) \
		{ return std::dynamic_pointer_cast<CNAME>(a); } \
	static inline const ValuePtr ValueCast(const CNAME##Ptr& fv) \
		{ return std::shared_ptr<Value>(fv, (Value*) fv.get()); }

#define CREATE_VALUE_DECL(CNAME) \
	template<typename ... Type> \
	static inline std::shared_ptr<CNAME> create##CNAME(Type&&... args) \
		{ return std::make_shared<CNAME>(std::forward<Type>(args)...); }

/** @}*/
} // namespace opencog

// overload of operator<< to print Values
namespace std
{
    template<typename Out>
    Out& operator<<(Out& out, const opencog::ValuePtr& pa)
    {
        out << pa->to_string("");
        return out;
    }
} // ~namespace std

#endif // _OPENCOG_VALUE_H