<commit_before>/*
 * ScopeLink.cc
 *
 * Copyright (C) 2009, 2014, 2015 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 <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/util/Logger.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/LambdaLink.h>
#include <opencog/atoms/core/TypeNode.h>

#include "ScopeLink.h"

using namespace opencog;

void ScopeLink::init(void)
{
	extract_variables(_outgoing);
}

ScopeLink::ScopeLink(const Handle& vars, const Handle& body)
	: Link(HandleSeq({vars, body}), SCOPE_LINK)
{
	init();
}

bool ScopeLink::skip_init(Type t)
{
	// Type must be as expected.
	if (not classserver().isA(t, SCOPE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a ScopeLink, got %s", tname.c_str());
	}

	// Certain derived classes want to have a different initialization
	// sequence. We can't use virtual init() in the ctor, so just
	// do an if-statement here.
	if (IMPLICATION_SCOPE_LINK == t) return true;
	if (PUT_LINK == t) return true;
	if (classserver().isA(t, PATTERN_LINK)) return true;
	return false;
}

ScopeLink::ScopeLink(Type t, const Handle& body)
	: Link(HandleSeq({body}), t)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(const HandleSeq& oset, Type t)
	: Link(oset, t)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(const Link &l)
	: Link(l)
{
	if (skip_init(l.get_type())) return;
	init();
}

/* ================================================================= */
///
/// Find and unpack variable declarations, if any; otherwise, just
/// find all free variables.
///
void ScopeLink::extract_variables(const HandleSeq& oset)
{
	if (oset.size() == 0)
		throw SyntaxException(TRACE_INFO,
			"Expecting a non-empty outgoing set.");

	Type decls = oset.at(0)->get_type();

	// If we trip over an unquote immediately, then we can assume that
	// the whole link appears in some quote context. This cannot be
	// treated as an ordinary ScopeLink in any way ... halt all further
	// initialization now.
	if (UNQUOTE_LINK == decls)
		return;

	// If the first atom is not explicitly a variable declaration, then
	// there are no variable declarations. There are two cases that can
	// apply here: either the body is a lambda, in which case, we copy
	// the variables from the lambda; else we extract all free variables.
	if (VARIABLE_LIST != decls and
	    // A VariableNode could a be valid body, if it has no variable
	    // declaration, that is if the Scope has only one argument.
	    (VARIABLE_NODE != decls or oset.size() == 1) and
	    TYPED_VARIABLE_LINK != decls and
	    GLOB_NODE != decls)
	{
		_body = oset[0];

		if (classserver().isA(_body->get_type(), LAMBDA_LINK))
		{
			LambdaLinkPtr lam(LambdaLinkCast(_body));
			_varlist = lam->get_variables();
			_body = lam->get_body();
		}
		else
		{
			_varlist.find_variables(oset[0]);
		}
		return;
	}

	if (oset.size() < 2)
		throw SyntaxException(TRACE_INFO,
			"Expecting an outgoing set size of at least two; got %s",
			oset[0]->to_string().c_str());

	// If we are here, then the first outgoing set member should be
	// a variable declaration.
	_vardecl = oset[0];
	_body = oset[1];

	// Initialize _varlist with the scoped variables
	init_scoped_variables(_vardecl);
}

/* ================================================================= */
///
/// Initialize _varlist given a handle of either VariableList or a
/// variable.
///
void ScopeLink::init_scoped_variables(const Handle& hvar)
{
	// Use the VariableList class as a tool to extract the variables
	// for us.
	VariableList vl(hvar);
	_varlist = vl.get_variables();
}

/* ================================================================= */
///
/// Compare other ScopeLink, return true if it is equal to this one,
/// up to an alpha-conversion of variables.
///
bool ScopeLink::is_equal(const Handle& other, bool silent) const
{
	if (other == this) return true;
	if (other->get_type() != _type) return false;

	ScopeLinkPtr scother(ScopeLinkCast(other));

	// If the hashes are not equal, they can't possibly be equivalent.
	if (get_hash() != scother->get_hash()) return false;

	// Some derived classes (such as BindLink) have multiple body parts,
	// so it is not enough to compare this->_body to other->_body.
	// They tricky bit, below, is skipping over variable decls correctly,
	// to find the remaining body parts. Start by counting to make sure
	// that this and other have the same number of body parts.
	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity other_vardecl_offset = scother->_vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = get_arity() - vardecl_offset;
	Arity other_n_scoped_terms = other->get_arity() - other_vardecl_offset;
	if (n_scoped_terms != other_n_scoped_terms) return false;

	// Variable declarations must match.
	if (not _varlist.is_equal(scother->_varlist)) return false;

	// If all of the variable names are identical in this and other,
	// then no alpha conversion needs to be done; we can do a direct
	// comparison.
	if (_varlist.is_identical(scother->_varlist))
	{
		// Compare them, they should match.
		const HandleSeq& otho(other->getOutgoingSet());
		for (Arity i = 0; i < n_scoped_terms; ++i)
		{
			const Handle& h(_outgoing[i + vardecl_offset]);
			const Handle& other_h(otho[i + other_vardecl_offset]);
			if (h->operator!=(*((AtomPtr) other_h))) return false;
		}
		return true;
	}

	// If we are here, we need to perform alpha conversion to test
	// equality.  Other terms, with our variables in place of its
	// variables, should be same as our terms.
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		Handle h = getOutgoingAtom(i + vardecl_offset);
		Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
		other_h = scother->_varlist.substitute_nocheck(other_h,
		                                         _varlist.varseq, silent);
		// Compare them, they should match.
		if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
	}

	return true;
}

/* ================================================================= */

/// A specialized hashing function, designed so that all alpha-
/// convertable links get exactly the same hash.  To acheive this,
/// the actual variable names have to be excluded from the hash,
/// and a standardized set used instead.
//
// There's a lot of prime-numbers in the code below, but the
// actual mixing and avalanching is extremely poor. I'm hoping
// its good enough for hash buckets, but have not verified.
//
// (In the code below, the numbers of the form `((1UL<<35) - 325)`
// etc. are all prime numbers. "Mixing" refers to code having the
// form `hash += (hash<<5) + other_stuff;` -- the shift and add
// mixes the bits. "Avalanching" refers to single-bit differences
// rapidly turning into multi-bit differences.)
//
// There's also an issue that there are multiple places where the
// hash must not mix, and must stay abelian, in order to deal with
// unordered links and alpha-conversion. (Here, "abelian" refers to
// order independence; addition is abelian; while "mixing" as
// defined above, is non-abelian).
//
ContentHash ScopeLink::compute_hash() const
{
	ContentHash hsh = ((1UL<<35) - 325) * get_type();
	hsh += (hsh <<5) + ((1UL<<47) - 649) * _varlist.varseq.size();

	// It is not safe to mix here, since the sort order of the
	// typemaps will depend on the variable names. So must be
	// abelian.
	ContentHash vth = 0;
	for (const auto& pr : _varlist._simple_typemap)
	{
		for (Type t : pr.second) vth += ((1UL<<19) - 87) * t;
	}

	for (const auto& pr : _varlist._deep_typemap)
	{
		for (const Handle& th : pr.second) vth += th->get_hash();
	}
	hsh += (hsh <<5) + (vth % ((1UL<<27) - 235));

	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = get_arity() - vardecl_offset;

	UnorderedHandleSet hidden;
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		const Handle& h(_outgoing[i + vardecl_offset]);
		hsh += (hsh<<5) + term_hash(h, hidden);
	}
	hsh %= (1UL << 63) - 409;

	// Links will always have the MSB set.
	ContentHash mask = ((ContentHash) 1UL) << (8*sizeof(ContentHash) - 1);
	hsh |= mask;

	if (Handle::INVALID_HASH == hsh) hsh -= 1;
	_content_hash = hsh;
	return _content_hash;
}

/// Recursive helper for computing the content hash correctly for
/// scoped links.  The algorithm here is almost identical to that
/// used in VarScraper::find_vars(), with obvious alterations.
ContentHash ScopeLink::term_hash(const Handle& h,
                                 UnorderedHandleSet& bound_vars,
                                 Quotation quotation) const
{
	Type t = h->get_type();
	if ((VARIABLE_NODE == t or GLOB_NODE == t) and
	    quotation.is_unquoted() and
	    0 != _varlist.varset.count(h) and
	    0 == bound_vars.count(h))
	{
		// Alpha-convert the variable "name" to its unique position
		// in the sequence of bound vars.  Thus, the name is unique.
		return ((1UL<<24)-77) * (1 + _varlist.index.find(h)->second);
	}

	// Just the plain old hash for all other nodes.
	if (h->is_node()) return h->get_hash();

	// Quotation
	quotation.update(t);

	// Other embedded ScopeLinks might be hiding some of our variables...
	bool issco = classserver().isA(t, SCOPE_LINK);
	UnorderedHandleSet bsave;
	if (issco)
	{
		// Protect current hidden vars from harm.
		bsave = bound_vars;
		// Add the Scope link vars to the hidden set.
		ScopeLinkPtr sco(ScopeLinkCast(h));
		const Variables& vees = sco->get_variables();
		for (const Handle& v : vees.varseq) bound_vars.insert(v);
	}

	// Prevent mixing for UnorderedLinks. The `mixer` var will be zero
	// for UnorderedLinks. The problem is that two UnorderdLinks might
	// be alpha-equivalent, but have their atoms presented in a
	// different order. Thus, the hash must be computed in a purely
	// commutative fashion: using only addition, so as to never create
	// any entropy, until the end.
	//
	// XXX As discussed in issue #1176, a better fix would be to
	// compute the individual term_hashes first, then sort them,
	// and then mix them!  This provides the desired qualities:
	// different unordered links can be directly compared, and also
	// have good mixing/avalanching properties. The code below
	// only allows for compare; it fails to mix.
	//
	bool is_ordered = not classserver().isA(t, UNORDERED_LINK);
	ContentHash mixer = (ContentHash) is_ordered;
	ContentHash hsh = ((1UL<<8) - 59) * t;
	for (const Handle& ho: h->getOutgoingSet())
	{
		hsh += mixer * (hsh<<5) + term_hash(ho, bound_vars, quotation);
	}
	hsh %= (1UL<<63) - 471;

	// Restore saved vars from stack.
	if (issco) bound_vars = bsave;

	return hsh;
}

/* ================================================================= */

inline std::string rand_hex_str()
{
	int rnd_id = randGen().randint();
	std::stringstream ss;
	ss << std::hex << rnd_id;
	return ss.str();
}

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars) {
		std::string new_var_name = h->get_name() + "-" + rand_hex_str();
		new_vars.emplace_back(createNode(VARIABLE_NODE, new_var_name));
	}
	return new_vars;
}

Handle ScopeLink::alpha_conversion(HandleSeq vars) const
{
	// If hs is empty then generate new variable names
	if (vars.empty())
		vars = append_rand_str(_varlist.varseq);

	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < get_arity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars));

	// Create the alpha converted scope link
	return createLink(hs, get_type());
}

/* ================================================================= */

bool ScopeLink::operator==(const Atom& ac) const
{
	Atom& a = (Atom&) ac; // cast away constness, for smart ptr.
	try {
		return is_equal(a.get_handle(), true);
	} catch (const NestingException& ex) {}
	return false;
}

bool ScopeLink::operator!=(const Atom& a) const
{
	return not operator==(a);
}

DEFINE_LINK_FACTORY(ScopeLink, SCOPE_LINK);

/* ===================== END OF FILE ===================== */
<commit_msg>Use randstr from cogutil<commit_after>/*
 * ScopeLink.cc
 *
 * Copyright (C) 2009, 2014, 2015 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 <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/util/random.h>
#include <opencog/util/Logger.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/LambdaLink.h>
#include <opencog/atoms/core/TypeNode.h>

#include "ScopeLink.h"

using namespace opencog;

void ScopeLink::init(void)
{
	extract_variables(_outgoing);
}

ScopeLink::ScopeLink(const Handle& vars, const Handle& body)
	: Link(HandleSeq({vars, body}), SCOPE_LINK)
{
	init();
}

bool ScopeLink::skip_init(Type t)
{
	// Type must be as expected.
	if (not classserver().isA(t, SCOPE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a ScopeLink, got %s", tname.c_str());
	}

	// Certain derived classes want to have a different initialization
	// sequence. We can't use virtual init() in the ctor, so just
	// do an if-statement here.
	if (IMPLICATION_SCOPE_LINK == t) return true;
	if (PUT_LINK == t) return true;
	if (classserver().isA(t, PATTERN_LINK)) return true;
	return false;
}

ScopeLink::ScopeLink(Type t, const Handle& body)
	: Link(HandleSeq({body}), t)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(const HandleSeq& oset, Type t)
	: Link(oset, t)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(const Link &l)
	: Link(l)
{
	if (skip_init(l.get_type())) return;
	init();
}

/* ================================================================= */
///
/// Find and unpack variable declarations, if any; otherwise, just
/// find all free variables.
///
void ScopeLink::extract_variables(const HandleSeq& oset)
{
	if (oset.size() == 0)
		throw SyntaxException(TRACE_INFO,
			"Expecting a non-empty outgoing set.");

	Type decls = oset.at(0)->get_type();

	// If we trip over an unquote immediately, then we can assume that
	// the whole link appears in some quote context. This cannot be
	// treated as an ordinary ScopeLink in any way ... halt all further
	// initialization now.
	if (UNQUOTE_LINK == decls)
		return;

	// If the first atom is not explicitly a variable declaration, then
	// there are no variable declarations. There are two cases that can
	// apply here: either the body is a lambda, in which case, we copy
	// the variables from the lambda; else we extract all free variables.
	if (VARIABLE_LIST != decls and
	    // A VariableNode could a be valid body, if it has no variable
	    // declaration, that is if the Scope has only one argument.
	    (VARIABLE_NODE != decls or oset.size() == 1) and
	    TYPED_VARIABLE_LINK != decls and
	    GLOB_NODE != decls)
	{
		_body = oset[0];

		if (classserver().isA(_body->get_type(), LAMBDA_LINK))
		{
			LambdaLinkPtr lam(LambdaLinkCast(_body));
			_varlist = lam->get_variables();
			_body = lam->get_body();
		}
		else
		{
			_varlist.find_variables(oset[0]);
		}
		return;
	}

	if (oset.size() < 2)
		throw SyntaxException(TRACE_INFO,
			"Expecting an outgoing set size of at least two; got %s",
			oset[0]->to_string().c_str());

	// If we are here, then the first outgoing set member should be
	// a variable declaration.
	_vardecl = oset[0];
	_body = oset[1];

	// Initialize _varlist with the scoped variables
	init_scoped_variables(_vardecl);
}

/* ================================================================= */
///
/// Initialize _varlist given a handle of either VariableList or a
/// variable.
///
void ScopeLink::init_scoped_variables(const Handle& hvar)
{
	// Use the VariableList class as a tool to extract the variables
	// for us.
	VariableList vl(hvar);
	_varlist = vl.get_variables();
}

/* ================================================================= */
///
/// Compare other ScopeLink, return true if it is equal to this one,
/// up to an alpha-conversion of variables.
///
bool ScopeLink::is_equal(const Handle& other, bool silent) const
{
	if (other == this) return true;
	if (other->get_type() != _type) return false;

	ScopeLinkPtr scother(ScopeLinkCast(other));

	// If the hashes are not equal, they can't possibly be equivalent.
	if (get_hash() != scother->get_hash()) return false;

	// Some derived classes (such as BindLink) have multiple body parts,
	// so it is not enough to compare this->_body to other->_body.
	// They tricky bit, below, is skipping over variable decls correctly,
	// to find the remaining body parts. Start by counting to make sure
	// that this and other have the same number of body parts.
	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity other_vardecl_offset = scother->_vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = get_arity() - vardecl_offset;
	Arity other_n_scoped_terms = other->get_arity() - other_vardecl_offset;
	if (n_scoped_terms != other_n_scoped_terms) return false;

	// Variable declarations must match.
	if (not _varlist.is_equal(scother->_varlist)) return false;

	// If all of the variable names are identical in this and other,
	// then no alpha conversion needs to be done; we can do a direct
	// comparison.
	if (_varlist.is_identical(scother->_varlist))
	{
		// Compare them, they should match.
		const HandleSeq& otho(other->getOutgoingSet());
		for (Arity i = 0; i < n_scoped_terms; ++i)
		{
			const Handle& h(_outgoing[i + vardecl_offset]);
			const Handle& other_h(otho[i + other_vardecl_offset]);
			if (h->operator!=(*((AtomPtr) other_h))) return false;
		}
		return true;
	}

	// If we are here, we need to perform alpha conversion to test
	// equality.  Other terms, with our variables in place of its
	// variables, should be same as our terms.
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		Handle h = getOutgoingAtom(i + vardecl_offset);
		Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
		other_h = scother->_varlist.substitute_nocheck(other_h,
		                                         _varlist.varseq, silent);
		// Compare them, they should match.
		if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
	}

	return true;
}

/* ================================================================= */

/// A specialized hashing function, designed so that all alpha-
/// convertable links get exactly the same hash.  To acheive this,
/// the actual variable names have to be excluded from the hash,
/// and a standardized set used instead.
//
// There's a lot of prime-numbers in the code below, but the
// actual mixing and avalanching is extremely poor. I'm hoping
// its good enough for hash buckets, but have not verified.
//
// (In the code below, the numbers of the form `((1UL<<35) - 325)`
// etc. are all prime numbers. "Mixing" refers to code having the
// form `hash += (hash<<5) + other_stuff;` -- the shift and add
// mixes the bits. "Avalanching" refers to single-bit differences
// rapidly turning into multi-bit differences.)
//
// There's also an issue that there are multiple places where the
// hash must not mix, and must stay abelian, in order to deal with
// unordered links and alpha-conversion. (Here, "abelian" refers to
// order independence; addition is abelian; while "mixing" as
// defined above, is non-abelian).
//
ContentHash ScopeLink::compute_hash() const
{
	ContentHash hsh = ((1UL<<35) - 325) * get_type();
	hsh += (hsh <<5) + ((1UL<<47) - 649) * _varlist.varseq.size();

	// It is not safe to mix here, since the sort order of the
	// typemaps will depend on the variable names. So must be
	// abelian.
	ContentHash vth = 0;
	for (const auto& pr : _varlist._simple_typemap)
	{
		for (Type t : pr.second) vth += ((1UL<<19) - 87) * t;
	}

	for (const auto& pr : _varlist._deep_typemap)
	{
		for (const Handle& th : pr.second) vth += th->get_hash();
	}
	hsh += (hsh <<5) + (vth % ((1UL<<27) - 235));

	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = get_arity() - vardecl_offset;

	UnorderedHandleSet hidden;
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		const Handle& h(_outgoing[i + vardecl_offset]);
		hsh += (hsh<<5) + term_hash(h, hidden);
	}
	hsh %= (1UL << 63) - 409;

	// Links will always have the MSB set.
	ContentHash mask = ((ContentHash) 1UL) << (8*sizeof(ContentHash) - 1);
	hsh |= mask;

	if (Handle::INVALID_HASH == hsh) hsh -= 1;
	_content_hash = hsh;
	return _content_hash;
}

/// Recursive helper for computing the content hash correctly for
/// scoped links.  The algorithm here is almost identical to that
/// used in VarScraper::find_vars(), with obvious alterations.
ContentHash ScopeLink::term_hash(const Handle& h,
                                 UnorderedHandleSet& bound_vars,
                                 Quotation quotation) const
{
	Type t = h->get_type();
	if ((VARIABLE_NODE == t or GLOB_NODE == t) and
	    quotation.is_unquoted() and
	    0 != _varlist.varset.count(h) and
	    0 == bound_vars.count(h))
	{
		// Alpha-convert the variable "name" to its unique position
		// in the sequence of bound vars.  Thus, the name is unique.
		return ((1UL<<24)-77) * (1 + _varlist.index.find(h)->second);
	}

	// Just the plain old hash for all other nodes.
	if (h->is_node()) return h->get_hash();

	// Quotation
	quotation.update(t);

	// Other embedded ScopeLinks might be hiding some of our variables...
	bool issco = classserver().isA(t, SCOPE_LINK);
	UnorderedHandleSet bsave;
	if (issco)
	{
		// Protect current hidden vars from harm.
		bsave = bound_vars;
		// Add the Scope link vars to the hidden set.
		ScopeLinkPtr sco(ScopeLinkCast(h));
		const Variables& vees = sco->get_variables();
		for (const Handle& v : vees.varseq) bound_vars.insert(v);
	}

	// Prevent mixing for UnorderedLinks. The `mixer` var will be zero
	// for UnorderedLinks. The problem is that two UnorderdLinks might
	// be alpha-equivalent, but have their atoms presented in a
	// different order. Thus, the hash must be computed in a purely
	// commutative fashion: using only addition, so as to never create
	// any entropy, until the end.
	//
	// XXX As discussed in issue #1176, a better fix would be to
	// compute the individual term_hashes first, then sort them,
	// and then mix them!  This provides the desired qualities:
	// different unordered links can be directly compared, and also
	// have good mixing/avalanching properties. The code below
	// only allows for compare; it fails to mix.
	//
	bool is_ordered = not classserver().isA(t, UNORDERED_LINK);
	ContentHash mixer = (ContentHash) is_ordered;
	ContentHash hsh = ((1UL<<8) - 59) * t;
	for (const Handle& ho: h->getOutgoingSet())
	{
		hsh += mixer * (hsh<<5) + term_hash(ho, bound_vars, quotation);
	}
	hsh %= (1UL<<63) - 471;

	// Restore saved vars from stack.
	if (issco) bound_vars = bsave;

	return hsh;
}

/* ================================================================= */

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars) {
		std::string new_var_name = randstr(h->get_name() + "-");
		new_vars.emplace_back(createNode(VARIABLE_NODE, new_var_name));
	}
	return new_vars;
}

Handle ScopeLink::alpha_conversion(HandleSeq vars) const
{
	// If hs is empty then generate new variable names
	if (vars.empty())
		vars = append_rand_str(_varlist.varseq);

	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < get_arity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars));

	// Create the alpha converted scope link
	return createLink(hs, get_type());
}

/* ================================================================= */

bool ScopeLink::operator==(const Atom& ac) const
{
	Atom& a = (Atom&) ac; // cast away constness, for smart ptr.
	try {
		return is_equal(a.get_handle(), true);
	} catch (const NestingException& ex) {}
	return false;
}

bool ScopeLink::operator!=(const Atom& a) const
{
	return not operator==(a);
}

DEFINE_LINK_FACTORY(ScopeLink, SCOPE_LINK);

/* ===================== END OF FILE ===================== */
<|endoftext|>


<commit_before>// Function grapher: user can choose among a set of functions (e.g., sin() and
// log(), provide parameters for those functions and then graph them

#include "Simple_window.h"
#include "Graph.h"

int main()
try {
    Point tl(400,150);
    Fgraph_window fwin(tl,800,605,"Function Grapher");
    return gui_main();
}
catch (exception& e) {
    cerr << "exception: " << e.what() << endl;
    keep_window_open();
}
catch (...) {
    cerr << "exception\n";
    keep_window_open();
}<commit_msg>Complete header comment of Chapter 16, exercise 10<commit_after>// Chapter 16, exercise 10: function grapher: user can choose among a set of
// functions (e.g., sin() and log(), provide parameters for those functions and
// then graph them

#include "Simple_window.h"
#include "Graph.h"

int main()
try {
    Point tl(400,150);
    Fgraph_window fwin(tl,800,605,"Function Grapher");
    return gui_main();
}
catch (exception& e) {
    cerr << "exception: " << e.what() << endl;
    keep_window_open();
}
catch (...) {
    cerr << "exception\n";
    keep_window_open();
}
<|endoftext|>


<commit_before>#include <bits/stdc++.h>
using namespace std;
typedef vector <int> vi;

vector <string> piece;
vector <vector <int>> status;
int n = 8;
//int n;
int m = 8;

void rook(int row, int col){
	status[row][col] = true;
	for(int i=row+1; i<n; i++){
		if(piece[i][col] != '0') break;
		status[i][col] = true;
	}
	for(int i=row-1; i>=0; i--){
		if(piece[i][col] != '0') break;
		status[i][col] = true;
	}
	for(int i=col+1; i<m; i++){
		if(piece[row][i] != '0') break;
		status[row][i] = true;
	}
	for(int i=col-1; i>=0; i--){
		if(piece[row][i] != '0') break;
		status[row][i] = true;
	}
	return;
}
void knight(int row, int col){
	status[row][col] = true;
	if(row-2>=0 && col+1<m) status[row-2][col+1] = true;
	if(row-1>=0 && col+2<m) status[row-1][col+2] = true;
	if(row+1<n && col+2<m) status[row+1][col+2] = true;
	if(row+2<n && col+1<m) status[row+2][col+1] = true;
	if(row+2<n && col-1>=0) status[row+2][col-1] = true;
	if(row+1<n && col-2>=0) status[row+1][col-2] = true;
	if(row-1>=0 && col-2>=0) status[row-1][col-2] = true;
	if(row-2>=0 && col-1 >= 0) status[row-2][col-1] = true;
	return;
}
void king(int row, int col){
	status[row][col] = true;
	if(row-1>=0) status[row-1][col] = true;
	if(row-1>=0 && col+1<m) status[row-1][col+1] = true;
	if(col+1<m) status[row][col+1] = true;
	if(row+1<n && col+1<m) status[row+1][col+1] = true;
	if(row+1<n) status[row+1][col] = true;
	if(row+1<n && col-1>=0) status[row+1][col-1] = true;
	if(col-1>=0) status[row][col-1] = true;
	if(row-1>=0 && col-1>=0) status[row-1][col-1] = true;
	return;
}
void bishop(int row, int col){
	status[row][col] = true;
	for(int i=row+1; col-row+i<m && i<n; i++){
		if(piece[i][col-row+i] != '0') break;
		status[i][col-row+i] = true;
	}
	for(int i=row-1; col-row+i>=0 && i>=0; i--){
		if(piece[i][col-row+i] != '0') break;
		status[i][col-row+i] = true;
	}
	for(int i=row+1; col+row-i>=0 && i<n; i++){
		if(piece[i][col+row-i] != '0') break;
		status[i][col+row-i] = true;
	}
	for(int i=row-1; col+row-i<m && i>=0; i--){
		if(piece[i][col+row-i] != '0') break;
		status[i][col+row-i] = true;
	}
	return;
}
void queen(int row, int col){
	bishop(row, col);
	rook(row, col);
	return;
}
void pawn(int row, int col, int color){
	status[row][col] = true;
	if(color == 0){
		if(row+1<n && col-1>=0) status[row+1][col-1] = true;
		if(row+1<n && col+1<m) status[row+1][col+1] = true;
	}
	else {
		if(row-1>=0 && col+1<m) status[row-1][col+1] = true;
		if(row-1>=0 && col-1<m) status[row-1][col-1] = true;
	}
	return;
}

void printv(ostream &cout){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++) cout << piece[i][j];
		cout << endl;
	}
	cout << endl;
}
void print(ostream &cout){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++) cout << status[i][j];
		cout << endl;
	}
	cout << endl;
}
int main(){
	//ifstream cin("in.txt");
	//ofstream cout("out.txt");
	string a;
	while(cin >> a){
		//n = count(a.begin(), a.end(), '/') + 1;
		//cout << n << endl;
		piece.resize(n);
		status.resize(n, vector <int> (m));
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				piece[i][j] = '0';
				status[i][j] = false;
			}
		}
		int index = 0;
		int k = 0;
		char current;
		while(index != a.size()){
			current = a[index];
			if(current >= '1' && current <= '8') k+=current-'0'-1;
			else if(current == '/') k--;
			else piece[k/8][k%8] = current;
			assert(k/8<n && k%8<m);
			k++;
			index++;
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				current = piece[i][j];
				if(current == '0');
				else if(tolower(current) == 'r') rook(i, j);
				else if(tolower(current) == 'n') knight(i, j);
				else if(tolower(current) == 'k') king(i, j);
				else if(tolower(current) == 'q') queen(i, j);
				else if(tolower(current) == 'b') bishop(i, j);
				else if(current == 'p') pawn(i, j, 0);
				else if(current == 'P') pawn(i, j, 1);
			}
		}
		//print(cout);
		//printv(cout);
		int counter = 0;
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				if(status[i][j] == false) counter++;
			}
		}
		cout << counter << endl;
	}
}
<commit_msg>Update chessboard_in_fen.cpp<commit_after>#include <bits/stdc++.h>
using namespace std;
typedef vector <int> vi;

vector <string> piece;
vector <vector <int>> status;
int n = 8;
//int n;
int m = 8;

void rook(int row, int col){
	status[row][col] = true;
	for(int i=row+1; i<n; i++){
		if(piece[i][col] != '0') break;
		status[i][col] = true;
	}
	for(int i=row-1; i>=0; i--){
		if(piece[i][col] != '0') break;
		status[i][col] = true;
	}
	for(int i=col+1; i<m; i++){
		if(piece[row][i] != '0') break;
		status[row][i] = true;
	}
	for(int i=col-1; i>=0; i--){
		if(piece[row][i] != '0') break;
		status[row][i] = true;
	}
	return;
}
void knight(int row, int col){
	status[row][col] = true;
	if(row-2>=0 && col+1<m) status[row-2][col+1] = true;
	if(row-1>=0 && col+2<m) status[row-1][col+2] = true;
	if(row+1<n && col+2<m) status[row+1][col+2] = true;
	if(row+2<n && col+1<m) status[row+2][col+1] = true;
	if(row+2<n && col-1>=0) status[row+2][col-1] = true;
	if(row+1<n && col-2>=0) status[row+1][col-2] = true;
	if(row-1>=0 && col-2>=0) status[row-1][col-2] = true;
	if(row-2>=0 && col-1 >= 0) status[row-2][col-1] = true;
	return;
}
void king(int row, int col){
	status[row][col] = true;
	if(row-1>=0) status[row-1][col] = true;
	if(row-1>=0 && col+1<m) status[row-1][col+1] = true;
	if(col+1<m) status[row][col+1] = true;
	if(row+1<n && col+1<m) status[row+1][col+1] = true;
	if(row+1<n) status[row+1][col] = true;
	if(row+1<n && col-1>=0) status[row+1][col-1] = true;
	if(col-1>=0) status[row][col-1] = true;
	if(row-1>=0 && col-1>=0) status[row-1][col-1] = true;
	return;
}
void bishop(int row, int col){
	status[row][col] = true;
	for(int i=row+1; col-row+i<m && i<n; i++){
		if(piece[i][col-row+i] != '0') break;
		status[i][col-row+i] = true;
	}
	for(int i=row-1; col-row+i>=0 && i>=0; i--){
		if(piece[i][col-row+i] != '0') break;
		status[i][col-row+i] = true;
	}
	for(int i=row+1; col+row-i>=0 && i<n; i++){
		if(piece[i][col+row-i] != '0') break;
		status[i][col+row-i] = true;
	}
	for(int i=row-1; col+row-i<m && i>=0; i--){
		if(piece[i][col+row-i] != '0') break;
		status[i][col+row-i] = true;
	}
	return;
}
void queen(int row, int col){
	bishop(row, col);
	rook(row, col);
	return;
}
void pawn(int row, int col, int color){
	status[row][col] = true;
	if(color == 0){
		if(row+1<n && col-1>=0) status[row+1][col-1] = true;
		if(row+1<n && col+1<m) status[row+1][col+1] = true;
	}
	else {
		if(row-1>=0 && col+1<m) status[row-1][col+1] = true;
		if(row-1>=0 && col-1>=0) status[row-1][col-1] = true;
	}
	return;
}

void printv(ostream &cout){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++) cout << piece[i][j];
		cout << endl;
	}
	cout << endl;
}
void print(ostream &cout){
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++) cout << status[i][j];
		cout << endl;
	}
	cout << endl;
}
int main(){
	//ifstream cin("in.txt");
	//ofstream cout("out.txt");
	string a;
	while(cin >> a){
		//n = count(a.begin(), a.end(), '/') + 1;
		//cout << n << endl;
		piece.resize(n);
		status.resize(n, vector <int> (m));
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				piece[i][j] = '0';
				status[i][j] = false;
			}
		}
		int index = 0;
		int k = 0;
		char current;
		while(index != a.size()){
			current = a[index];
			if(current >= '1' && current <= '8') k+=current-'0'-1;
			else if(current == '/') k--;
			else piece[k/8][k%8] = current;
			assert(k/8<n && k%8<m);
			k++;
			index++;
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				current = piece[i][j];
				if(current == '0');
				else if(tolower(current) == 'r') rook(i, j);
				else if(tolower(current) == 'n') knight(i, j);
				else if(tolower(current) == 'k') king(i, j);
				else if(tolower(current) == 'q') queen(i, j);
				else if(tolower(current) == 'b') bishop(i, j);
				else if(current == 'p') pawn(i, j, 0);
				else if(current == 'P') pawn(i, j, 1);
			}
		}
		//print(cout);
		//printv(cout);
		int counter = 0;
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				if(status[i][j] == false) counter++;
			}
		}
		cout << counter << endl;
	}
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <core/CHIPCore.h>

#include <ChipShellCollection.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CHIP_ENABLE_OPENTHREAD

#include <stdio.h>

#include <lib/shell/Engine.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <platform/ThreadStackManager.h>

#if CHIP_TARGET_STYLE_EMBEDDED
#include <openthread/cli.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
#include <openthread/link.h>
#include <openthread/thread.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif

using namespace chip;
using namespace chip::Shell;
using namespace chip::Platform;
using namespace chip::DeviceLayer;
using namespace chip::Logging;
using namespace chip::ArgParser;

static chip::Shell::Engine sShellOtcliSubcommands;

int cmd_otcli_help_iterator(shell_command_t * command, void * arg)
{
    streamer_printf(streamer_get(), "  %-15s %s\n\r", command->cmd_name, command->cmd_help);
    return 0;
}

int cmd_otcli_help(int argc, char ** argv)
{
    sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, nullptr);
    return 0;
}

#if CHIP_TARGET_STYLE_EMBEDDED

int cmd_otcli_dispatch(int argc, char ** argv)
{
    CHIP_ERROR error = CHIP_NO_ERROR;

// From OT CLI internal lib, kMaxLineLength = 128
#define kMaxLineLength 128
    char buff[kMaxLineLength] = { 0 };
    char * buff_ptr           = buff;
    int i                     = 0;

    VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);

    for (i = 0; i < argc; i++)
    {
        size_t arg_len = strlen(argv[i]);

        /* Make sure that the next argument won't overflow the buffer */
        VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL);

        strncpy(buff_ptr, argv[i], arg_len);
        buff_ptr += arg_len;

        /* Make sure that there is enough buffer for a space char */
        if (buff_ptr + sizeof(char) < buff + kMaxLineLength)
        {
            strncpy(buff_ptr, " ", sizeof(char));
            buff_ptr++;
        }
    }
    buff_ptr = 0;

    otCliConsoleInputLine(buff, buff_ptr - buff);
exit:
    return error;
}

#elif CHIP_TARGET_STYLE_UNIX

int cmd_otcli_dispatch(int argc, char ** argv)
{
    CHIP_ERROR error = CHIP_NO_ERROR;

    int pid;
    uid_t euid         = geteuid();
    char ctl_command[] = "/usr/local/sbin/ot-ctl";

    // Must run as sudo.
    if (euid != 0)
    {
        streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
        error = CHIP_ERROR_INCORRECT_STATE;
        ExitNow();
    }

    VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);

    // Fork and execute the command.
    pid = fork();
    VerifyOrExit(pid != -1, error = CHIP_ERROR_INCORRECT_STATE);

    if (pid == 0)
    {
        // Child process to execute the command with provided arguments
        --argv; // Restore access to entry [0] containing the command;
        argv[0] = ctl_command;
        if (execvp(ctl_command, argv) < 0)
        {
            streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
        }
        exit(errno);
    }
    else
    {
        // Parent process to wait on child.
        int status;
        wait(&status);
        error = (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
    }

exit:
    return error;
}

#endif // CHIP_TARGET_STYLE_UNIX

static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };

#if CHIP_TARGET_STYLE_EMBEDDED
static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
{
    return streamer_write(streamer_get(), aBuf, aBufLength);
}
#endif

#endif // CHIP_ENABLE_OPENTHREAD

void cmd_otcli_init()
{
#if CHIP_ENABLE_OPENTHREAD
#if CHIP_TARGET_STYLE_EMBEDDED
    otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
#endif

    // Register the root otcli command with the top-level shell.
    Engine::Root().RegisterCommands(&cmds_otcli_root, 1);
#endif // CHIP_ENABLE_OPENTHREAD
}
<commit_msg>Shell example: OT-CLI compilation error fixed for EFR32 boards. (#7275)<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include <core/CHIPCore.h>

#include <ChipShellCollection.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CHIP_ENABLE_OPENTHREAD

#include <stdio.h>

#include <lib/shell/Engine.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <platform/ThreadStackManager.h>

#if CHIP_TARGET_STYLE_EMBEDDED
#include <openthread/cli.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
#include <openthread/link.h>
#include <openthread/thread.h>
#ifdef EFR32_OPENTHREAD_API
#ifndef SHELL_OTCLI_TX_BUFFER_SIZE
#define SHELL_OTCLI_TX_BUFFER_SIZE 1024
#endif
static char sTxBuffer[SHELL_OTCLI_TX_BUFFER_SIZE];
static constexpr uint16_t sTxLength = SHELL_OTCLI_TX_BUFFER_SIZE;
#endif
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#endif

using namespace chip;
using namespace chip::Shell;
using namespace chip::Platform;
using namespace chip::DeviceLayer;
using namespace chip::Logging;
using namespace chip::ArgParser;

static chip::Shell::Engine sShellOtcliSubcommands;

int cmd_otcli_help_iterator(shell_command_t * command, void * arg)
{
    streamer_printf(streamer_get(), "  %-15s %s\n\r", command->cmd_name, command->cmd_help);
    return 0;
}

int cmd_otcli_help(int argc, char ** argv)
{
    sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, nullptr);
    return 0;
}

#if CHIP_TARGET_STYLE_EMBEDDED

int cmd_otcli_dispatch(int argc, char ** argv)
{
    CHIP_ERROR error = CHIP_NO_ERROR;

// From OT CLI internal lib, kMaxLineLength = 128
#define kMaxLineLength 128
    char buff[kMaxLineLength] = { 0 };
    char * buff_ptr           = buff;
    int i                     = 0;

    VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);

    for (i = 0; i < argc; i++)
    {
        size_t arg_len = strlen(argv[i]);

        /* Make sure that the next argument won't overflow the buffer */
        VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL);

        strncpy(buff_ptr, argv[i], arg_len);
        buff_ptr += arg_len;

        /* Make sure that there is enough buffer for a space char */
        if (buff_ptr + sizeof(char) < buff + kMaxLineLength)
        {
            strncpy(buff_ptr, " ", sizeof(char));
            buff_ptr++;
        }
    }
    buff_ptr = 0;
#ifdef EFR32_OPENTHREAD_API
    otCliInputLine(buff);
#else
    otCliConsoleInputLine(buff, buff_ptr - buff);
#endif
exit:
    return error;
}

#elif CHIP_TARGET_STYLE_UNIX

int cmd_otcli_dispatch(int argc, char ** argv)
{
    CHIP_ERROR error = CHIP_NO_ERROR;

    int pid;
    uid_t euid         = geteuid();
    char ctl_command[] = "/usr/local/sbin/ot-ctl";

    // Must run as sudo.
    if (euid != 0)
    {
        streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r");
        error = CHIP_ERROR_INCORRECT_STATE;
        ExitNow();
    }

    VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT);

    // Fork and execute the command.
    pid = fork();
    VerifyOrExit(pid != -1, error = CHIP_ERROR_INCORRECT_STATE);

    if (pid == 0)
    {
        // Child process to execute the command with provided arguments
        --argv; // Restore access to entry [0] containing the command;
        argv[0] = ctl_command;
        if (execvp(ctl_command, argv) < 0)
        {
            streamer_printf(streamer_get(), "Error exec %s: %s\n", ctl_command, strerror(errno));
        }
        exit(errno);
    }
    else
    {
        // Parent process to wait on child.
        int status;
        wait(&status);
        error = (status) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR;
    }

exit:
    return error;
}

#endif // CHIP_TARGET_STYLE_UNIX

static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" };

#if CHIP_TARGET_STYLE_EMBEDDED
#ifdef EFR32_OPENTHREAD_API
static int OnOtCliOutput(void * aContext, const char * aFormat, va_list aArguments)
{
    int rval = vsnprintf(sTxBuffer, sTxLength, aFormat, aArguments);
    VerifyOrExit(rval >= 0 && rval < sTxLength, rval = CHIP_ERROR_BUFFER_TOO_SMALL);
    return streamer_write(streamer_get(), (const char *) sTxBuffer, rval);
exit:
    return rval;
}
#else
static int OnOtCliOutput(const char * aBuf, uint16_t aBufLength, void * aContext)
{
    return streamer_write(streamer_get(), aBuf, aBufLength);
}
#endif
#endif

#endif // CHIP_ENABLE_OPENTHREAD

void cmd_otcli_init()
{
#if CHIP_ENABLE_OPENTHREAD
#if CHIP_TARGET_STYLE_EMBEDDED
#ifdef EFR32_OPENTHREAD_API
    otCliInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
#else
    otCliConsoleInit(otInstanceInitSingle(), &OnOtCliOutput, NULL);
#endif
#endif

    // Register the root otcli command with the top-level shell.
    Engine::Root().RegisterCommands(&cmds_otcli_root, 1);
#endif // CHIP_ENABLE_OPENTHREAD
}
<|endoftext|>


<commit_before>/*
 * ScopeLink.cc
 *
 * Copyright (C) 2009, 2014, 2015 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 <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/TypeNode.h>
#include <opencog/atoms/core/FreeLink.h>
#include <opencog/atoms/core/LambdaLink.h>
#include <opencog/atoms/core/PutLink.h>
#include <opencog/atoms/core/ImplicationLink.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atomutils/TypeUtils.h>

#include "ScopeLink.h"

using namespace opencog;

void ScopeLink::init(void)
{
	extract_variables(_outgoing);
}

ScopeLink::ScopeLink(const HandleSeq& oset,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(SCOPE_LINK, oset, tv, av)
{
	init();
}

ScopeLink::ScopeLink(const Handle& vars, const Handle& body,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(SCOPE_LINK, HandleSeq({vars, body}), tv, av)
{
	init();
}

bool ScopeLink::skip_init(Type t)
{
	// Type must be as expected.
	if (not classserver().isA(t, SCOPE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a ScopeLink, got %s", tname.c_str());
	}

	// Certain derived classes want to have a different initialization
	// sequence. We can't use virtual init() in the ctor, so just
	// do an if-statement here.
	if (IMPLICATION_LINK == t) return true;
	if (PUT_LINK == t) return true;
	if (classserver().isA(t, PATTERN_LINK)) return true;
	return false;
}

ScopeLink::ScopeLink(Type t, const Handle& body,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(t, HandleSeq({body}), tv, av)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(Type t, const HandleSeq& oset,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(t, oset, tv, av)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(Link &l)
	: Link(l)
{
	if (skip_init(l.getType())) return;
	init();
}

/* ================================================================= */
///
/// Find and unpack variable declarations, if any; otherwise, just
/// find all free variables.
///
void ScopeLink::extract_variables(const HandleSeq& oset)
{
	if (oset.size() == 0)
		throw SyntaxException(TRACE_INFO,
			"Expecting a non-empty outgoing set.");

	Type decls = oset.at(0)->getType();

	// If the first atom is not explicitly a variable declaration, then
	// there are no variable declarations. There are two cases that; can
	// apply here: either the body is a lambda, in which case, we copy
	// the variables from the lambda; else we extract all free variables.
	if (VARIABLE_LIST != decls and
	    VARIABLE_NODE != decls and
	    TYPED_VARIABLE_LINK != decls and
	    GLOB_NODE != decls)
	{
		_body = oset[0];

		if (classserver().isA(_body->getType(), LAMBDA_LINK))
		{
			LambdaLinkPtr lam(LambdaLinkCast(_body));
			if (nullptr == lam)
				lam = createLambdaLink(*LinkCast(_body));
			_varlist = lam->get_variables();
			_body = lam->get_body();
		}
		else
		{
			_varlist.find_variables(oset[0]);
		}
		return;
	}

	if (oset.size() < 2)
		throw SyntaxException(TRACE_INFO,
			"Expecting an outgoing set size of at least two; got %s",
			oset[0]->toString().c_str());

	// If we are here, then the first outgoing set member should be
	// a variable declaration.
	_vardecl = oset[0];
	_body = oset[1];

	// Initialize _varlist with the scoped variables
	init_scoped_variables(_vardecl);
}

/* ================================================================= */
///
/// Initialize _varlist given a handle of either VariableList or a
/// variable.
///
void ScopeLink::init_scoped_variables(const Handle& hvar)
{
	// Use the VariableList class as a tool to extract the variables
	// for us.
	VariableList vl(hvar);
	_varlist = vl.get_variables();
}

/* ================================================================= */
///
/// Compare other ScopeLink, return true if it is equal to this one,
/// up to an alpha-conversion of variables.
///
bool ScopeLink::is_equal(const Handle& other, bool silent) const
{
	if (other == this) return true;
	if (other->getType() != _type) return false;

	ScopeLinkPtr scother(ScopeLinkCast(other));
	if (nullptr == scother)
		scother = createScopeLink(*LinkCast(other));

	// In case we're dealing with a class inheriting from ScopeLink,
	// like BindLink, that has more than one scoped term, like
	// implicand, etc, then we need to check the alpha equivalence
	// over all terms. Before that, let's check that they have the
	// same number of terms.
	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity other_vardecl_offset = scother->_vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = getArity() - vardecl_offset;
	Arity other_n_scoped_terms = other->getArity() - other_vardecl_offset;
	if (n_scoped_terms != other_n_scoped_terms) return false;

	// Variable declarations must match.
	if (not _varlist.is_equal(scother->_varlist)) return false;

	// If all of the variable names are identical in this and other,
	// then no alpha conversion needs to be done; we can do a direct
	// comparison.
	if (_varlist.is_identical(scother->_varlist))
	{
		// Compare them, they should match.
		for (Arity i = 0; i < n_scoped_terms; ++i)
		{
			Handle h = getOutgoingAtom(i + vardecl_offset);
			Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
			if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
		}
		return true;
	}

	// If we are here, we need to perform alpha conversion to test
	// equality.  Other terms, with our variables in place of its
	// variables, should be same as our terms.
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		Handle h = getOutgoingAtom(i + vardecl_offset);
		Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
		other_h = scother->_varlist.substitute_nocheck(other_h,
		                                         _varlist.varseq, silent);
		// Compare them, they should match.
		if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
	}

	return true;
}

/* ================================================================= */

/// A specialized hashing function, designed so that all alpha-
/// convertable links get exactly the same hash.  To acheive this
/// the actual variable names have to be excluded from the hash,
/// and a standardized set used instead.
///
ContentHash ScopeLink::compute_hash() const
{
	UnorderedHandleSet hidden;

	// djb hash
	ContentHash hsh = 5381;
	hsh += (hsh <<5) + getType();
	for (const Handle& h: _outgoing)
	{
		hsh += (hsh <<5) + term_hash(h, hidden, 0); // recursive!
	}

	// Links will always have the MSB set.
	ContentHash mask = ((ContentHash) 1UL) << (8*sizeof(ContentHash) - 1);
	hsh |= mask;

	if (Handle::INVALID_HASH == hsh) hsh -= 1;
	_content_hash = hsh;
	return _content_hash;
}

/// Recursive helper for computing the content hash correctly for
/// scoped links.  The algorithm here is almost identical to that
/// used in VarScraper::find_vars(), with obvious alterations.
ContentHash ScopeLink::term_hash(const Handle& h,
                                 UnorderedHandleSet& bound_vars,
                                 int quote_lvl) const
{
	Type t = h->getType();
	if ((VARIABLE_NODE == t or GLOB_NODE == t) and
	    0 == quote_lvl and
	    0 != _varlist.varset.count(h) and
	    0 == bound_vars.count(h))
	{
		// Alpha-convert the variable "name" to its unique position
		// in the sequence of bound vars.  Thus, the name is unique.
		return 11 + _varlist.index.find(h)->second;
	}

	// Just the plain old hash for all other nodes.
	if (h->isNode()) return h->get_hash();

	// quotation
	if (QUOTE_LINK == t) quote_lvl++;
	else if (UNQUOTE_LINK == t) quote_lvl--;

	// Other embedded ScopeLinks might be hiding some of our varialbes...
	bool issco = classserver().isA(t, SCOPE_LINK);
	UnorderedHandleSet bsave;
	if (issco)
	{
		// Prevent current hidden vars from harm.
		bsave = bound_vars;
		// Add the Scope links vars to the hidden set.
		ScopeLinkPtr sco(ScopeLinkCast(h));
		if (nullptr == sco)
			sco = ScopeLink::factory(t, h->getOutgoingSet());
		const Variables& vees = sco->get_variables();
		for (const Handle& v : vees.varseq) bound_vars.insert(v);
	}

	// djb hash
	ContentHash hsh = 5381;
	hsh += (hsh <<5) + t;
	for (const Handle& ho: h->getOutgoingSet())
	{
		hsh += (hsh <<5) + term_hash(ho, bound_vars, quote_lvl); // recursive!
	}

	// Links will always have the MSB set.
	ContentHash mask = ((ContentHash) 1UL) << (8*sizeof(ContentHash) - 1);
	hsh |= mask;

	if (Handle::INVALID_HASH == hsh) hsh -= 1;
	_content_hash = hsh;

	// Restore save vars from stack.
	if (issco) bound_vars = bsave;

	return _content_hash;
}

/* ================================================================= */

inline std::string rand_hex_str()
{
	int rnd_id = randGen().randint();
	std::stringstream ss;
	ss << std::hex << rnd_id;
	return ss.str();
}

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars) {
		std::string new_var_name = h->getName() + "-" + rand_hex_str();
		new_vars.emplace_back(createNode(VARIABLE_NODE, new_var_name));
	}
	return new_vars;
}

Handle ScopeLink::alpha_conversion(HandleSeq vars, Handle vardecl) const
{
	// If hs is empty then generate new variable names
	if (vars.empty())
		vars = append_rand_str(_varlist.varseq);

	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < getArity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars));

	// Replace vardecl by the substituted version if any
	if (vardecl.is_undefined() and _vardecl.is_defined())
		vardecl = hs[0];

	// Remove the optional variable declaration from hs
	if (_vardecl.is_defined())
		hs.erase(hs.begin());

	// Filter vardecl
	vardecl = filter_vardecl(vardecl, hs);

	// Insert vardecl back in hs if defined
	if (vardecl.is_defined())
		hs.insert(hs.begin(), vardecl);

	// Create the alpha converted scope link
	return Handle(factory(getType(), hs));
}

/* ================================================================= */

bool ScopeLink::operator==(const Atom& ac) const
{
	Atom& a = (Atom&) ac; // cast away constness, for smart ptr.
	try {
		return is_equal(a.getHandle(), true);
	} catch (const NestingException& ex) {}
	return false;
}

bool ScopeLink::operator!=(const Atom& a) const
{
	return not operator==(a);
}

/* ================================================================= */

ScopeLinkPtr ScopeLink::factory(const Handle& h)
{
	return factory(h->getType(), h->getOutgoingSet());
}

ScopeLinkPtr ScopeLink::factory(Type t, const HandleSeq& seq)
{
	if (PUT_LINK == t)
		return createPutLink(seq);

	if (LAMBDA_LINK == t)
		return createLambdaLink(seq);

	if (classserver().isA(t, IMPLICATION_LINK))
		return createImplicationLink(t, seq);

	if (classserver().isA(t, PATTERN_LINK))
		return PatternLink::factory(t, seq);

	if (classserver().isA(t, SCOPE_LINK))
		return createScopeLink(t, seq);

	throw SyntaxException(TRACE_INFO,
		"ScopeLink is not a factory for %s",
		classserver().getTypeName(t).c_str());
}

/* ===================== END OF FILE ===================== */
<commit_msg>Remove cut-n-past cruft<commit_after>/*
 * ScopeLink.cc
 *
 * Copyright (C) 2009, 2014, 2015 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 <string>

#include <opencog/util/mt19937ar.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/TypeNode.h>
#include <opencog/atoms/core/FreeLink.h>
#include <opencog/atoms/core/LambdaLink.h>
#include <opencog/atoms/core/PutLink.h>
#include <opencog/atoms/core/ImplicationLink.h>
#include <opencog/atoms/pattern/PatternLink.h>
#include <opencog/atomutils/TypeUtils.h>

#include "ScopeLink.h"

using namespace opencog;

void ScopeLink::init(void)
{
	extract_variables(_outgoing);
}

ScopeLink::ScopeLink(const HandleSeq& oset,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(SCOPE_LINK, oset, tv, av)
{
	init();
}

ScopeLink::ScopeLink(const Handle& vars, const Handle& body,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(SCOPE_LINK, HandleSeq({vars, body}), tv, av)
{
	init();
}

bool ScopeLink::skip_init(Type t)
{
	// Type must be as expected.
	if (not classserver().isA(t, SCOPE_LINK))
	{
		const std::string& tname = classserver().getTypeName(t);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a ScopeLink, got %s", tname.c_str());
	}

	// Certain derived classes want to have a different initialization
	// sequence. We can't use virtual init() in the ctor, so just
	// do an if-statement here.
	if (IMPLICATION_LINK == t) return true;
	if (PUT_LINK == t) return true;
	if (classserver().isA(t, PATTERN_LINK)) return true;
	return false;
}

ScopeLink::ScopeLink(Type t, const Handle& body,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(t, HandleSeq({body}), tv, av)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(Type t, const HandleSeq& oset,
                     TruthValuePtr tv, AttentionValuePtr av)
	: Link(t, oset, tv, av)
{
	if (skip_init(t)) return;
	init();
}

ScopeLink::ScopeLink(Link &l)
	: Link(l)
{
	if (skip_init(l.getType())) return;
	init();
}

/* ================================================================= */
///
/// Find and unpack variable declarations, if any; otherwise, just
/// find all free variables.
///
void ScopeLink::extract_variables(const HandleSeq& oset)
{
	if (oset.size() == 0)
		throw SyntaxException(TRACE_INFO,
			"Expecting a non-empty outgoing set.");

	Type decls = oset.at(0)->getType();

	// If the first atom is not explicitly a variable declaration, then
	// there are no variable declarations. There are two cases that; can
	// apply here: either the body is a lambda, in which case, we copy
	// the variables from the lambda; else we extract all free variables.
	if (VARIABLE_LIST != decls and
	    VARIABLE_NODE != decls and
	    TYPED_VARIABLE_LINK != decls and
	    GLOB_NODE != decls)
	{
		_body = oset[0];

		if (classserver().isA(_body->getType(), LAMBDA_LINK))
		{
			LambdaLinkPtr lam(LambdaLinkCast(_body));
			if (nullptr == lam)
				lam = createLambdaLink(*LinkCast(_body));
			_varlist = lam->get_variables();
			_body = lam->get_body();
		}
		else
		{
			_varlist.find_variables(oset[0]);
		}
		return;
	}

	if (oset.size() < 2)
		throw SyntaxException(TRACE_INFO,
			"Expecting an outgoing set size of at least two; got %s",
			oset[0]->toString().c_str());

	// If we are here, then the first outgoing set member should be
	// a variable declaration.
	_vardecl = oset[0];
	_body = oset[1];

	// Initialize _varlist with the scoped variables
	init_scoped_variables(_vardecl);
}

/* ================================================================= */
///
/// Initialize _varlist given a handle of either VariableList or a
/// variable.
///
void ScopeLink::init_scoped_variables(const Handle& hvar)
{
	// Use the VariableList class as a tool to extract the variables
	// for us.
	VariableList vl(hvar);
	_varlist = vl.get_variables();
}

/* ================================================================= */
///
/// Compare other ScopeLink, return true if it is equal to this one,
/// up to an alpha-conversion of variables.
///
bool ScopeLink::is_equal(const Handle& other, bool silent) const
{
	if (other == this) return true;
	if (other->getType() != _type) return false;

	ScopeLinkPtr scother(ScopeLinkCast(other));
	if (nullptr == scother)
		scother = createScopeLink(*LinkCast(other));

	// In case we're dealing with a class inheriting from ScopeLink,
	// like BindLink, that has more than one scoped term, like
	// implicand, etc, then we need to check the alpha equivalence
	// over all terms. Before that, let's check that they have the
	// same number of terms.
	Arity vardecl_offset = _vardecl != Handle::UNDEFINED;
	Arity other_vardecl_offset = scother->_vardecl != Handle::UNDEFINED;
	Arity n_scoped_terms = getArity() - vardecl_offset;
	Arity other_n_scoped_terms = other->getArity() - other_vardecl_offset;
	if (n_scoped_terms != other_n_scoped_terms) return false;

	// Variable declarations must match.
	if (not _varlist.is_equal(scother->_varlist)) return false;

	// If all of the variable names are identical in this and other,
	// then no alpha conversion needs to be done; we can do a direct
	// comparison.
	if (_varlist.is_identical(scother->_varlist))
	{
		// Compare them, they should match.
		for (Arity i = 0; i < n_scoped_terms; ++i)
		{
			Handle h = getOutgoingAtom(i + vardecl_offset);
			Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
			if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
		}
		return true;
	}

	// If we are here, we need to perform alpha conversion to test
	// equality.  Other terms, with our variables in place of its
	// variables, should be same as our terms.
	for (Arity i = 0; i < n_scoped_terms; ++i)
	{
		Handle h = getOutgoingAtom(i + vardecl_offset);
		Handle other_h = other->getOutgoingAtom(i + other_vardecl_offset);
		other_h = scother->_varlist.substitute_nocheck(other_h,
		                                         _varlist.varseq, silent);
		// Compare them, they should match.
		if (*((AtomPtr)h) != *((AtomPtr) other_h)) return false;
	}

	return true;
}

/* ================================================================= */

/// A specialized hashing function, designed so that all alpha-
/// convertable links get exactly the same hash.  To acheive this
/// the actual variable names have to be excluded from the hash,
/// and a standardized set used instead.
///
ContentHash ScopeLink::compute_hash() const
{
	UnorderedHandleSet hidden;

	// djb hash
	ContentHash hsh = 5381;
	hsh += (hsh <<5) + getType();
	for (const Handle& h: _outgoing)
	{
		hsh += (hsh <<5) + term_hash(h, hidden, 0); // recursive!
	}

	// Links will always have the MSB set.
	ContentHash mask = ((ContentHash) 1UL) << (8*sizeof(ContentHash) - 1);
	hsh |= mask;

	if (Handle::INVALID_HASH == hsh) hsh -= 1;
	_content_hash = hsh;
	return _content_hash;
}

/// Recursive helper for computing the content hash correctly for
/// scoped links.  The algorithm here is almost identical to that
/// used in VarScraper::find_vars(), with obvious alterations.
ContentHash ScopeLink::term_hash(const Handle& h,
                                 UnorderedHandleSet& bound_vars,
                                 int quote_lvl) const
{
	Type t = h->getType();
	if ((VARIABLE_NODE == t or GLOB_NODE == t) and
	    0 == quote_lvl and
	    0 != _varlist.varset.count(h) and
	    0 == bound_vars.count(h))
	{
		// Alpha-convert the variable "name" to its unique position
		// in the sequence of bound vars.  Thus, the name is unique.
		return 11 + _varlist.index.find(h)->second;
	}

	// Just the plain old hash for all other nodes.
	if (h->isNode()) return h->get_hash();

	// quotation
	if (QUOTE_LINK == t) quote_lvl++;
	else if (UNQUOTE_LINK == t) quote_lvl--;

	// Other embedded ScopeLinks might be hiding some of our varialbes...
	bool issco = classserver().isA(t, SCOPE_LINK);
	UnorderedHandleSet bsave;
	if (issco)
	{
		// Prevent current hidden vars from harm.
		bsave = bound_vars;
		// Add the Scope links vars to the hidden set.
		ScopeLinkPtr sco(ScopeLinkCast(h));
		if (nullptr == sco)
			sco = ScopeLink::factory(t, h->getOutgoingSet());
		const Variables& vees = sco->get_variables();
		for (const Handle& v : vees.varseq) bound_vars.insert(v);
	}

	// djb hash
	ContentHash hsh = 5381;
	hsh += (hsh <<5) + t;
	for (const Handle& ho: h->getOutgoingSet())
	{
		hsh += (hsh <<5) + term_hash(ho, bound_vars, quote_lvl); // recursive!
	}

	// Restore saved vars from stack.
	if (issco) bound_vars = bsave;

	return hsh;
}

/* ================================================================= */

inline std::string rand_hex_str()
{
	int rnd_id = randGen().randint();
	std::stringstream ss;
	ss << std::hex << rnd_id;
	return ss.str();
}

inline HandleSeq append_rand_str(const HandleSeq& vars)
{
	HandleSeq new_vars;
	for (const Handle& h : vars) {
		std::string new_var_name = h->getName() + "-" + rand_hex_str();
		new_vars.emplace_back(createNode(VARIABLE_NODE, new_var_name));
	}
	return new_vars;
}

Handle ScopeLink::alpha_conversion(HandleSeq vars, Handle vardecl) const
{
	// If hs is empty then generate new variable names
	if (vars.empty())
		vars = append_rand_str(_varlist.varseq);

	// Perform alpha conversion
	HandleSeq hs;
	for (size_t i = 0; i < getArity(); ++i)
		hs.push_back(_varlist.substitute_nocheck(getOutgoingAtom(i), vars));

	// Replace vardecl by the substituted version if any
	if (vardecl.is_undefined() and _vardecl.is_defined())
		vardecl = hs[0];

	// Remove the optional variable declaration from hs
	if (_vardecl.is_defined())
		hs.erase(hs.begin());

	// Filter vardecl
	vardecl = filter_vardecl(vardecl, hs);

	// Insert vardecl back in hs if defined
	if (vardecl.is_defined())
		hs.insert(hs.begin(), vardecl);

	// Create the alpha converted scope link
	return Handle(factory(getType(), hs));
}

/* ================================================================= */

bool ScopeLink::operator==(const Atom& ac) const
{
	Atom& a = (Atom&) ac; // cast away constness, for smart ptr.
	try {
		return is_equal(a.getHandle(), true);
	} catch (const NestingException& ex) {}
	return false;
}

bool ScopeLink::operator!=(const Atom& a) const
{
	return not operator==(a);
}

/* ================================================================= */

ScopeLinkPtr ScopeLink::factory(const Handle& h)
{
	return factory(h->getType(), h->getOutgoingSet());
}

ScopeLinkPtr ScopeLink::factory(Type t, const HandleSeq& seq)
{
	if (PUT_LINK == t)
		return createPutLink(seq);

	if (LAMBDA_LINK == t)
		return createLambdaLink(seq);

	if (classserver().isA(t, IMPLICATION_LINK))
		return createImplicationLink(t, seq);

	if (classserver().isA(t, PATTERN_LINK))
		return PatternLink::factory(t, seq);

	if (classserver().isA(t, SCOPE_LINK))
		return createScopeLink(t, seq);

	throw SyntaxException(TRACE_INFO,
		"ScopeLink is not a factory for %s",
		classserver().getTypeName(t).c_str());
}

/* ===================== END OF FILE ===================== */
<|endoftext|>


<commit_before>#ifndef __STOUT_OS_SYSCTL_HPP__
#define __STOUT_OS_SYSCTL_HPP__

// Only provide sysctl support for OS X.
#ifndef __APPLE__
#error "stout/os/sysctl.hpp is only available on OS X."
#endif

#include <string>
#include <vector>

#include <sys/types.h>
#include <sys/sysctl.h>

#include <stout/error.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

namespace os {

// Provides an abstraction for getting system information via the
// underlying 'sysctl' system call. You describe the sysctl
// "Management Information Base" (MIB) name via the constructor, for
// example, to describe "maximum number of processes allowed in the
// system" you would do:
//
//   os::sysctl(CTL_KERN, KERN_MAXPROC)
//
// To _retrieve_ the value you need to use one of the 'integer',
// 'string', or 'table' methods to indicate the type of the value
// being retrieved. For example:
//
//   Try<int> maxproc = os::sysctl(CTL_KERN, KERN_MAXPROC).integer();
//
// Note that the 'table' method requires specifying a length. If you
// would like the length to be looked up dynamically you can just pass
// None. Here's an example using 'table' that builds on above:
//
//   Try<vector<kinfo_proc> > processes =
//     os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(maxprox.get());
//
// TODO(benh): Provide an 'integer(i)', 'string(s)', and 'table(t)' to
// enable setting system information.
struct sysctl
{
  // Note that we create a constructor for each number of levels
  // because we can't pick a suitable default for unused levels (in
  // order to distinguish no value from some value) and while Option
  // would solve that it could also cause people to use None which
  // we'd need to later handle as an error.
  explicit sysctl(int level1);
  sysctl(int level1, int level2);
  sysctl(int level1, int level2, int level3);
  sysctl(int level1, int level2, int level3, int level4);
  sysctl(int level1, int level2, int level3, int level4, int level5);
  ~sysctl();

  // Get system information as an integer.
private: struct Integer; // Forward declaration.
public:
  Integer integer() const;

  // Get system information as a string.
  Try<std::string> string() const;

  // Get system information as a table, optionally specifying a
  // length. Note that this function is lazy and will not actually
  // perform the syscall until you cast (implicitely or explicitly) a
  // 'Table' to a std::vector<T>. For example, to get the first 10
  // processes in the process table you can do:
  //
  //     Try<std::vector<kinfo_proc> > processes =
  //       os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(10);
  //
private: struct Table; // Forward declaration.
public:
  Table table(const Option<size_t>& length = None()) const;

private:
  struct Integer
  {
    Integer(int _levels, int* _name);

    template <typename T>
    operator Try<T> ();

    const int levels;
    int* name;
  };

  struct Table
  {
    Table(int _levels, int* _name, const Option<size_t>& _length);

    template <typename T>
    operator Try<std::vector<T> > ();

    const int levels;
    int* name;
    Option<size_t> length;
  };

  const int levels;
  int* name;
};

inline sysctl::sysctl(int level1)
  : levels(1), name(new int[levels])
{
  name[0] = level1;
}

inline sysctl::sysctl(int level1, int level2)
  : levels(2), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
}

inline sysctl::sysctl(int level1, int level2, int level3)
  : levels(3), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
}

inline sysctl::sysctl(int level1, int level2, int level3, int level4)
  : levels(4), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
  name[3] = level4;
}

inline sysctl::sysctl(int level1, int level2, int level3, int level4, int level5)
  : levels(5), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
  name[3] = level4;
  name[4] = level5;
}

inline sysctl::~sysctl()
{
  delete[] name;
}

inline sysctl::Integer sysctl::integer() const
{
  return Integer(levels, name);
}

inline Try<std::string> sysctl::string() const
{
  // First determine the size of the string.
  size_t size = 0;
  if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
    return ErrnoError();
  }

  // Now read it.
  size_t length = size / sizeof(char);
  char* temp = new char[length];
  if (::sysctl(name, levels, temp, &size, NULL, 0) == -1) {
    Error error = ErrnoError();
    delete[] temp;
    return error;
  }

  // TODO(benh): It's possible that the value has changed since we
  // determined it's length above. We should really check that we
  // get back the same length and if not throw an error.

  std::string result(temp);
  delete[] temp;
  return result;
}

inline sysctl::Table sysctl::table(const Option<size_t>& length) const
{
  return Table(levels, name, length);
}

inline sysctl::Integer::Integer(
    int _levels,
    int* _name)
  : levels(_levels),
    name(_name)
{}

template <typename T>
sysctl::Integer::operator Try<T> ()
{
  T i;
  size_t size = sizeof(i);
  if (::sysctl(name, levels, &i, &size, NULL, 0) == -1) {
    return ErrnoError();
  }
  return i;
}

inline sysctl::Table::Table(
    int _levels,
    int* _name,
    const Option<size_t>& _length)
  : levels(_levels),
    name(_name),
    length(_length)
{}

template <typename T>
sysctl::Table::operator Try<std::vector<T> > ()
{
  size_t size = 0;
  if (length.isNone()) {
    if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
      return ErrnoError();
    }
    if (size % sizeof(T) != 0) {
      return Error("Failed to determine the length of result, "
                   "amount of available data is not a multiple "
                   "of the table type");
    }
    length = Option<size_t>(size / sizeof(T));
  }

  T* ts = new T[length.get()];
  size = length.get() * sizeof(T);
  if (::sysctl(name, levels, ts, &size, NULL, 0) == -1) {
    Error error = ErrnoError();
    delete[] ts;
    return error;
  }

  // TODO(benh): It's possible that the value has changed since we
  // determined it's length above (or from what was specified). We
  // should really check that we get back the same length and if not
  // throw an error.

  length = size / sizeof(T);

  std::vector<T> results;
  for (size_t i = 0; i < length.get(); i++) {
    results.push_back(ts[i]);
  }
  delete[] ts;
  return results;
}

} // namespace os {

#endif // __STOUT_OS_SYSCTL_HPP__
<commit_msg>Fixed os::sysctl::string to return results with null bytes.<commit_after>#ifndef __STOUT_OS_SYSCTL_HPP__
#define __STOUT_OS_SYSCTL_HPP__

// Only provide sysctl support for OS X.
#ifndef __APPLE__
#error "stout/os/sysctl.hpp is only available on OS X."
#endif

#include <string>
#include <vector>

#include <sys/types.h>
#include <sys/sysctl.h>

#include <stout/error.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

namespace os {

// Provides an abstraction for getting system information via the
// underlying 'sysctl' system call. You describe the sysctl
// "Management Information Base" (MIB) name via the constructor, for
// example, to describe "maximum number of processes allowed in the
// system" you would do:
//
//   os::sysctl(CTL_KERN, KERN_MAXPROC)
//
// To _retrieve_ the value you need to use one of the 'integer',
// 'string', or 'table' methods to indicate the type of the value
// being retrieved. For example:
//
//   Try<int> maxproc = os::sysctl(CTL_KERN, KERN_MAXPROC).integer();
//
// Note that the 'table' method requires specifying a length. If you
// would like the length to be looked up dynamically you can just pass
// None. Here's an example using 'table' that builds on above:
//
//   Try<vector<kinfo_proc> > processes =
//     os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(maxprox.get());
//
// TODO(benh): Provide an 'integer(i)', 'string(s)', and 'table(t)' to
// enable setting system information.
struct sysctl
{
  // Note that we create a constructor for each number of levels
  // because we can't pick a suitable default for unused levels (in
  // order to distinguish no value from some value) and while Option
  // would solve that it could also cause people to use None which
  // we'd need to later handle as an error.
  explicit sysctl(int level1);
  sysctl(int level1, int level2);
  sysctl(int level1, int level2, int level3);
  sysctl(int level1, int level2, int level3, int level4);
  sysctl(int level1, int level2, int level3, int level4, int level5);
  ~sysctl();

  // Get system information as an integer.
private: struct Integer; // Forward declaration.
public:
  Integer integer() const;

  // Get system information as a string.
  Try<std::string> string() const;

  // Get system information as a table, optionally specifying a
  // length. Note that this function is lazy and will not actually
  // perform the syscall until you cast (implicitely or explicitly) a
  // 'Table' to a std::vector<T>. For example, to get the first 10
  // processes in the process table you can do:
  //
  //     Try<std::vector<kinfo_proc> > processes =
  //       os::sysctl(CTL_KERN, KERN_PROC, KERN_PROC_ALL).table(10);
  //
private: struct Table; // Forward declaration.
public:
  Table table(const Option<size_t>& length = None()) const;

private:
  struct Integer
  {
    Integer(int _levels, int* _name);

    template <typename T>
    operator Try<T> ();

    const int levels;
    int* name;
  };

  struct Table
  {
    Table(int _levels, int* _name, const Option<size_t>& _length);

    template <typename T>
    operator Try<std::vector<T> > ();

    const int levels;
    int* name;
    Option<size_t> length;
  };

  const int levels;
  int* name;
};

inline sysctl::sysctl(int level1)
  : levels(1), name(new int[levels])
{
  name[0] = level1;
}

inline sysctl::sysctl(int level1, int level2)
  : levels(2), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
}

inline sysctl::sysctl(int level1, int level2, int level3)
  : levels(3), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
}

inline sysctl::sysctl(int level1, int level2, int level3, int level4)
  : levels(4), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
  name[3] = level4;
}

inline sysctl::sysctl(int level1, int level2, int level3, int level4, int level5)
  : levels(5), name(new int[levels])
{
  name[0] = level1;
  name[1] = level2;
  name[2] = level3;
  name[3] = level4;
  name[4] = level5;
}

inline sysctl::~sysctl()
{
  delete[] name;
}

inline sysctl::Integer sysctl::integer() const
{
  return Integer(levels, name);
}

inline Try<std::string> sysctl::string() const
{
  // First determine the size of the string.
  size_t size = 0;
  if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
    return ErrnoError();
  }

  // Now read it.
  size_t length = size / sizeof(char);
  char* temp = new char[length];
  if (::sysctl(name, levels, temp, &size, NULL, 0) == -1) {
    Error error = ErrnoError();
    delete[] temp;
    return error;
  }

  // TODO(benh): It's possible that the value has changed since we
  // determined it's length above. We should really check that we
  // get back the same length and if not throw an error.

  // The "string" in 'temp' might include null bytes, so to get all of
  // the data we need to create a string with 'size' (but we exclude
  // the last null byte via 'size - 1').
  std::string result(temp, size - 1);
  delete[] temp;
  return result;
}

inline sysctl::Table sysctl::table(const Option<size_t>& length) const
{
  return Table(levels, name, length);
}

inline sysctl::Integer::Integer(
    int _levels,
    int* _name)
  : levels(_levels),
    name(_name)
{}

template <typename T>
sysctl::Integer::operator Try<T> ()
{
  T i;
  size_t size = sizeof(i);
  if (::sysctl(name, levels, &i, &size, NULL, 0) == -1) {
    return ErrnoError();
  }
  return i;
}

inline sysctl::Table::Table(
    int _levels,
    int* _name,
    const Option<size_t>& _length)
  : levels(_levels),
    name(_name),
    length(_length)
{}

template <typename T>
sysctl::Table::operator Try<std::vector<T> > ()
{
  size_t size = 0;
  if (length.isNone()) {
    if (::sysctl(name, levels, NULL, &size, NULL, 0) == -1) {
      return ErrnoError();
    }
    if (size % sizeof(T) != 0) {
      return Error("Failed to determine the length of result, "
                   "amount of available data is not a multiple "
                   "of the table type");
    }
    length = Option<size_t>(size / sizeof(T));
  }

  T* ts = new T[length.get()];
  size = length.get() * sizeof(T);
  if (::sysctl(name, levels, ts, &size, NULL, 0) == -1) {
    Error error = ErrnoError();
    delete[] ts;
    return error;
  }

  // TODO(benh): It's possible that the value has changed since we
  // determined it's length above (or from what was specified). We
  // should really check that we get back the same length and if not
  // throw an error.

  length = size / sizeof(T);

  std::vector<T> results;
  for (size_t i = 0; i < length.get(); i++) {
    results.push_back(ts[i]);
  }
  delete[] ts;
  return results;
}

} // namespace os {

#endif // __STOUT_OS_SYSCTL_HPP__
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace {

const int kLongWaitMs = 100 * 1000; // A long time in testing terms
const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen

// A Baton is one possible control structure one can build using
// conditional variables.
// A Baton is always held by one and only one active thread - unlike
// a lock, it can never be free.
// One can pass it or grab it - both calls have timeouts.
// Note - a production tool would guard against passing it without
// grabbing it first. This one is for testing, so it doesn't.
class Baton {
 public:
  Baton()
    : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
      being_passed_(false),
      pass_count_(0) {
  }

  ~Baton() {
    delete giver_sect_;
    delete crit_sect_;
    delete cond_var_;
  }

  // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
  // Only one process can pass at the same time; this property is
  // ensured by the |giver_sect_| lock.
  bool Pass(uint32_t max_msecs) {
    CriticalSectionScoped cs_giver(giver_sect_);
    CriticalSectionScoped cs(crit_sect_);
    SignalBatonAvailable();
    const bool result = TakeBatonIfStillFree(max_msecs);
    if (result) {
      ++pass_count_;
    }
    return result;
  }

  // Grab the baton. Returns false if baton is not passed.
  bool Grab(uint32_t max_msecs) {
    CriticalSectionScoped cs(crit_sect_);
    return WaitUntilBatonOffered(max_msecs);
  }

  int PassCount() {
    // We don't allow polling PassCount() during a Pass()-call since there is
    // no guarantee that |pass_count_| is incremented until the Pass()-call
    // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
    // incremented.
    // Thus, this function waits on giver_sect_.
    CriticalSectionScoped cs(giver_sect_);
    return pass_count_;
  }

 private:
  // Wait/Signal forms a classical semaphore on |being_passed_|.
  // These functions must be called with crit_sect_ held.
  bool WaitUntilBatonOffered(int timeout_ms) {
    while (!being_passed_) {
      if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
        return false;
      }
    }
    being_passed_ = false;
    cond_var_->Wake();
    return true;
  }

  void SignalBatonAvailable() {
    assert(!being_passed_);
    being_passed_ = true;
    cond_var_->Wake();
  }

  // Timeout extension: Wait for a limited time for someone else to
  // take it, and take it if it's not taken.
  // Returns true if resource is taken by someone else, false
  // if it is taken back by the caller.
  // This function must be called with both |giver_sect_| and
  // |crit_sect_| held.
  bool TakeBatonIfStillFree(int timeout_ms) {
    bool not_timeout = true;
    while (being_passed_ && not_timeout) {
      not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
      // If we're woken up while variable is still held, we may have
      // gotten a wakeup destined for a grabber thread.
      // This situation is not treated specially here.
    }
    if (!being_passed_) {
      return true;
    } else {
      assert(!not_timeout);
      being_passed_ = false;
      return false;
    }
  }

  // Lock that ensures that there is only one thread in the active
  // part of Pass() at a time.
  // |giver_sect_| must always be acquired before |cond_var_|.
  CriticalSectionWrapper* giver_sect_;
  // Lock that protects |being_passed_|.
  CriticalSectionWrapper* crit_sect_;
  ConditionVariableWrapper* cond_var_;
  bool being_passed_;
  // Statistics information: Number of successfull passes.
  int pass_count_;
};

// Function that waits on a Baton, and passes it right back.
// We expect these calls never to time out.
bool WaitingRunFunction(void* obj) {
  Baton* the_baton = static_cast<Baton*> (obj);
  EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
  EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
  return true;
}

class CondVarTest : public ::testing::Test {
 public:
  CondVarTest() {}

  virtual void SetUp() {
    thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
                                          &baton_);
    unsigned int id = 42;
    ASSERT_TRUE(thread_->Start(id));
  }

  virtual void TearDown() {
    // We have to wake the thread in order to make it obey the stop order.
    // But we don't know if the thread has completed the run function, so
    // we don't know if it will exit before or after the Pass.
    // Thus, we need to pin it down inside its Run function (between Grab
    // and Pass).
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
    ASSERT_TRUE(thread_->Stop());
    delete thread_;
  }

 protected:
  Baton baton_;

 private:
  ThreadWrapper* thread_;
};

// The SetUp and TearDown functions use condition variables.
// This test verifies those pieces in isolation.
TEST_F(CondVarTest, InitFunctionsWork) {
  // All relevant asserts are in the SetUp and TearDown functions.
}

// This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
  const int kNumberOfRounds = 2;
  for (int i = 0; i < kNumberOfRounds; ++i) {
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
  }
  EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
}

}  // anonymous namespace

}  // namespace webrtc
<commit_msg>Disable CondVarTest.InitFunctionsWork. The order of Sleep/Wake calls doesn't seem to be guaranteed, so this test is flaky.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace {

const int kLongWaitMs = 100 * 1000; // A long time in testing terms
const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen

// A Baton is one possible control structure one can build using
// conditional variables.
// A Baton is always held by one and only one active thread - unlike
// a lock, it can never be free.
// One can pass it or grab it - both calls have timeouts.
// Note - a production tool would guard against passing it without
// grabbing it first. This one is for testing, so it doesn't.
class Baton {
 public:
  Baton()
    : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
      being_passed_(false),
      pass_count_(0) {
  }

  ~Baton() {
    delete giver_sect_;
    delete crit_sect_;
    delete cond_var_;
  }

  // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
  // Only one process can pass at the same time; this property is
  // ensured by the |giver_sect_| lock.
  bool Pass(uint32_t max_msecs) {
    CriticalSectionScoped cs_giver(giver_sect_);
    CriticalSectionScoped cs(crit_sect_);
    SignalBatonAvailable();
    const bool result = TakeBatonIfStillFree(max_msecs);
    if (result) {
      ++pass_count_;
    }
    return result;
  }

  // Grab the baton. Returns false if baton is not passed.
  bool Grab(uint32_t max_msecs) {
    CriticalSectionScoped cs(crit_sect_);
    return WaitUntilBatonOffered(max_msecs);
  }

  int PassCount() {
    // We don't allow polling PassCount() during a Pass()-call since there is
    // no guarantee that |pass_count_| is incremented until the Pass()-call
    // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
    // incremented.
    // Thus, this function waits on giver_sect_.
    CriticalSectionScoped cs(giver_sect_);
    return pass_count_;
  }

 private:
  // Wait/Signal forms a classical semaphore on |being_passed_|.
  // These functions must be called with crit_sect_ held.
  bool WaitUntilBatonOffered(int timeout_ms) {
    while (!being_passed_) {
      if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
        return false;
      }
    }
    being_passed_ = false;
    cond_var_->Wake();
    return true;
  }

  void SignalBatonAvailable() {
    assert(!being_passed_);
    being_passed_ = true;
    cond_var_->Wake();
  }

  // Timeout extension: Wait for a limited time for someone else to
  // take it, and take it if it's not taken.
  // Returns true if resource is taken by someone else, false
  // if it is taken back by the caller.
  // This function must be called with both |giver_sect_| and
  // |crit_sect_| held.
  bool TakeBatonIfStillFree(int timeout_ms) {
    bool not_timeout = true;
    while (being_passed_ && not_timeout) {
      not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
      // If we're woken up while variable is still held, we may have
      // gotten a wakeup destined for a grabber thread.
      // This situation is not treated specially here.
    }
    if (!being_passed_) {
      return true;
    } else {
      assert(!not_timeout);
      being_passed_ = false;
      return false;
    }
  }

  // Lock that ensures that there is only one thread in the active
  // part of Pass() at a time.
  // |giver_sect_| must always be acquired before |cond_var_|.
  CriticalSectionWrapper* giver_sect_;
  // Lock that protects |being_passed_|.
  CriticalSectionWrapper* crit_sect_;
  ConditionVariableWrapper* cond_var_;
  bool being_passed_;
  // Statistics information: Number of successfull passes.
  int pass_count_;
};

// Function that waits on a Baton, and passes it right back.
// We expect these calls never to time out.
bool WaitingRunFunction(void* obj) {
  Baton* the_baton = static_cast<Baton*> (obj);
  EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
  EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
  return true;
}

class CondVarTest : public ::testing::Test {
 public:
  CondVarTest() {}

  virtual void SetUp() {
    thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
                                          &baton_);
    unsigned int id = 42;
    ASSERT_TRUE(thread_->Start(id));
  }

  virtual void TearDown() {
    // We have to wake the thread in order to make it obey the stop order.
    // But we don't know if the thread has completed the run function, so
    // we don't know if it will exit before or after the Pass.
    // Thus, we need to pin it down inside its Run function (between Grab
    // and Pass).
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
    ASSERT_TRUE(thread_->Stop());
    delete thread_;
  }

 protected:
  Baton baton_;

 private:
  ThreadWrapper* thread_;
};

// The SetUp and TearDown functions use condition variables.
// This test verifies those pieces in isolation.
// Disabled due to flakiness.  See bug 4262 for details.
TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
  // All relevant asserts are in the SetUp and TearDown functions.
}

// This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
  const int kNumberOfRounds = 2;
  for (int i = 0; i < kNumberOfRounds; ++i) {
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
  }
  EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
}

}  // anonymous namespace

}  // namespace webrtc
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>
#include <png.h>
#include <zlib.h>
#include <jpeglib.h>
#include <vector>
#include "screenshot.h"
using namespace std;

// main() is where program execution begins.

int main() {
    Display *display;
    Window root;
    int width = 0;
    int height = 0;
    XWindowAttributes gwa;

    display = XOpenDisplay(NULL);
    if (display == NULL) {
        cout << "No display can be aquired" << endl;
        return (1);
    }
    root = DefaultRootWindow(display);

    XGetWindowAttributes(display, root, &gwa);
    width = gwa.width;
    height = gwa.height;
    cout << "Width: " <<  width << "; Height: " << height << endl;
    XImage *image = XGetImage(
        display,
        root,
        0,
        0,
        width,
        height,
        AllPlanes,
        ZPixmap
    );

    X11Screenshot screenshot = X11Screenshot(image);
    if (screenshot.save_to_jpeg("test.jpg", 30))
        cout << "saved jpeg" << endl;
    if (screenshot.save_to_png("test.png"))
        cout << "saved png" << endl;
    XDestroyImage(image);
    XCloseDisplay(display);
    return 0;
}
<commit_msg>Add thumbnail example<commit_after>#include <iostream>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>
#include <png.h>
#include <zlib.h>
#include <jpeglib.h>
#include <vector>
#include "screenshot.h"
using namespace std;

// main() is where program execution begins.

int main() {
    Display *display;
    Window root;
    int width = 0;
    int height = 0;
    XWindowAttributes gwa;

    display = XOpenDisplay(NULL);
    if (display == NULL) {
        cout << "No display can be aquired" << endl;
        return (1);
    }
    root = DefaultRootWindow(display);

    XGetWindowAttributes(display, root, &gwa);
    width = gwa.width;
    height = gwa.height;
    cout << "Width: " <<  width << "; Height: " << height << endl;
    XImage *image = XGetImage(
        display,
        root,
        0,
        0,
        width,
        height,
        AllPlanes,
        ZPixmap
    );

    X11Screenshot screenshot = X11Screenshot(image);
    cout << "x11 init" << endl;
    if (screenshot.save_to_jpeg("test.jpg", 30))
        cout << "saved jpeg" << endl;
    if (screenshot.save_to_png("test.png"))
        cout << "saved png" << endl;
    X11Screenshot thumbnail = X11Screenshot(image, 1920, 540);
    if (thumbnail.save_to_jpeg("thumb_test.jpg", 30))
        cout << "saved thumbnail jpeg" << endl;
    if (thumbnail.save_to_png("thumb_test.png"))
        cout << "saved thumbnail png" << endl;
    XDestroyImage(image);
    XCloseDisplay(display);
    return 0;
}
<|endoftext|>