<commit_before>/*
 * Instantiator.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 <opencog/atoms/core/DefineLink.h>
#include <opencog/atoms/core/FunctionLink.h>
#include <opencog/atoms/core/PutLink.h>
#include <opencog/atoms/execution/ExecutionOutputLink.h>
#include <opencog/atoms/reduct/FoldLink.h>
#include <opencog/query/BindLinkAPI.h>

#include "Instantiator.h"

using namespace opencog;

HandleSeq Instantiator::walk_tree(const HandleSeq& expr)
{
	HandleSeq oset_results;
	for (const Handle& h : expr)
	{
		Handle hg(walk_tree(h));
		// It could be a NULL handle if it's deleted... Just skip
		// over it. We test the pointer here, not the uuid, since
		// the uuid's are all Handle::UNDEFINED until we put them
		// into the atomspace.
		if (NULL != hg)
			oset_results.emplace_back(hg);
	}
	return oset_results;
}

Handle Instantiator::walk_tree(const Handle& expr)
{
	Type t = expr->getType();

	// Must not explore the insides of a QuoteLink.
	// XXX TODO: Need to implement UNQUOTE_LINK here...
	if (QUOTE_LINK == t)
		return Handle(expr);

	LinkPtr lexpr(LinkCast(expr));
	if (not lexpr)
	{
		// If we are here, we are a Node.
		if (DEFINED_SCHEMA_NODE == t)
		{
			return walk_tree(DefineLink::get_definition(expr));
		}

		if (VARIABLE_NODE != t)
			return Handle(expr);

		// If we are here, we found a variable. Look it up. Return a
		// grounding if it has one, otherwise return the variable
		// itself.
		std::map<Handle,Handle>::const_iterator it = _vmap->find(expr);
		if (_vmap->end() == it) return Handle(expr);

		// Not so fast, pardner. VariableNodes can be grounded by
		// links, and those links may be executable. In that case,
		// we have to execute them.

		// halt infinite regress
		if (_halt)
			return Handle(expr);

		_halt = true;
		Handle hgnd(walk_tree(it->second));
		_halt = false;
		return hgnd;
	}

	// -----------------------------------------------------------
	// If we are here, then we have a link. Walk it. In general,
	// links may contain both bound variables, and also free variables.
	// We must be careful to substitute only for free variables, and
	// never for bound ones.
	//
	// Reduce PutLinks.
	if (PUT_LINK == t)
	{
		PutLinkPtr ppp(PutLinkCast(expr));

		// PutLinks always have arity two. There may be free vars in
		// the body of the PutLink, but we won't substitue for them until
		// after the beta-reduction.  Do substitute the free vars that
		// occur in the argument, and do that before beta-reduction.
		// Execute the body only after the beta-reduction has been done.
		const HandleSeq& oset = lexpr->getOutgoingSet();
		Handle gargs = walk_tree(oset[1]);
		if (gargs != oset[1])
		{
			HandleSeq groset;
			groset.emplace_back(oset[0]);
			groset.emplace_back(gargs);
			ppp = createPutLink(groset);
		}
		// Step one: beta-reduce.
		Handle red = ppp->reduce();
		// Step two: execute the resulting body.
		return walk_tree(red);
	}

	// ExecutionOutputLinks are not handled by the FunctionLink factory
	// below. This is due to a circular shared-libarary dependency.
	if (EXECUTION_OUTPUT_LINK == t)
	{
		// At this time, the GSN or the DSN is always in position 0
		// of the outgoing set, and the ListLink of arguments is always
		// in position 1.  Someday in the future, there may be a variable
		// declaration; we punt on that.
		Handle sn(lexpr->getOutgoingAtom(0));
		Handle args(lexpr->getOutgoingAtom(1));

		// Perform substitution on the args, only.
		args = walk_tree(args);

		// If its a DSN, obtain the correct body for it.
		if (DEFINED_SCHEMA_NODE == sn->getType())
			sn = DefineLink::get_definition(sn);

		// If its a function link, execute it here.
		if (FUNCTION_LINK == sn->getType())
		{
			FunctionLinkPtr flp(FunctionLinkCast(sn));
			if (NULL == flp)
				flp = createFunctionLink(*LinkCast(sn));

			// Two-step process. First, plug the arguments into the
			// function; i.e. perform beta-reduction. Second, actually
			// execute the result. We execute by just calling walk_tree
			// again.
			Handle body(flp->get_body());
			Variables vars(flp->get_variables());

			const HandleSeq& oset(LinkCast(args)->getOutgoingSet());
			Handle beta_reduced(vars.substitute(body, oset));
			return walk_tree(beta_reduced);
		}

		ExecutionOutputLinkPtr eolp(createExecutionOutputLink(sn, args));
		return eolp->execute(_as);
	}

	// FoldLink's cannot be handled by the factory below, due to
	// ciruclar shared library dependencies. Yuck. Something better
	// than a factory needs to be invented.
	if (classserver().isA(t, FOLD_LINK))
	{
		// At this time, no FoldLink ever has a variable declaration,
		// and the number of arguments is not fixed, i.e. variadic.
		// Perform substitution on all arguments before applying the
		// function itself.
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		Handle hl(FoldLink::factory(t, oset_results));
		FoldLinkPtr flp(FoldLinkCast(hl));
		return flp->execute(_as);
	}

	// Handle DeleteLink's before general FunctionLink's; they
	// work differently.
	if (DELETE_LINK == t)
	{
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		for (const Handle& h: oset_results)
			if (VARIABLE_NODE != h->getType())
				_as->remove_atom(h, true);

		return Handle::UNDEFINED;
	}

	// Fire any other function links, not handled above.
	if (classserver().isA(t, FUNCTION_LINK))
	{
		// At this time, no FunctionLink that is outsode of an
		// ExecutionOutputLink ever has a variable declaration.
		// Also, the number of arguments is not fixed, i.e. variadic.
		// Perform substitution on all arguments before applying the
		// function itself.
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		Handle hl(FunctionLink::factory(t, oset_results));
		FunctionLinkPtr flp(FunctionLinkCast(hl));
		return flp->execute(_as);
	}

	// If there is a GetLink, we have to perform the get, and replace
	// it with the results of the get. The get is implemented with the
	// PatternLink::satisfy() method.
	if (GET_LINK == t)
	{
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		size_t sz = oset_results.size();
		for (size_t i=0; i< sz; i++)
			oset_results[i] = _as->add_atom(oset_results[i]);

		LinkPtr lp = createLink(GET_LINK, oset_results);

		return satisfying_set(_as, Handle(lp));
	}

	// None of the above. Create a duplicate link, but with an outgoing
	// set where the variables have been substituted by their values.
	HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
	return Handle(createLink(t, oset_results, expr->getTruthValue()));
}

/**
 * instantiate -- create a grounded expression from an ungrounded one.
 *
 * Given a handle to an ungrounded expression, and a set of groundings,
 * this will create a grounded expression.
 *
 * The set of groundings is to be passed in with the map 'vars', which
 * maps variable names to their groundings -- it maps variable names to
 * atoms that already exist in the atomspace.  This method will then go
 * through all of the variables in the expression, and substitute them
 * with their values, creating a new expression. The new expression is
 * added to the atomspace, and its handle is returned.
 */
Handle Instantiator::instantiate(const Handle& expr,
                                 const std::map<Handle, Handle> &vars)
{
	// throw, not assert, because this is a user error ...
	if (nullptr == expr)
		throw InvalidParamException(TRACE_INFO,
			"Asked to ground a null expression");

	_vmap = &vars;

	// The returned handle is not yet in the atomspace. Add it now.
	// We do this here, instead of in walk_tree(), because adding
	// atoms to the atomspace is an expensive process.  We can save
	// some time by doing it just once, right here, in one big batch.
	// A null pointer means that we hit
	Handle gnd = walk_tree(expr);
	if (NULL != gnd)
		return _as->add_atom(gnd);
	return gnd;
}

/* ===================== END OF FILE ===================== */
<commit_msg>Replace NULL by nullprt<commit_after>/*
 * Instantiator.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 <opencog/atoms/core/DefineLink.h>
#include <opencog/atoms/core/FunctionLink.h>
#include <opencog/atoms/core/PutLink.h>
#include <opencog/atoms/execution/ExecutionOutputLink.h>
#include <opencog/atoms/reduct/FoldLink.h>
#include <opencog/query/BindLinkAPI.h>

#include "Instantiator.h"

using namespace opencog;

HandleSeq Instantiator::walk_tree(const HandleSeq& expr)
{
	HandleSeq oset_results;
	for (const Handle& h : expr)
	{
		Handle hg(walk_tree(h));
		// It could be a NULL handle if it's deleted... Just skip
		// over it. We test the pointer here, not the uuid, since
		// the uuid's are all Handle::UNDEFINED until we put them
		// into the atomspace.
		if (NULL != hg)
			oset_results.emplace_back(hg);
	}
	return oset_results;
}

Handle Instantiator::walk_tree(const Handle& expr)
{
	Type t = expr->getType();

	// Must not explore the insides of a QuoteLink.
	// XXX TODO: Need to implement UNQUOTE_LINK here...
	if (QUOTE_LINK == t)
		return Handle(expr);

	LinkPtr lexpr(LinkCast(expr));
	if (not lexpr)
	{
		// If we are here, we are a Node.
		if (DEFINED_SCHEMA_NODE == t)
		{
			return walk_tree(DefineLink::get_definition(expr));
		}

		if (VARIABLE_NODE != t)
			return Handle(expr);

		// If we are here, we found a variable. Look it up. Return a
		// grounding if it has one, otherwise return the variable
		// itself.
		std::map<Handle,Handle>::const_iterator it = _vmap->find(expr);
		if (_vmap->end() == it) return Handle(expr);

		// Not so fast, pardner. VariableNodes can be grounded by
		// links, and those links may be executable. In that case,
		// we have to execute them.

		// halt infinite regress
		if (_halt)
			return Handle(expr);

		_halt = true;
		Handle hgnd(walk_tree(it->second));
		_halt = false;
		return hgnd;
	}

	// -----------------------------------------------------------
	// If we are here, then we have a link. Walk it. In general,
	// links may contain both bound variables, and also free variables.
	// We must be careful to substitute only for free variables, and
	// never for bound ones.
	//
	// Reduce PutLinks.
	if (PUT_LINK == t)
	{
		PutLinkPtr ppp(PutLinkCast(expr));

		// PutLinks always have arity two. There may be free vars in
		// the body of the PutLink, but we won't substitue for them until
		// after the beta-reduction.  Do substitute the free vars that
		// occur in the argument, and do that before beta-reduction.
		// Execute the body only after the beta-reduction has been done.
		const HandleSeq& oset = lexpr->getOutgoingSet();
		Handle gargs = walk_tree(oset[1]);
		if (gargs != oset[1])
		{
			HandleSeq groset;
			groset.emplace_back(oset[0]);
			groset.emplace_back(gargs);
			ppp = createPutLink(groset);
		}
		// Step one: beta-reduce.
		Handle red = ppp->reduce();
		// Step two: execute the resulting body.
		return walk_tree(red);
	}

	// ExecutionOutputLinks are not handled by the FunctionLink factory
	// below. This is due to a circular shared-libarary dependency.
	if (EXECUTION_OUTPUT_LINK == t)
	{
		// At this time, the GSN or the DSN is always in position 0
		// of the outgoing set, and the ListLink of arguments is always
		// in position 1.  Someday in the future, there may be a variable
		// declaration; we punt on that.
		Handle sn(lexpr->getOutgoingAtom(0));
		Handle args(lexpr->getOutgoingAtom(1));

		// Perform substitution on the args, only.
		args = walk_tree(args);

		// If its a DSN, obtain the correct body for it.
		if (DEFINED_SCHEMA_NODE == sn->getType())
			sn = DefineLink::get_definition(sn);

		// If its a function link, execute it here.
		if (FUNCTION_LINK == sn->getType())
		{
			FunctionLinkPtr flp(FunctionLinkCast(sn));
			if (NULL == flp)
				flp = createFunctionLink(*LinkCast(sn));

			// Two-step process. First, plug the arguments into the
			// function; i.e. perform beta-reduction. Second, actually
			// execute the result. We execute by just calling walk_tree
			// again.
			Handle body(flp->get_body());
			Variables vars(flp->get_variables());

			const HandleSeq& oset(LinkCast(args)->getOutgoingSet());
			Handle beta_reduced(vars.substitute(body, oset));
			return walk_tree(beta_reduced);
		}

		ExecutionOutputLinkPtr eolp(createExecutionOutputLink(sn, args));
		return eolp->execute(_as);
	}

	// FoldLink's cannot be handled by the factory below, due to
	// ciruclar shared library dependencies. Yuck. Something better
	// than a factory needs to be invented.
	if (classserver().isA(t, FOLD_LINK))
	{
		// At this time, no FoldLink ever has a variable declaration,
		// and the number of arguments is not fixed, i.e. variadic.
		// Perform substitution on all arguments before applying the
		// function itself.
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		Handle hl(FoldLink::factory(t, oset_results));
		FoldLinkPtr flp(FoldLinkCast(hl));
		return flp->execute(_as);
	}

	// Handle DeleteLink's before general FunctionLink's; they
	// work differently.
	if (DELETE_LINK == t)
	{
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		for (const Handle& h: oset_results)
			if (VARIABLE_NODE != h->getType())
				_as->remove_atom(h, true);

		return Handle::UNDEFINED;
	}

	// Fire any other function links, not handled above.
	if (classserver().isA(t, FUNCTION_LINK))
	{
		// At this time, no FunctionLink that is outsode of an
		// ExecutionOutputLink ever has a variable declaration.
		// Also, the number of arguments is not fixed, i.e. variadic.
		// Perform substitution on all arguments before applying the
		// function itself.
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		Handle hl(FunctionLink::factory(t, oset_results));
		FunctionLinkPtr flp(FunctionLinkCast(hl));
		return flp->execute(_as);
	}

	// If there is a GetLink, we have to perform the get, and replace
	// it with the results of the get. The get is implemented with the
	// PatternLink::satisfy() method.
	if (GET_LINK == t)
	{
		HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
		size_t sz = oset_results.size();
		for (size_t i=0; i< sz; i++)
			oset_results[i] = _as->add_atom(oset_results[i]);

		LinkPtr lp = createLink(GET_LINK, oset_results);

		return satisfying_set(_as, Handle(lp));
	}

	// None of the above. Create a duplicate link, but with an outgoing
	// set where the variables have been substituted by their values.
	HandleSeq oset_results(walk_tree(lexpr->getOutgoingSet()));
	return Handle(createLink(t, oset_results, expr->getTruthValue()));
}

/**
 * instantiate -- create a grounded expression from an ungrounded one.
 *
 * Given a handle to an ungrounded expression, and a set of groundings,
 * this will create a grounded expression.
 *
 * The set of groundings is to be passed in with the map 'vars', which
 * maps variable names to their groundings -- it maps variable names to
 * atoms that already exist in the atomspace.  This method will then go
 * through all of the variables in the expression, and substitute them
 * with their values, creating a new expression. The new expression is
 * added to the atomspace, and its handle is returned.
 */
Handle Instantiator::instantiate(const Handle& expr,
                                 const std::map<Handle, Handle> &vars)
{
	// throw, not assert, because this is a user error ...
	if (nullptr == expr)
		throw InvalidParamException(TRACE_INFO,
			"Asked to ground a null expression");

	_vmap = &vars;

	// The returned handle is not yet in the atomspace. Add it now.
	// We do this here, instead of in walk_tree(), because adding
	// atoms to the atomspace is an expensive process.  We can save
	// some time by doing it just once, right here, in one big batch.
	// A null pointer means that we hit
	Handle gnd = walk_tree(expr);
	if (nullptr != gnd)
		return _as->add_atom(gnd);
	return gnd;
}

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


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"

#include "base/logging.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/api/sync_error.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "content/browser/browser_thread.h"

namespace browser_sync {

NonFrontendDataTypeController::NonFrontendDataTypeController()
    : profile_sync_factory_(NULL),
      profile_(NULL),
      profile_sync_service_(NULL),
      state_(NOT_RUNNING),
      abort_association_(false),
      abort_association_complete_(false, false),
      datatype_stopped_(false, false) {}

NonFrontendDataTypeController::NonFrontendDataTypeController(
    ProfileSyncFactory* profile_sync_factory,
    Profile* profile)
    : profile_sync_factory_(profile_sync_factory),
      profile_(profile),
      profile_sync_service_(profile->GetProfileSyncService()),
      state_(NOT_RUNNING),
      abort_association_(false),
      abort_association_complete_(false, false),
      datatype_stopped_(false, false) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_sync_factory_);
  DCHECK(profile_);
  DCHECK(profile_sync_service_);
}

NonFrontendDataTypeController::~NonFrontendDataTypeController() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void NonFrontendDataTypeController::Start(StartCallback* start_callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(start_callback);
  if (state_ != NOT_RUNNING) {
    start_callback->Run(BUSY, SyncError());
    delete start_callback;
    return;
  }

  start_callback_.reset(start_callback);
  abort_association_ = false;

  state_ = MODEL_STARTING;
  if (!StartModels()) {
    // If we are waiting for some external service to load before associating
    // or we failed to start the models, we exit early. state_ will control
    // what we perform next.
    DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
    return;
  }

  // Kick off association on the thread the datatype resides on.
  state_ = ASSOCIATING;
  if (!StartAssociationAsync()) {
    SyncError error(FROM_HERE, "Failed to post StartAssociation", type());
    StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error);
  }
}

bool NonFrontendDataTypeController::StartModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_EQ(state_, MODEL_STARTING);
  // By default, no additional services need to be started before we can proceed
  // with model association, so do nothing.
  return true;
}

void NonFrontendDataTypeController::StartAssociation() {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_EQ(state_, ASSOCIATING);
  {
    base::AutoLock lock(abort_association_lock_);
    if (abort_association_) {
      abort_association_complete_.Signal();
      return;
    }
    CreateSyncComponents();
  }

  if (!model_associator_->CryptoReadyIfNecessary()) {
    StartFailed(NEEDS_CRYPTO, SyncError());
    return;
  }

  bool sync_has_nodes = false;
  if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
    SyncError error(FROM_HERE, "Failed to load sync nodes", type());
    StartFailed(UNRECOVERABLE_ERROR, error);
    return;
  }

  base::TimeTicks start_time = base::TimeTicks::Now();
  SyncError error;
  bool merge_success = model_associator_->AssociateModels(&error);
  RecordAssociationTime(base::TimeTicks::Now() - start_time);
  if (!merge_success) {
    StartFailed(ASSOCIATION_FAILED, error);
    return;
  }

  profile_sync_service_->ActivateDataType(type(), model_safe_group(),
                                          change_processor_.get());
  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError());
}

void NonFrontendDataTypeController::StartFailed(StartResult result,
                                                const SyncError& error) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  model_associator_.reset();
  change_processor_.reset();
  StartDone(result,
            result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING,
            error);
}

void NonFrontendDataTypeController::StartDone(
    DataTypeController::StartResult result,
    DataTypeController::State new_state,
    const SyncError& error) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  abort_association_complete_.Signal();
  base::AutoLock lock(abort_association_lock_);
  if (!abort_association_) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(
            this,
            &NonFrontendDataTypeController::StartDoneImpl,
            result,
            new_state,
            error));
  }
}

void NonFrontendDataTypeController::StartDoneImpl(
    DataTypeController::StartResult result,
    DataTypeController::State new_state,
    const SyncError& error) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  state_ = new_state;
  if (state_ != RUNNING) {
    // Start failed.
    StopModels();
    RecordStartFailure(result);
  }

  // We have to release the callback before we call it, since it's possible
  // invoking the callback will trigger a call to STOP(), which will get
  // confused by the non-NULL start_callback_.
  scoped_ptr<StartCallback> callback(start_callback_.release());
  callback->Run(result, error);
}

// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
// this (http://crbug.com/55662).
void NonFrontendDataTypeController::Stop() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // If Stop() is called while Start() is waiting for association to
  // complete, we need to abort the association and wait for the DB
  // thread to finish the StartImpl() task.
  if (state_ == ASSOCIATING) {
    state_ = STOPPING;
    {
      base::AutoLock lock(abort_association_lock_);
      abort_association_ = true;
      if (model_associator_.get())
        model_associator_->AbortAssociation();
    }
    // Wait for the model association to abort.
    abort_association_complete_.Wait();
    StartDoneImpl(ABORTED, STOPPING, SyncError());
  } else if (state_ == MODEL_STARTING) {
    state_ = STOPPING;
    // If Stop() is called while Start() is waiting for the models to start,
    // abort the start. We don't need to continue on since it means we haven't
    // kicked off the association, and once we call StopModels, we never will.
    StartDoneImpl(ABORTED, NOT_RUNNING, SyncError());
    return;
  } else {
    state_ = STOPPING;

    StopModels();
  }
  DCHECK(!start_callback_.get());

  // Deactivate the change processor on the UI thread. We dont want to listen
  // for any more changes or process them from server.
  profile_sync_service_->DeactivateDataType(type());

  if (StopAssociationAsync()) {
    datatype_stopped_.Wait();
  } else {
    // We do DFATAL here because this will eventually lead to a failed CHECK
    // when the change processor gets destroyed on the wrong thread.
    LOG(DFATAL) << "Failed to destroy datatype " << name();
  }
  state_ = NOT_RUNNING;
}

void NonFrontendDataTypeController::StopModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(state_ == STOPPING || state_ == NOT_RUNNING || state_ == DISABLED);
  VLOG(1) << "NonFrontendDataTypeController::StopModels(): State = " << state_;
  // Do nothing by default.
}

void NonFrontendDataTypeController::StopAssociation() {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (model_associator_.get()) {
    SyncError error;  // Not used.
    model_associator_->DisassociateModels(&error);
  }
  model_associator_.reset();
  change_processor_.reset();
  datatype_stopped_.Signal();
}

std::string NonFrontendDataTypeController::name() const {
  // For logging only.
  return syncable::ModelTypeToString(type());
}

DataTypeController::State NonFrontendDataTypeController::state() const {
  return state_;
}

void NonFrontendDataTypeController::OnUnrecoverableError(
    const tracked_objects::Location& from_here,
    const std::string& message) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  RecordUnrecoverableError(from_here, message);
  BrowserThread::PostTask(BrowserThread::UI, from_here, NewRunnableMethod(this,
      &NonFrontendDataTypeController::OnUnrecoverableErrorImpl, from_here,
      message));
}

void NonFrontendDataTypeController::OnUnrecoverableErrorImpl(
    const tracked_objects::Location& from_here,
    const std::string& message) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  profile_sync_service_->OnUnrecoverableError(from_here, message);
}

ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory()
    const {
  return profile_sync_factory_;
}

Profile* NonFrontendDataTypeController::profile() const {
  return profile_;
}

ProfileSyncService* NonFrontendDataTypeController::profile_sync_service()
    const {
  return profile_sync_service_;
}

void NonFrontendDataTypeController::set_state(State state) {
  state_ = state;
}

void NonFrontendDataTypeController::set_model_associator(
    AssociatorInterface* associator) {
  model_associator_.reset(associator);
}

void NonFrontendDataTypeController::set_change_processor(
    ChangeProcessor* change_processor) {
  change_processor_.reset(change_processor);
}

}  // namespace browser_sync
<commit_msg>In StopDoneImpl check for the current state. If it is not running return right away.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"

#include "base/logging.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/api/sync_error.h"
#include "chrome/browser/sync/glue/change_processor.h"
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/syncable/model_type.h"
#include "content/browser/browser_thread.h"

namespace browser_sync {

NonFrontendDataTypeController::NonFrontendDataTypeController()
    : profile_sync_factory_(NULL),
      profile_(NULL),
      profile_sync_service_(NULL),
      state_(NOT_RUNNING),
      abort_association_(false),
      abort_association_complete_(false, false),
      datatype_stopped_(false, false) {}

NonFrontendDataTypeController::NonFrontendDataTypeController(
    ProfileSyncFactory* profile_sync_factory,
    Profile* profile)
    : profile_sync_factory_(profile_sync_factory),
      profile_(profile),
      profile_sync_service_(profile->GetProfileSyncService()),
      state_(NOT_RUNNING),
      abort_association_(false),
      abort_association_complete_(false, false),
      datatype_stopped_(false, false) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_sync_factory_);
  DCHECK(profile_);
  DCHECK(profile_sync_service_);
}

NonFrontendDataTypeController::~NonFrontendDataTypeController() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void NonFrontendDataTypeController::Start(StartCallback* start_callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(start_callback);
  if (state_ != NOT_RUNNING) {
    start_callback->Run(BUSY, SyncError());
    delete start_callback;
    return;
  }

  start_callback_.reset(start_callback);
  abort_association_ = false;

  state_ = MODEL_STARTING;
  if (!StartModels()) {
    // If we are waiting for some external service to load before associating
    // or we failed to start the models, we exit early. state_ will control
    // what we perform next.
    DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
    return;
  }

  // Kick off association on the thread the datatype resides on.
  state_ = ASSOCIATING;
  if (!StartAssociationAsync()) {
    SyncError error(FROM_HERE, "Failed to post StartAssociation", type());
    StartDoneImpl(ASSOCIATION_FAILED, DISABLED, error);
  }
}

bool NonFrontendDataTypeController::StartModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_EQ(state_, MODEL_STARTING);
  // By default, no additional services need to be started before we can proceed
  // with model association, so do nothing.
  return true;
}

void NonFrontendDataTypeController::StartAssociation() {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK_EQ(state_, ASSOCIATING);
  {
    base::AutoLock lock(abort_association_lock_);
    if (abort_association_) {
      abort_association_complete_.Signal();
      return;
    }
    CreateSyncComponents();
  }

  if (!model_associator_->CryptoReadyIfNecessary()) {
    StartFailed(NEEDS_CRYPTO, SyncError());
    return;
  }

  bool sync_has_nodes = false;
  if (!model_associator_->SyncModelHasUserCreatedNodes(&sync_has_nodes)) {
    SyncError error(FROM_HERE, "Failed to load sync nodes", type());
    StartFailed(UNRECOVERABLE_ERROR, error);
    return;
  }

  base::TimeTicks start_time = base::TimeTicks::Now();
  SyncError error;
  bool merge_success = model_associator_->AssociateModels(&error);
  RecordAssociationTime(base::TimeTicks::Now() - start_time);
  if (!merge_success) {
    StartFailed(ASSOCIATION_FAILED, error);
    return;
  }

  profile_sync_service_->ActivateDataType(type(), model_safe_group(),
                                          change_processor_.get());
  StartDone(!sync_has_nodes ? OK_FIRST_RUN : OK, RUNNING, SyncError());
}

void NonFrontendDataTypeController::StartFailed(StartResult result,
                                                const SyncError& error) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  model_associator_.reset();
  change_processor_.reset();
  StartDone(result,
            result == ASSOCIATION_FAILED ? DISABLED : NOT_RUNNING,
            error);
}

void NonFrontendDataTypeController::StartDone(
    DataTypeController::StartResult result,
    DataTypeController::State new_state,
    const SyncError& error) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  abort_association_complete_.Signal();
  base::AutoLock lock(abort_association_lock_);
  if (!abort_association_) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(
            this,
            &NonFrontendDataTypeController::StartDoneImpl,
            result,
            new_state,
            error));
  }
}

void NonFrontendDataTypeController::StartDoneImpl(
    DataTypeController::StartResult result,
    DataTypeController::State new_state,
    const SyncError& error) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (state_ == NOT_RUNNING) {
    // During stop it is possible startdoneimpl can be called twice. Once from
    // the |StartDone| method and once from the |Stop| method.
    DCHECK(!start_callback_.get());
    return;
  }
  state_ = new_state;
  if (state_ != RUNNING) {
    // Start failed.
    StopModels();
    RecordStartFailure(result);
  }

  // We have to release the callback before we call it, since it's possible
  // invoking the callback will trigger a call to STOP(), which will get
  // confused by the non-NULL start_callback_.
  scoped_ptr<StartCallback> callback(start_callback_.release());
  callback->Run(result, error);
}

// TODO(sync): Blocking the UI thread at shutdown is bad. If we had a way of
// distinguishing chrome shutdown from sync shutdown, we should be able to avoid
// this (http://crbug.com/55662).
void NonFrontendDataTypeController::Stop() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // If Stop() is called while Start() is waiting for association to
  // complete, we need to abort the association and wait for the DB
  // thread to finish the StartImpl() task.
  if (state_ == ASSOCIATING) {
    state_ = STOPPING;
    {
      base::AutoLock lock(abort_association_lock_);
      abort_association_ = true;
      if (model_associator_.get())
        model_associator_->AbortAssociation();
    }
    // Wait for the model association to abort.
    abort_association_complete_.Wait();
    StartDoneImpl(ABORTED, STOPPING, SyncError());
  } else if (state_ == MODEL_STARTING) {
    state_ = STOPPING;
    // If Stop() is called while Start() is waiting for the models to start,
    // abort the start. We don't need to continue on since it means we haven't
    // kicked off the association, and once we call StopModels, we never will.
    StartDoneImpl(ABORTED, NOT_RUNNING, SyncError());
    return;
  } else {
    state_ = STOPPING;

    StopModels();
  }
  DCHECK(!start_callback_.get());

  // Deactivate the change processor on the UI thread. We dont want to listen
  // for any more changes or process them from server.
  profile_sync_service_->DeactivateDataType(type());

  if (StopAssociationAsync()) {
    datatype_stopped_.Wait();
  } else {
    // We do DFATAL here because this will eventually lead to a failed CHECK
    // when the change processor gets destroyed on the wrong thread.
    LOG(DFATAL) << "Failed to destroy datatype " << name();
  }
  state_ = NOT_RUNNING;
}

void NonFrontendDataTypeController::StopModels() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(state_ == STOPPING || state_ == NOT_RUNNING || state_ == DISABLED);
  VLOG(1) << "NonFrontendDataTypeController::StopModels(): State = " << state_;
  // Do nothing by default.
}

void NonFrontendDataTypeController::StopAssociation() {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (model_associator_.get()) {
    SyncError error;  // Not used.
    model_associator_->DisassociateModels(&error);
  }
  model_associator_.reset();
  change_processor_.reset();
  datatype_stopped_.Signal();
}

std::string NonFrontendDataTypeController::name() const {
  // For logging only.
  return syncable::ModelTypeToString(type());
}

DataTypeController::State NonFrontendDataTypeController::state() const {
  return state_;
}

void NonFrontendDataTypeController::OnUnrecoverableError(
    const tracked_objects::Location& from_here,
    const std::string& message) {
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
  RecordUnrecoverableError(from_here, message);
  BrowserThread::PostTask(BrowserThread::UI, from_here, NewRunnableMethod(this,
      &NonFrontendDataTypeController::OnUnrecoverableErrorImpl, from_here,
      message));
}

void NonFrontendDataTypeController::OnUnrecoverableErrorImpl(
    const tracked_objects::Location& from_here,
    const std::string& message) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  profile_sync_service_->OnUnrecoverableError(from_here, message);
}

ProfileSyncFactory* NonFrontendDataTypeController::profile_sync_factory()
    const {
  return profile_sync_factory_;
}

Profile* NonFrontendDataTypeController::profile() const {
  return profile_;
}

ProfileSyncService* NonFrontendDataTypeController::profile_sync_service()
    const {
  return profile_sync_service_;
}

void NonFrontendDataTypeController::set_state(State state) {
  state_ = state;
}

void NonFrontendDataTypeController::set_model_associator(
    AssociatorInterface* associator) {
  model_associator_.reset(associator);
}

void NonFrontendDataTypeController::set_change_processor(
    ChangeProcessor* change_processor) {
  change_processor_.reset(change_processor);
}

}  // namespace browser_sync
<|endoftext|>


<commit_before>#include <cassert>
#include <regex>
#include <sstream>
#include "dart/common/Console.h"
#include "UriUtils.h"

// std::regex is only implemented in GCC 4.9 and above; i.e. libstdc++ 6.0.20
// or above. In fact, it contains major bugs in GCC 4.8 [1]. There is no
// reliable way to test the version of libstdc++ when building with Clang [2],
// so we'll fall back on Boost.Regex when using libstdc++.
//
// [1] http://stackoverflow.com/a/12665408/111426
// [2] http://stackoverflow.com/q/31506594/111426
//
#ifdef __GLIBCXX__

#include <boost/regex.hpp>

using boost::regex;
using boost::regex_match;
using boost::smatch;
using boost::ssub_match;

#else

#include <regex>

using std::regex;
using std::regex_match;
using std::smatch;
using std::ssub_match;

#endif

static bool startsWith(const std::string& _target, const std::string& _prefix)
{
  return _target.substr(0, _prefix.size()) == _prefix;
}

namespace dart {
namespace utils {

/*
 * UriComponent
 */
UriComponent::UriComponent()
{
  reset();
}

UriComponent::UriComponent(reference_const_type _value)
{
  assign(_value);
}

UriComponent::operator bool() const
{
  return mExists;
}

bool UriComponent::operator !() const
{
  return !mExists;
}

auto UriComponent::operator =(reference_const_type _value) -> UriComponent&
{
  assign(_value);
  return *this;
}

auto UriComponent::operator*() -> reference_type
{
  return get();
}

auto UriComponent::operator*() const -> reference_const_type
{
  return get();
}

auto UriComponent::operator->() -> pointer_type
{
  return &get();
}

auto UriComponent::operator->() const -> pointer_const_type
{
  return &get();
}

void UriComponent::assign(reference_const_type _value)
{
  mExists = true;
  mValue = _value;
}

void UriComponent::reset()
{
  mExists = false;
}

auto UriComponent::get() -> reference_type
{
  assert(mExists);
  return mValue;
}

auto UriComponent::get() const -> reference_const_type
{
  assert(mExists);
  return mValue;
}

auto UriComponent::get_value_or(reference_type _default) -> reference_type
{
  if(mExists)
    return mValue;
  else
    return _default;
}

auto UriComponent::get_value_or(reference_const_type _default) const -> reference_const_type
{
  if(mExists)
    return mValue;
  else
    return _default;
}

/*
 * Uri
 */
void Uri::clear()
{
  mScheme.reset();
  mAuthority.reset();
  mPath.reset();
  mQuery.reset();
  mFragment.reset();
}

void Uri::append(const std::string& _relativePath)
{
  if (mPath)
    mPath = *mPath + "/" + _relativePath;
  else
    mPath = _relativePath;
}

bool Uri::isPath() const
{
  return !mScheme && mPath;
}

bool Uri::isRelativePath() const
{
  return isPath() && !mPath->empty() && mPath->front() != '/';
}

bool Uri::fromRelativeUri(const Uri& _base, const std::string& _relative, bool _strict)
{
  Uri relativeUri;
  if(!relativeUri.fromString(_relative))
    return false;

  return fromRelativeUri(_base, relativeUri, _strict);
}

bool Uri::fromRelativeUri(const Uri& _base, const Uri& _relative, bool _strict)
{
  assert(_base.mPath && "The path component is always defined.");
  assert(_relative.mPath && "The path component is always defined.");

  // TODO If (!_strict && _relative.mScheme == _base.mScheme), then we need to
  // enable backwards compatability.

  // This directly implements the psueocode in Section 5.2.2. of RFC 3986.
  if(_relative.mScheme)
  {
    mScheme = _relative.mScheme;
    mAuthority = _relative.mAuthority;
    mPath = removeDotSegments(*_relative.mPath);
    mQuery = _relative.mQuery;
  }
  else
  {
    if(_relative.mAuthority)
    {
      mAuthority = _relative.mAuthority;
      mPath = removeDotSegments(*_relative.mPath);
      mQuery = _relative.mQuery;
    }
    else
    {
      if(_relative.mPath->empty())
      {
        mPath = _base.mPath;

        if(_relative.mQuery)
          mQuery = _relative.mQuery;
        else
          mQuery = _base.mQuery;
      }
      else
      {
        if(_relative.mPath->front() == '/')
          mPath = removeDotSegments(*_relative.mPath);
        else
          mPath = removeDotSegments(mergePaths(_base, _relative));

        mQuery = _relative.mQuery;
      }

      mAuthority = _base.mAuthority;
    }

    mScheme = _base.mScheme;
  }

  mFragment = _relative.mFragment;
  return true;
}

bool Uri::fromString(const std::string& _input)
{
  // This is regex is from Appendix B of RFC 3986.
  static regex uriRegex(
    R"END(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)END",
    regex::extended);
  static const size_t schemeIndex = 2;
  static const size_t authorityIndex = 4;
  static const size_t pathIndex = 5;
  static const size_t queryIndex = 7;
  static const size_t fragmentIndex = 9;

  clear();

  smatch matches;
  if(!regex_match(_input, matches, uriRegex))
    return false;

  assert(matches.size() > schemeIndex);
  const ssub_match& schemeMatch = matches[schemeIndex];
  if(schemeMatch.matched)
    mScheme = schemeMatch;

  assert(matches.size() > authorityIndex);
  const ssub_match& authorityMatch = matches[authorityIndex];
  if(authorityMatch.matched)
    mAuthority = authorityMatch;

  assert(matches.size() > pathIndex);
  const ssub_match& pathMatch = matches[pathIndex];
  if(pathMatch.matched)
    mPath = pathMatch;

  assert(matches.size() > queryIndex);
  const ssub_match& queryMatch = matches[queryIndex];
  if(queryMatch.matched)
    mQuery = queryMatch;

  assert(matches.size() > fragmentIndex);
  const ssub_match& fragmentMatch = matches[fragmentIndex];
  if (fragmentMatch.matched)
    mFragment = fragmentMatch;

  return true;
}

std::string Uri::toString() const
{
  // This function implements the pseudo-code from Section 5.3 of RFC 3986.
  std::stringstream output;

  if(mScheme)
    output << *mScheme << ":";

  if(mAuthority)
    output << "//" << *mAuthority;

  output << mPath.get_value_or("");

  if(mQuery)
    output << "?" << *mQuery;

  if(mFragment)
    output << "#" << *mFragment;

  return output.str();
}

bool Uri::fromStringOrPath(const std::string& _input)
{
  if (!fromString(_input))
    return false;

  // Assume that any URI without a scheme is a path.
  if (!mScheme && mPath)
  {
    mScheme = "file";

    // Replace backslashes (from Windows paths) with forward slashes.
    std::replace(std::begin(*mPath), std::end(*mPath), '\\', '/');
  }

  return true;
}

std::string Uri::getUri(const std::string& _input)
{
  Uri uri;
  if(uri.fromStringOrPath(_input))
    return uri.toString();
  else
    return "";
}

std::string Uri::mergePaths(const Uri& _base, const Uri& _relative)
{
  assert(_base.mPath && "The path component is always defined.");
  assert(_relative.mPath && "The path component is always defined.");

  // This directly implements the logic from Section 5.2.3. of RFC 3986.
  if(_base.mAuthority && _base.mPath->empty())
    return "/" + *_relative.mPath;
  else
  {
    const size_t index = _base.mPath->find_last_of('/');
    if(index != std::string::npos)
      return _base.mPath->substr(0, index + 1) + *_relative.mPath;
    else
      return *_relative.mPath;
  }
}

std::string Uri::removeDotSegments(const std::string& _path)
{
  // 1.  The input buffer is initialized with the now-appended path
  //     components and the output buffer is initialized to the empty
  //     string.
  std::string input = _path;
  std::string output;

  // 2.  While the input buffer is not empty, loop as follows:
  while(!input.empty())
  {
    // A.  If the input buffer begins with a prefix of "../" or "./",
    //     then remove that prefix from the input buffer; otherwise,
    if(startsWith(input, "../"))
    {
      input = input.substr(3);
    }
    else if(startsWith(input, "./"))
    {
      input = input.substr(2);
    }
    // B.  if the input buffer begins with a prefix of "/./" or "/.",
    //     where "." is a complete path segment, then replace that
    //     prefix with "/" in the input buffer; otherwise,
    else if(input == "/.")
    {
      input = "/";
    }
    else if(startsWith(input, "/./"))
    {
      input = "/" + input.substr(3);
    }
    // C.  if the input buffer begins with a prefix of "/../" or "/..",
    //     where ".." is a complete path segment, then replace that
    //     prefix with "/" in the input buffer and remove the last
    //     segment and its preceding "/" (if any) from the output
    //     buffer; otherwise,
    else if(input  == "/..")
    {
      input = "/";

      size_t index = output.find_last_of('/');
      if(index != std::string::npos)
        output = output.substr(0, index);
      else
        output = "";
    }
    else if(startsWith(input, "/../"))
    {
      input = "/" + input.substr(4);

      size_t index = output.find_last_of('/');
      if(index != std::string::npos)
        output = output.substr(0, index);
      else
        output = "";
    }
    // D.  if the input buffer consists only of "." or "..", then remove
    //     that from the input buffer; otherwise,
    else if(input == "." || input == "..")
    {
      input = "";
    }
    // E.  move the first path segment in the input buffer to the end of
    //     the output buffer, including the initial "/" character (if
    //     any) and any subsequent characters up to, but not including,
    //     the next "/" character or the end of the input buffer.
    else
    {
      // Start at index one so we keep the leading '/'.
      size_t index = input.find_first_of('/', 1);
      output += input.substr(0, index);

      if(index != std::string::npos)
        input = input.substr(index);
      else
        input = "";
    }
  }

  // 3.  Finally, the output buffer is returned as the result of
  //     remove_dot_segments.
  return output;
}

} // namespace utils
} // namespace dart
<commit_msg>Optimized the regex.<commit_after>#include <cassert>
#include <regex>
#include <sstream>
#include "dart/common/Console.h"
#include "UriUtils.h"

// std::regex is only implemented in GCC 4.9 and above; i.e. libstdc++ 6.0.20
// or above. In fact, it contains major bugs in GCC 4.8 [1]. There is no
// reliable way to test the version of libstdc++ when building with Clang [2],
// so we'll fall back on Boost.Regex when using libstdc++.
//
// [1] http://stackoverflow.com/a/12665408/111426
// [2] http://stackoverflow.com/q/31506594/111426
//
#ifdef __GLIBCXX__

#include <boost/regex.hpp>

using boost::regex;
using boost::regex_match;
using boost::smatch;
using boost::ssub_match;

#else

#include <regex>

using std::regex;
using std::regex_match;
using std::smatch;
using std::ssub_match;

#endif

static bool startsWith(const std::string& _target, const std::string& _prefix)
{
  return _target.substr(0, _prefix.size()) == _prefix;
}

namespace dart {
namespace utils {

/*
 * UriComponent
 */
UriComponent::UriComponent()
{
  reset();
}

UriComponent::UriComponent(reference_const_type _value)
{
  assign(_value);
}

UriComponent::operator bool() const
{
  return mExists;
}

bool UriComponent::operator !() const
{
  return !mExists;
}

auto UriComponent::operator =(reference_const_type _value) -> UriComponent&
{
  assign(_value);
  return *this;
}

auto UriComponent::operator*() -> reference_type
{
  return get();
}

auto UriComponent::operator*() const -> reference_const_type
{
  return get();
}

auto UriComponent::operator->() -> pointer_type
{
  return &get();
}

auto UriComponent::operator->() const -> pointer_const_type
{
  return &get();
}

void UriComponent::assign(reference_const_type _value)
{
  mExists = true;
  mValue = _value;
}

void UriComponent::reset()
{
  mExists = false;
}

auto UriComponent::get() -> reference_type
{
  assert(mExists);
  return mValue;
}

auto UriComponent::get() const -> reference_const_type
{
  assert(mExists);
  return mValue;
}

auto UriComponent::get_value_or(reference_type _default) -> reference_type
{
  if(mExists)
    return mValue;
  else
    return _default;
}

auto UriComponent::get_value_or(reference_const_type _default) const -> reference_const_type
{
  if(mExists)
    return mValue;
  else
    return _default;
}

/*
 * Uri
 */
void Uri::clear()
{
  mScheme.reset();
  mAuthority.reset();
  mPath.reset();
  mQuery.reset();
  mFragment.reset();
}

void Uri::append(const std::string& _relativePath)
{
  if (mPath)
    mPath = *mPath + "/" + _relativePath;
  else
    mPath = _relativePath;
}

bool Uri::isPath() const
{
  return !mScheme && mPath;
}

bool Uri::isRelativePath() const
{
  return isPath() && !mPath->empty() && mPath->front() != '/';
}

bool Uri::fromRelativeUri(const Uri& _base, const std::string& _relative, bool _strict)
{
  Uri relativeUri;
  if(!relativeUri.fromString(_relative))
    return false;

  return fromRelativeUri(_base, relativeUri, _strict);
}

bool Uri::fromRelativeUri(const Uri& _base, const Uri& _relative, bool _strict)
{
  assert(_base.mPath && "The path component is always defined.");
  assert(_relative.mPath && "The path component is always defined.");

  // TODO If (!_strict && _relative.mScheme == _base.mScheme), then we need to
  // enable backwards compatability.

  // This directly implements the psueocode in Section 5.2.2. of RFC 3986.
  if(_relative.mScheme)
  {
    mScheme = _relative.mScheme;
    mAuthority = _relative.mAuthority;
    mPath = removeDotSegments(*_relative.mPath);
    mQuery = _relative.mQuery;
  }
  else
  {
    if(_relative.mAuthority)
    {
      mAuthority = _relative.mAuthority;
      mPath = removeDotSegments(*_relative.mPath);
      mQuery = _relative.mQuery;
    }
    else
    {
      if(_relative.mPath->empty())
      {
        mPath = _base.mPath;

        if(_relative.mQuery)
          mQuery = _relative.mQuery;
        else
          mQuery = _base.mQuery;
      }
      else
      {
        if(_relative.mPath->front() == '/')
          mPath = removeDotSegments(*_relative.mPath);
        else
          mPath = removeDotSegments(mergePaths(_base, _relative));

        mQuery = _relative.mQuery;
      }

      mAuthority = _base.mAuthority;
    }

    mScheme = _base.mScheme;
  }

  mFragment = _relative.mFragment;
  return true;
}

bool Uri::fromString(const std::string& _input)
{
  // This is regex is from Appendix B of RFC 3986.
  static regex uriRegex(
    R"END(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)END",
    regex::extended | regex::optimize);
  static const size_t schemeIndex = 2;
  static const size_t authorityIndex = 4;
  static const size_t pathIndex = 5;
  static const size_t queryIndex = 7;
  static const size_t fragmentIndex = 9;

  clear();

  smatch matches;
  if(!regex_match(_input, matches, uriRegex))
    return false;

  assert(matches.size() > schemeIndex);
  const ssub_match& schemeMatch = matches[schemeIndex];
  if(schemeMatch.matched)
    mScheme = schemeMatch;

  assert(matches.size() > authorityIndex);
  const ssub_match& authorityMatch = matches[authorityIndex];
  if(authorityMatch.matched)
    mAuthority = authorityMatch;

  assert(matches.size() > pathIndex);
  const ssub_match& pathMatch = matches[pathIndex];
  if(pathMatch.matched)
    mPath = pathMatch;

  assert(matches.size() > queryIndex);
  const ssub_match& queryMatch = matches[queryIndex];
  if(queryMatch.matched)
    mQuery = queryMatch;

  assert(matches.size() > fragmentIndex);
  const ssub_match& fragmentMatch = matches[fragmentIndex];
  if (fragmentMatch.matched)
    mFragment = fragmentMatch;

  return true;
}

std::string Uri::toString() const
{
  // This function implements the pseudo-code from Section 5.3 of RFC 3986.
  std::stringstream output;

  if(mScheme)
    output << *mScheme << ":";

  if(mAuthority)
    output << "//" << *mAuthority;

  output << mPath.get_value_or("");

  if(mQuery)
    output << "?" << *mQuery;

  if(mFragment)
    output << "#" << *mFragment;

  return output.str();
}

bool Uri::fromStringOrPath(const std::string& _input)
{
  if (!fromString(_input))
    return false;

  // Assume that any URI without a scheme is a path.
  if (!mScheme && mPath)
  {
    mScheme = "file";

    // Replace backslashes (from Windows paths) with forward slashes.
    std::replace(std::begin(*mPath), std::end(*mPath), '\\', '/');
  }

  return true;
}

std::string Uri::getUri(const std::string& _input)
{
  Uri uri;
  if(uri.fromStringOrPath(_input))
    return uri.toString();
  else
    return "";
}

std::string Uri::mergePaths(const Uri& _base, const Uri& _relative)
{
  assert(_base.mPath && "The path component is always defined.");
  assert(_relative.mPath && "The path component is always defined.");

  // This directly implements the logic from Section 5.2.3. of RFC 3986.
  if(_base.mAuthority && _base.mPath->empty())
    return "/" + *_relative.mPath;
  else
  {
    const size_t index = _base.mPath->find_last_of('/');
    if(index != std::string::npos)
      return _base.mPath->substr(0, index + 1) + *_relative.mPath;
    else
      return *_relative.mPath;
  }
}

std::string Uri::removeDotSegments(const std::string& _path)
{
  // 1.  The input buffer is initialized with the now-appended path
  //     components and the output buffer is initialized to the empty
  //     string.
  std::string input = _path;
  std::string output;

  // 2.  While the input buffer is not empty, loop as follows:
  while(!input.empty())
  {
    // A.  If the input buffer begins with a prefix of "../" or "./",
    //     then remove that prefix from the input buffer; otherwise,
    if(startsWith(input, "../"))
    {
      input = input.substr(3);
    }
    else if(startsWith(input, "./"))
    {
      input = input.substr(2);
    }
    // B.  if the input buffer begins with a prefix of "/./" or "/.",
    //     where "." is a complete path segment, then replace that
    //     prefix with "/" in the input buffer; otherwise,
    else if(input == "/.")
    {
      input = "/";
    }
    else if(startsWith(input, "/./"))
    {
      input = "/" + input.substr(3);
    }
    // C.  if the input buffer begins with a prefix of "/../" or "/..",
    //     where ".." is a complete path segment, then replace that
    //     prefix with "/" in the input buffer and remove the last
    //     segment and its preceding "/" (if any) from the output
    //     buffer; otherwise,
    else if(input  == "/..")
    {
      input = "/";

      size_t index = output.find_last_of('/');
      if(index != std::string::npos)
        output = output.substr(0, index);
      else
        output = "";
    }
    else if(startsWith(input, "/../"))
    {
      input = "/" + input.substr(4);

      size_t index = output.find_last_of('/');
      if(index != std::string::npos)
        output = output.substr(0, index);
      else
        output = "";
    }
    // D.  if the input buffer consists only of "." or "..", then remove
    //     that from the input buffer; otherwise,
    else if(input == "." || input == "..")
    {
      input = "";
    }
    // E.  move the first path segment in the input buffer to the end of
    //     the output buffer, including the initial "/" character (if
    //     any) and any subsequent characters up to, but not including,
    //     the next "/" character or the end of the input buffer.
    else
    {
      // Start at index one so we keep the leading '/'.
      size_t index = input.find_first_of('/', 1);
      output += input.substr(0, index);

      if(index != std::string::npos)
        input = input.substr(index);
      else
        input = "";
    }
  }

  // 3.  Finally, the output buffer is returned as the result of
  //     remove_dot_segments.
  return output;
}

} // namespace utils
} // namespace dart
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "GlobalConfig.h"

void InlinerConfig::bind_config() {
  bind("delete_non_virtuals", delete_non_virtuals, delete_non_virtuals);
  bind("true_virtual_inline", true_virtual_inline, true_virtual_inline);
  bind("intermediate_shrinking", intermediate_shrinking,
       intermediate_shrinking);
  bind("enforce_method_size_limit", enforce_method_size_limit,
       enforce_method_size_limit);
  bind("throws", throws_inline, throws_inline);
  bind("throw_after_no_return", throw_after_no_return, throw_after_no_return);
  bind("multiple_callers", multiple_callers, multiple_callers);
  bind("run_const_prop", shrinker.run_const_prop, shrinker.run_const_prop);
  bind("run_cse", shrinker.run_cse, shrinker.run_cse);
  bind("run_dedup_blocks", shrinker.run_dedup_blocks,
       shrinker.run_dedup_blocks);
  bind("run_copy_prop", shrinker.run_copy_prop, shrinker.run_copy_prop);
  bind("run_reg_alloc", shrinker.run_reg_alloc, shrinker.run_reg_alloc);
  bind("run_fast_reg_alloc", shrinker.run_fast_reg_alloc,
       shrinker.run_fast_reg_alloc);
  bind("run_local_dce", shrinker.run_local_dce, shrinker.run_local_dce);
  bind("no_inline_annos", {}, m_no_inline_annos);
  bind("force_inline_annos", {}, m_force_inline_annos);
  bind("blocklist", {}, m_blocklist);
  bind("blocklist", {}, m_blocklist);
  bind("caller_blocklist", {}, m_caller_blocklist);
  bind("intradex_allowlist", {}, m_intradex_allowlist,
       "The purpose of this white-list is to remove black-list entries when "
       "inlining after the InterDex pass has run. (This reduces the impact of "
       "black-list entries that avoid inlining conditional control-flow and "
       "catchers that cause issues with the SwitchMethodPartitioning analysis "
       "that tends to be used by passes that run before or during InterDex.)");
}

void OptDecisionsConfig::bind_config() {
  bind("enable_logs", false, enable_logs,
       "Should we log Redex's optimization decisions?");
}

void IRTypeCheckerConfig::bind_config() {
  bind("run_after_each_pass", {}, run_after_each_pass);
  bind("verify_moves", {}, verify_moves);
  bind("validate_invoke_super", {}, validate_invoke_super);
  bind("run_after_passes", {}, run_after_passes);
  bind("check_no_overwrite_this", {}, check_no_overwrite_this);
  bind("check_num_of_refs", {}, check_num_of_refs);
  bind("annotated_cfg_on_error", annotated_cfg_on_error,
       annotated_cfg_on_error);
}

void HasherConfig::bind_config() {
  bind("run_after_each_pass", {}, run_after_each_pass);
}

void AssessorConfig::bind_config() {
  bind("run_after_each_pass", run_after_each_pass, run_after_each_pass);
  bind("run_initially", run_initially, run_initially);
  bind("run_finally", run_finally, run_finally);
}

void CheckUniqueDeobfuscatedNamesConfig::bind_config() {
  bind("run_after_each_pass", run_after_each_pass, run_after_each_pass);
  bind("run_initially", run_initially, run_initially);
  bind("run_finally", run_finally, run_finally);
}

void MethodProfileOrderingConfig::bind_config() {
  bind("method_sorting_allowlisted_substrings",
       method_sorting_allowlisted_substrings,
       method_sorting_allowlisted_substrings);
  bind("min_appear_percent", min_appear_percent, min_appear_percent);
  bind("second_min_appear_percent", second_min_appear_percent,
       second_min_appear_percent);
  bind("skip_similarity_reordering", skip_similarity_reordering,
       skip_similarity_reordering);
}

void MethodSimilarityOrderingConfig::bind_config() {
  bind("use_class_level_perf_sensitivity", use_class_level_perf_sensitivity,
       use_class_level_perf_sensitivity);
  bind("disable", disable, disable);
}

void ProguardConfig::bind_config() {
  bind("blocklist", blocklist, blocklist);
  bind("disable_default_blocklist", disable_default_blocklist,
       disable_default_blocklist);
}

void PassManagerConfig::bind_config() {
  bind("pass_aliases", pass_aliases, pass_aliases);
}

void GlobalConfig::bind_config() {
  bool bool_param;
  std::string string_param;
  std::unordered_map<std::string, std::string> string_map_param;
  std::vector<std::string> string_vector_param;
  uint32_t uint32_param;
  // Sorted alphabetically
  bind("agg_method_stats_files", {}, string_vector_param);
  bind("android_sdk_api_15_file", "", string_param);
  bind("android_sdk_api_16_file", "", string_param);
  bind("android_sdk_api_17_file", "", string_param);
  bind("android_sdk_api_18_file", "", string_param);
  bind("android_sdk_api_19_file", "", string_param);
  bind("android_sdk_api_21_file", "", string_param);
  bind("android_sdk_api_23_file", "", string_param);
  bind("android_sdk_api_25_file", "", string_param);
  bind("android_sdk_api_26_file", "", string_param);
  bind("android_sdk_api_27_file", "", string_param);
  bind("android_sdk_api_28_file", "", string_param);
  bind("android_sdk_api_29_file", "", string_param);
  bind("bytecode_sort_mode", {}, string_vector_param);
  bind("coldstart_classes", "", string_param);
  bind("compute_xml_reachability", false, bool_param);
  bind("unused_keep_rule_abort", false, bool_param);
  bind("debug_info_kind", "", string_param);
  bind("default_coldstart_classes", "", string_param);
  bind("emit_class_method_info_map", false, bool_param);
  bind("emit_locator_strings", {}, bool_param);
  bind("iodi_layer_mode", "full", string_param,
       "IODI layer mode. One of \"full\", \"skip-layer-0-at-api-26\" or "
       "\"always-skip-layer-0\"");
  bind("symbolicate_detached_methods", false, bool_param);
  bind("enable_quickening", false, bool_param);
  bind("ab_experiments_states", {}, string_map_param);
  bind("ab_experiments_states_override", {}, string_map_param);
  bind("ab_experiments_default", "", string_param);
  bind("force_single_dex", false, bool_param);
  bind("emit_incoming_hashes", false, bool_param);
  bind("emit_outgoing_hashes", false, bool_param);
  bind("instruction_size_bitwidth_limit", 0u, uint32_param);
  bind("json_serde_supercls", {}, string_vector_param);
  bind("keep_all_annotation_classes", true, bool_param);
  bind("keep_methods", {}, string_vector_param);
  bind("keep_packages", {}, string_vector_param);
  bind("legacy_reflection_reachability", false, bool_param);
  bind("lower_with_cfg", {}, bool_param);
  bind("no_optimizations_annotations", {}, string_vector_param);
  bind("no_optimizations_blocklist", {}, string_vector_param);
  // TODO: Remove unused profiled_methods_file option and all build system
  // references
  bind("profiled_methods_file", "", string_param);
  bind("proguard_map", "", string_param);
  bind("prune_unexported_components", {}, string_vector_param);
  bind("pure_methods", {}, string_vector_param);
  bind("finalish_field_names", {}, string_vector_param);
  bind("record_keep_reasons", {}, bool_param);
  bind("dump_keep_reasons", {}, bool_param);
  bind("string_sort_mode", "", string_param);
  bind("write_cfg_each_pass", false, bool_param);
  bind("dump_cfg_classes", "", string_param);
  bind("slow_invariants_debug", false, bool_param);
  // Enabled for ease of testing, apps expected to opt-out
  bind("enable_bleeding_edge_app_bundle_support", true, bool_param);
  bind("no_devirtualize_annos", {}, string_vector_param);
  bind("create_init_class_insns", true, bool_param);
  bind("finalize_resource_table", false, bool_param);

  for (const auto& entry : m_registry) {
    m_global_configs.emplace(entry.name,
                             entry.bind_operation(this, entry.name));
  }
}

GlobalConfigRegistryEntry::GlobalConfigRegistryEntry(
    const std::string& name, BindOperationFn bind_operation)
    : name(name), bind_operation(std::move(bind_operation)) {}

GlobalConfigRegistry& GlobalConfig::default_registry() {
  static GlobalConfigRegistry registry{
      register_as<InlinerConfig>("inliner"),
      register_as<IRTypeCheckerConfig>("ir_type_checker"),
      register_as<HasherConfig>("hasher"),
      register_as<AssessorConfig>("assessor"),
      register_as<CheckUniqueDeobfuscatedNamesConfig>(
          "check_unique_deobfuscated_names"),
      register_as<OptDecisionsConfig>("opt_decisions"),
      register_as<MethodProfileOrderingConfig>("method_profile_order"),
      register_as<MethodSimilarityOrderingConfig>("method_similarity_order"),
      register_as<ProguardConfig>("proguard"),
      register_as<PassManagerConfig>("pass_manager"),
  };
  return registry;
}
<commit_msg>Remove unused profiled_methods_file option<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "GlobalConfig.h"

void InlinerConfig::bind_config() {
  bind("delete_non_virtuals", delete_non_virtuals, delete_non_virtuals);
  bind("true_virtual_inline", true_virtual_inline, true_virtual_inline);
  bind("intermediate_shrinking", intermediate_shrinking,
       intermediate_shrinking);
  bind("enforce_method_size_limit", enforce_method_size_limit,
       enforce_method_size_limit);
  bind("throws", throws_inline, throws_inline);
  bind("throw_after_no_return", throw_after_no_return, throw_after_no_return);
  bind("multiple_callers", multiple_callers, multiple_callers);
  bind("run_const_prop", shrinker.run_const_prop, shrinker.run_const_prop);
  bind("run_cse", shrinker.run_cse, shrinker.run_cse);
  bind("run_dedup_blocks", shrinker.run_dedup_blocks,
       shrinker.run_dedup_blocks);
  bind("run_copy_prop", shrinker.run_copy_prop, shrinker.run_copy_prop);
  bind("run_reg_alloc", shrinker.run_reg_alloc, shrinker.run_reg_alloc);
  bind("run_fast_reg_alloc", shrinker.run_fast_reg_alloc,
       shrinker.run_fast_reg_alloc);
  bind("run_local_dce", shrinker.run_local_dce, shrinker.run_local_dce);
  bind("no_inline_annos", {}, m_no_inline_annos);
  bind("force_inline_annos", {}, m_force_inline_annos);
  bind("blocklist", {}, m_blocklist);
  bind("blocklist", {}, m_blocklist);
  bind("caller_blocklist", {}, m_caller_blocklist);
  bind("intradex_allowlist", {}, m_intradex_allowlist,
       "The purpose of this white-list is to remove black-list entries when "
       "inlining after the InterDex pass has run. (This reduces the impact of "
       "black-list entries that avoid inlining conditional control-flow and "
       "catchers that cause issues with the SwitchMethodPartitioning analysis "
       "that tends to be used by passes that run before or during InterDex.)");
}

void OptDecisionsConfig::bind_config() {
  bind("enable_logs", false, enable_logs,
       "Should we log Redex's optimization decisions?");
}

void IRTypeCheckerConfig::bind_config() {
  bind("run_after_each_pass", {}, run_after_each_pass);
  bind("verify_moves", {}, verify_moves);
  bind("validate_invoke_super", {}, validate_invoke_super);
  bind("run_after_passes", {}, run_after_passes);
  bind("check_no_overwrite_this", {}, check_no_overwrite_this);
  bind("check_num_of_refs", {}, check_num_of_refs);
  bind("annotated_cfg_on_error", annotated_cfg_on_error,
       annotated_cfg_on_error);
}

void HasherConfig::bind_config() {
  bind("run_after_each_pass", {}, run_after_each_pass);
}

void AssessorConfig::bind_config() {
  bind("run_after_each_pass", run_after_each_pass, run_after_each_pass);
  bind("run_initially", run_initially, run_initially);
  bind("run_finally", run_finally, run_finally);
}

void CheckUniqueDeobfuscatedNamesConfig::bind_config() {
  bind("run_after_each_pass", run_after_each_pass, run_after_each_pass);
  bind("run_initially", run_initially, run_initially);
  bind("run_finally", run_finally, run_finally);
}

void MethodProfileOrderingConfig::bind_config() {
  bind("method_sorting_allowlisted_substrings",
       method_sorting_allowlisted_substrings,
       method_sorting_allowlisted_substrings);
  bind("min_appear_percent", min_appear_percent, min_appear_percent);
  bind("second_min_appear_percent", second_min_appear_percent,
       second_min_appear_percent);
  bind("skip_similarity_reordering", skip_similarity_reordering,
       skip_similarity_reordering);
}

void MethodSimilarityOrderingConfig::bind_config() {
  bind("use_class_level_perf_sensitivity", use_class_level_perf_sensitivity,
       use_class_level_perf_sensitivity);
  bind("disable", disable, disable);
}

void ProguardConfig::bind_config() {
  bind("blocklist", blocklist, blocklist);
  bind("disable_default_blocklist", disable_default_blocklist,
       disable_default_blocklist);
}

void PassManagerConfig::bind_config() {
  bind("pass_aliases", pass_aliases, pass_aliases);
}

void GlobalConfig::bind_config() {
  bool bool_param;
  std::string string_param;
  std::unordered_map<std::string, std::string> string_map_param;
  std::vector<std::string> string_vector_param;
  uint32_t uint32_param;
  // Sorted alphabetically
  bind("agg_method_stats_files", {}, string_vector_param);
  bind("android_sdk_api_15_file", "", string_param);
  bind("android_sdk_api_16_file", "", string_param);
  bind("android_sdk_api_17_file", "", string_param);
  bind("android_sdk_api_18_file", "", string_param);
  bind("android_sdk_api_19_file", "", string_param);
  bind("android_sdk_api_21_file", "", string_param);
  bind("android_sdk_api_23_file", "", string_param);
  bind("android_sdk_api_25_file", "", string_param);
  bind("android_sdk_api_26_file", "", string_param);
  bind("android_sdk_api_27_file", "", string_param);
  bind("android_sdk_api_28_file", "", string_param);
  bind("android_sdk_api_29_file", "", string_param);
  bind("bytecode_sort_mode", {}, string_vector_param);
  bind("coldstart_classes", "", string_param);
  bind("compute_xml_reachability", false, bool_param);
  bind("unused_keep_rule_abort", false, bool_param);
  bind("debug_info_kind", "", string_param);
  bind("default_coldstart_classes", "", string_param);
  bind("emit_class_method_info_map", false, bool_param);
  bind("emit_locator_strings", {}, bool_param);
  bind("iodi_layer_mode", "full", string_param,
       "IODI layer mode. One of \"full\", \"skip-layer-0-at-api-26\" or "
       "\"always-skip-layer-0\"");
  bind("symbolicate_detached_methods", false, bool_param);
  bind("enable_quickening", false, bool_param);
  bind("ab_experiments_states", {}, string_map_param);
  bind("ab_experiments_states_override", {}, string_map_param);
  bind("ab_experiments_default", "", string_param);
  bind("force_single_dex", false, bool_param);
  bind("emit_incoming_hashes", false, bool_param);
  bind("emit_outgoing_hashes", false, bool_param);
  bind("instruction_size_bitwidth_limit", 0u, uint32_param);
  bind("json_serde_supercls", {}, string_vector_param);
  bind("keep_all_annotation_classes", true, bool_param);
  bind("keep_methods", {}, string_vector_param);
  bind("keep_packages", {}, string_vector_param);
  bind("legacy_reflection_reachability", false, bool_param);
  bind("lower_with_cfg", {}, bool_param);
  bind("no_optimizations_annotations", {}, string_vector_param);
  bind("no_optimizations_blocklist", {}, string_vector_param);
  bind("proguard_map", "", string_param);
  bind("prune_unexported_components", {}, string_vector_param);
  bind("pure_methods", {}, string_vector_param);
  bind("finalish_field_names", {}, string_vector_param);
  bind("record_keep_reasons", {}, bool_param);
  bind("dump_keep_reasons", {}, bool_param);
  bind("string_sort_mode", "", string_param);
  bind("write_cfg_each_pass", false, bool_param);
  bind("dump_cfg_classes", "", string_param);
  bind("slow_invariants_debug", false, bool_param);
  // Enabled for ease of testing, apps expected to opt-out
  bind("enable_bleeding_edge_app_bundle_support", true, bool_param);
  bind("no_devirtualize_annos", {}, string_vector_param);
  bind("create_init_class_insns", true, bool_param);
  bind("finalize_resource_table", false, bool_param);

  for (const auto& entry : m_registry) {
    m_global_configs.emplace(entry.name,
                             entry.bind_operation(this, entry.name));
  }
}

GlobalConfigRegistryEntry::GlobalConfigRegistryEntry(
    const std::string& name, BindOperationFn bind_operation)
    : name(name), bind_operation(std::move(bind_operation)) {}

GlobalConfigRegistry& GlobalConfig::default_registry() {
  static GlobalConfigRegistry registry{
      register_as<InlinerConfig>("inliner"),
      register_as<IRTypeCheckerConfig>("ir_type_checker"),
      register_as<HasherConfig>("hasher"),
      register_as<AssessorConfig>("assessor"),
      register_as<CheckUniqueDeobfuscatedNamesConfig>(
          "check_unique_deobfuscated_names"),
      register_as<OptDecisionsConfig>("opt_decisions"),
      register_as<MethodProfileOrderingConfig>("method_profile_order"),
      register_as<MethodSimilarityOrderingConfig>("method_similarity_order"),
      register_as<ProguardConfig>("proguard"),
      register_as<PassManagerConfig>("pass_manager"),
  };
  return registry;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1999,2000 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"

#include "csengine/terrain.h"
#include "csengine/pol2d.h"
#include "csengine/texture.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "csterr/struct/ddgcntxt.h"
#include "csterr/struct/ddgtmesh.h"
#include "csterr/struct/ddgbtree.h"
#include "csterr/struct/ddgvarr.h"
#include "igraph3d.h"

IMPLEMENT_CSOBJTYPE (csTerrain,csObject);

csTerrain::csTerrain () : csObject()
{
  clipbox = NULL;
  heightMap = NULL;
  mesh = NULL;
  vbuf = NULL;
  _textureMap = NULL;
}

csTerrain::~csTerrain ()
{
  delete mesh;
  delete heightMap;
  delete clipbox;
  delete vbuf;
  delete _textureMap;
}

void csTerrain::SetDetail( unsigned int detail)
{
  mesh->minDetail(detail);
  mesh->maxDetail((unsigned int)(detail*1.1));
  mesh->absMaxDetail((unsigned int)(detail * 1.25));
  mesh->nearClip(1.0);
  mesh->farClip(150.0);
}

int csTerrain::GetNumTextures ()
{
  return mesh->getBinTreeNo ()/2;
}

bool csTerrain::Initialize (const void* heightMapFile, unsigned long size)
{
  heightMap = new ddgHeightMap ();
  if (heightMap->readTGN (heightMapFile, size))
    return false;

  mesh = new ddgTBinMesh (heightMap);
  clipbox = new ddgBBox (ddgVector3(0,0,3),ddgVector3(640, 480, 15000));
  context = new ddgContext ();

  vbuf = new ddgVArray ();

  mesh->init (context);

  vbuf->size((mesh->absMaxDetail()*3*11)/10);
  vbuf->init ();
  vbuf->reset ();
/*
JORRIT:  Create mesh->getBinTreeNo()/2  CS textures
         and put them in an array so I can reach them in the
		 Draw method.
		 This is probably not even the right place do this, perhaps
		 it is better done in csLoader.
		 I would suggest that in the world file syntax we derive the
		 the texture name from the heightMap file name eg.
		 myTerrain.TGN
		 has textures named:
		 myTerrain0.jpg
		 myTerrain1.jpg
		 ...
		 myTerrain128.jpg

	 Here is how DDG does it, but I use the ddgTexture class which is
	 openGL specific:
*/

  // We are going to get texture coords from the terrain engine
  // ranging from 0 to rows and 0 to cols.
  // CS wants them to range from 0 to 1.
  _pos = csVector3(0,0,0);
  _size = csVector3(heightMap->cols(),mesh->wheight(mesh->absMaxHeight()),heightMap->rows());

  // (15 May 2000) To Alex: This is new code that allocates the
  // texture array for the terrain.
  _textureMap = new csTextureHandle* [GetNumTextures ()];
  return true;
}

/**
 *  Retrieve info for a single triangle.
 *  Returns true if triangle should be rendered at all.
 */
bool csTerrain::drawTriangle( ddgTBinTree *bt, ddgVBIndex tvc, ddgVArray *vbuf )
{
	if ( !bt->visible(tvc))
		return ddgFailure;

    static ddgVector3 p1, p2, p3;
    static ddgColor3 c1, c2, c3;
    static ddgVector2 t1, t2, t3;
    unsigned int i1 = 0, i2 = 0, i3 = 0;

    ddgTriIndex
		tva = bt->parent(tvc),
		tv1 = bt->v0(tvc),
		tv0 = bt->v1(tvc);

    i1 = bt->vertex(tva,&p1);
    i2 = bt->vertex(tv0,&p2);
    i3 = bt->vertex(tv1,&p3);

	if (!i1) bt->textureC(tva,&t1);
	if (!i2) bt->textureC(tv0,&t2);
	if (!i3) bt->textureC(tv1,&t3);

    if (!i1) i1 = vbuf->pushVT(&p1,&t1);
    if (!i2) i2 = vbuf->pushVT(&p2,&t2);
    if (!i3) i3 = vbuf->pushVT(&p3,&t3);

    // Record that these vertices are in the buffer.
    bt->vbufferIndex(tva,i1);
    bt->vbufferIndex(tv0,i2);
    bt->vbufferIndex(tv1,i3);
    vbuf->pushTriangle(i1,i2,i3);

    return ddgSuccess;
}

void csTerrain::Draw (csRenderView& rview, bool /*use_z_buf*/)
{
  bool modified = true;
  /* Get matrices in OpenGL form
  JORRIT:
     this code is copied from the ogl_g3d renderer.
  csMatrix3 orientation = o2c.GetO2T();
  */
  // Alex: here it is I think:
  const csMatrix3& orientation = rview.GetO2T ();

  /*

  // set up coordinate transform
  GLfloat matrixholder[16];

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  // this zeroing is probably not needed, but I'm playing it safe in case
  // this code is changed later... GJH
  for (i=0; i<16; i++) matrixholder[i] = 0.0;

  matrixholder[0] = 1.0;
  matrixholder[5] = 1.0;
  matrixholder[10] = 1.0;

  matrixholder[0] = orientation.m11;
  matrixholder[1] = orientation.m21;
  matrixholder[2] = orientation.m31;

  matrixholder[4] = orientation.m12;
  matrixholder[5] = orientation.m22;
  matrixholder[6] = orientation.m32;

  matrixholder[8] = orientation.m13;
  matrixholder[9] = orientation.m23;
  matrixholder[10] = orientation.m33;

  matrixholder[15] = 1.0;

  csVector3 translation = o2c.GetO2TTranslation();

  glMultMatrixf(matrixholder);

  glTranslatef(-translation.x, -translation.y, -translation.z);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();

  glOrtho (0., (GLdouble) width, 0., (GLdouble) height, -1.0, 10.0);

  glTranslatef(width2,height2,0);

  for (i = 0 ; i < 16 ; i++)
    matrixholder[i] = 0.0;

  matrixholder[0] = matrixholder[5] = matrixholder[10] = matrixholder[15] = 1.0;

  matrixholder[10] = 0.0;
  matrixholder[11] = +1.0/aspect;
  matrixholder[14] = -1.0/aspect;
  matrixholder[15] = 0.0;

  glMultMatrixf(matrixholder);

*/
	context->extractPlanes(context->frustrum());
	// Optimize the mesh w.r.t. the current viewing location.
	modified = mesh->calculate(context);

  	unsigned int i = 0, s = 0;
	ddgTBinTree *bt;

	// If our orientation has changed, reload the buffer.
	if (modified)
	{
		vbuf->reset();
		// Update the vertex buffers.
		ddgCacheIndex ci = 0;
		while (i < mesh->getBinTreeNo())
		{
			if ((bt = mesh->getBinTree(i)))
			{
				s = 0;
				// Render each triangle.
				ci = bt->chain();
				// Render each triangle.
				while (ci)
				{
					ddgTNode *tn = (ddgTNode*) mesh->tcache()->get(ci);
 					if (drawTriangle(bt, tn->tindex(), vbuf) == ddgSuccess)
						s++;
					ci = tn->next();
				}
				bt->visTriangle(s);
			}
			i++;
		}

	}

    // Setup the structure for DrawTriangleMesh.
    static G3DTriangleMesh g3dmesh;
	static bool init = false;
	if (!init)
	{
		g3dmesh.vertex_colors[0] = NULL;			 // pointer to array of csColor for color information.
		g3dmesh.morph_factor = 0;
		g3dmesh.num_vertices_pool = 1;
		g3dmesh.num_textures = 1;
		g3dmesh.use_vertex_color = true;
		g3dmesh.do_clip = true;	// DEBUG THIS LATER
		g3dmesh.do_mirror = rview.IsMirrored ();
		g3dmesh.do_morph_texels = false;
		g3dmesh.do_morph_colors = false;
		g3dmesh.vertex_fog = NULL;
		g3dmesh.vertex_mode = G3DTriangleMesh::VM_WORLDSPACE;
		g3dmesh.fxmode = CS_FX_GOURAUD;
		init = true;
	}
    g3dmesh.num_vertices = vbuf->num();	  // number of shared vertices for all triangles
    // All the three below arrays have num_vertices elements.
    g3dmesh.vertices[0] = (csVector3*) vbuf->vbuf; // pointer to array of csVector3 for all those verts
    g3dmesh.texels[0][0] = (csVector2*) vbuf->tbuf;	 // pointer to array of csVector2 for uv coordinates

	// Render the vertex buffer piece by piece (per texture).
	i = 0;
	s = 0;
	while (i < mesh->getBinTreeNo())
	{
//	  if (_textureMap && (i%2 == 0) && _textureMap[i/2])
		g3dmesh.txt_handle[0] = _textureMap[i/2]->GetTextureHandle ();

		if ((bt = mesh->getBinTree(i)) && (bt->visTriangle() > 0))
		{
			// Render this bintree.
            g3dmesh.num_triangles = bt->visTriangle(); // number of triangles
            g3dmesh.triangles = (csTriangle *) &(vbuf->ibuf[s*3]);	// pointer to array of csTriangle for all triangles

            rview.g3d->DrawTriangleMesh (g3dmesh);

			s = s+bt->visTriangle();
		}
		i++;
	}

}

// If we hit this terrain adjust our position to be on top of it.
int csTerrain::CollisionDetect( csTransform *transform )
{
  float h;
  // Translate us into terrain coordinate space.
  csVector3 p = transform->GetOrigin () - _pos;
  // If our location is above or outside the terrain then we cannot hit is.
  if (p[0] < 0 || p[2] < 0 || p[0] > _size[0] || p[2] > _size[2] ||
      p[1]>_size[1])
    return 0;

  // Return height of terrain at this location in Y coord.
  h = mesh->height (p[0],p[2])+2;
  if (h < p[1])
    return 0;
  p[1] = h;
  // Translate us back.
  p = p + _pos;
  transform->SetOrigin (p);
  return 1;
}
<commit_msg>Disable gouraud shading.<commit_after>/*
    Copyright (C) 1999,2000 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"

#include "csengine/terrain.h"
#include "csengine/pol2d.h"
#include "csengine/texture.h"
#include "csgeom/math2d.h"
#include "csgeom/math3d.h"
#include "csgeom/polyclip.h"
#include "csterr/struct/ddgcntxt.h"
#include "csterr/struct/ddgtmesh.h"
#include "csterr/struct/ddgbtree.h"
#include "csterr/struct/ddgvarr.h"
#include "igraph3d.h"

IMPLEMENT_CSOBJTYPE (csTerrain,csObject);

csTerrain::csTerrain () : csObject()
{
  clipbox = NULL;
  heightMap = NULL;
  mesh = NULL;
  vbuf = NULL;
  _textureMap = NULL;
}

csTerrain::~csTerrain ()
{
  delete mesh;
  delete heightMap;
  delete clipbox;
  delete vbuf;
  delete _textureMap;
}

void csTerrain::SetDetail( unsigned int detail)
{
  mesh->minDetail(detail);
  mesh->maxDetail((unsigned int)(detail*1.1));
  mesh->absMaxDetail((unsigned int)(detail * 1.25));
  mesh->nearClip(1.0);
  mesh->farClip(150.0);
}

int csTerrain::GetNumTextures ()
{
  return mesh->getBinTreeNo ()/2;
}

bool csTerrain::Initialize (const void* heightMapFile, unsigned long size)
{
  heightMap = new ddgHeightMap ();
  if (heightMap->readTGN (heightMapFile, size))
    return false;

  mesh = new ddgTBinMesh (heightMap);
  clipbox = new ddgBBox (ddgVector3(0,0,3),ddgVector3(640, 480, 15000));
  context = new ddgContext ();

  vbuf = new ddgVArray ();

  mesh->init (context);

  vbuf->size((mesh->absMaxDetail()*3*11)/10);
  vbuf->init ();
  vbuf->reset ();
/*
JORRIT:  Create mesh->getBinTreeNo()/2  CS textures
         and put them in an array so I can reach them in the
		 Draw method.
		 This is probably not even the right place do this, perhaps
		 it is better done in csLoader.
		 I would suggest that in the world file syntax we derive the
		 the texture name from the heightMap file name eg.
		 myTerrain.TGN
		 has textures named:
		 myTerrain0.jpg
		 myTerrain1.jpg
		 ...
		 myTerrain128.jpg

	 Here is how DDG does it, but I use the ddgTexture class which is
	 openGL specific:
*/

  // We are going to get texture coords from the terrain engine
  // ranging from 0 to rows and 0 to cols.
  // CS wants them to range from 0 to 1.
  _pos = csVector3(0,0,0);
  _size = csVector3(heightMap->cols(),mesh->wheight(mesh->absMaxHeight()),heightMap->rows());

  // (15 May 2000) To Alex: This is new code that allocates the
  // texture array for the terrain.
  _textureMap = new csTextureHandle* [GetNumTextures ()];
  return true;
}

/**
 *  Retrieve info for a single triangle.
 *  Returns true if triangle should be rendered at all.
 */
bool csTerrain::drawTriangle( ddgTBinTree *bt, ddgVBIndex tvc, ddgVArray *vbuf )
{
	if ( !bt->visible(tvc))
		return ddgFailure;

    static ddgVector3 p1, p2, p3;
    static ddgColor3 c1, c2, c3;
    static ddgVector2 t1, t2, t3;
    unsigned int i1 = 0, i2 = 0, i3 = 0;

    ddgTriIndex
		tva = bt->parent(tvc),
		tv1 = bt->v0(tvc),
		tv0 = bt->v1(tvc);

    i1 = bt->vertex(tva,&p1);
    i2 = bt->vertex(tv0,&p2);
    i3 = bt->vertex(tv1,&p3);

	if (!i1) bt->textureC(tva,&t1);
	if (!i2) bt->textureC(tv0,&t2);
	if (!i3) bt->textureC(tv1,&t3);

    if (!i1) i1 = vbuf->pushVT(&p1,&t1);
    if (!i2) i2 = vbuf->pushVT(&p2,&t2);
    if (!i3) i3 = vbuf->pushVT(&p3,&t3);

    // Record that these vertices are in the buffer.
    bt->vbufferIndex(tva,i1);
    bt->vbufferIndex(tv0,i2);
    bt->vbufferIndex(tv1,i3);
    vbuf->pushTriangle(i1,i2,i3);

    return ddgSuccess;
}

void csTerrain::Draw (csRenderView& rview, bool /*use_z_buf*/)
{
  bool modified = true;
  /* Get matrices in OpenGL form
  JORRIT:
     this code is copied from the ogl_g3d renderer.
  csMatrix3 orientation = o2c.GetO2T();
  */
  // Alex: here it is I think:
  const csMatrix3& orientation = rview.GetO2T ();

  /*

  // set up coordinate transform
  GLfloat matrixholder[16];

  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  // this zeroing is probably not needed, but I'm playing it safe in case
  // this code is changed later... GJH
  for (i=0; i<16; i++) matrixholder[i] = 0.0;

  matrixholder[0] = 1.0;
  matrixholder[5] = 1.0;
  matrixholder[10] = 1.0;

  matrixholder[0] = orientation.m11;
  matrixholder[1] = orientation.m21;
  matrixholder[2] = orientation.m31;

  matrixholder[4] = orientation.m12;
  matrixholder[5] = orientation.m22;
  matrixholder[6] = orientation.m32;

  matrixholder[8] = orientation.m13;
  matrixholder[9] = orientation.m23;
  matrixholder[10] = orientation.m33;

  matrixholder[15] = 1.0;

  csVector3 translation = o2c.GetO2TTranslation();

  glMultMatrixf(matrixholder);

  glTranslatef(-translation.x, -translation.y, -translation.z);
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();

  glOrtho (0., (GLdouble) width, 0., (GLdouble) height, -1.0, 10.0);

  glTranslatef(width2,height2,0);

  for (i = 0 ; i < 16 ; i++)
    matrixholder[i] = 0.0;

  matrixholder[0] = matrixholder[5] = matrixholder[10] = matrixholder[15] = 1.0;

  matrixholder[10] = 0.0;
  matrixholder[11] = +1.0/aspect;
  matrixholder[14] = -1.0/aspect;
  matrixholder[15] = 0.0;

  glMultMatrixf(matrixholder);

*/
	context->extractPlanes(context->frustrum());
	// Optimize the mesh w.r.t. the current viewing location.
	modified = mesh->calculate(context);

  	unsigned int i = 0, s = 0;
	ddgTBinTree *bt;

	// If our orientation has changed, reload the buffer.
	if (modified)
	{
		vbuf->reset();
		// Update the vertex buffers.
		ddgCacheIndex ci = 0;
		while (i < mesh->getBinTreeNo())
		{
			if ((bt = mesh->getBinTree(i)))
			{
				s = 0;
				// Render each triangle.
				ci = bt->chain();
				// Render each triangle.
				while (ci)
				{
					ddgTNode *tn = (ddgTNode*) mesh->tcache()->get(ci);
 					if (drawTriangle(bt, tn->tindex(), vbuf) == ddgSuccess)
						s++;
					ci = tn->next();
				}
				bt->visTriangle(s);
			}
			i++;
		}

	}

    // Setup the structure for DrawTriangleMesh.
    static G3DTriangleMesh g3dmesh;
	static bool init = false;
	if (!init)
	{
		g3dmesh.vertex_colors[0] = NULL;			 // pointer to array of csColor for color information.
		g3dmesh.morph_factor = 0;
		g3dmesh.num_vertices_pool = 1;
		g3dmesh.num_textures = 1;
		g3dmesh.use_vertex_color = false;
		g3dmesh.do_clip = true;	// DEBUG THIS LATER
		g3dmesh.do_mirror = rview.IsMirrored ();
		g3dmesh.do_morph_texels = false;
		g3dmesh.do_morph_colors = false;
		g3dmesh.vertex_fog = NULL;
		g3dmesh.vertex_mode = G3DTriangleMesh::VM_WORLDSPACE;
		g3dmesh.fxmode = 0;//CS_FX_GOURAUD;
		init = true;
	}
    g3dmesh.num_vertices = vbuf->num();	  // number of shared vertices for all triangles
    // All the three below arrays have num_vertices elements.
    g3dmesh.vertices[0] = (csVector3*) vbuf->vbuf; // pointer to array of csVector3 for all those verts
    g3dmesh.texels[0][0] = (csVector2*) vbuf->tbuf;	 // pointer to array of csVector2 for uv coordinates

	// Render the vertex buffer piece by piece (per texture).
	i = 0;
	s = 0;
	while (i < mesh->getBinTreeNo())
	{
//	  if (_textureMap && (i%2 == 0) && _textureMap[i/2])
		g3dmesh.txt_handle[0] = _textureMap[i/2]->GetTextureHandle ();

		if ((bt = mesh->getBinTree(i)) && (bt->visTriangle() > 0))
		{
			// Render this bintree.
            g3dmesh.num_triangles = bt->visTriangle(); // number of triangles
            g3dmesh.triangles = (csTriangle *) &(vbuf->ibuf[s*3]);	// pointer to array of csTriangle for all triangles

            rview.g3d->DrawTriangleMesh (g3dmesh);

			s = s+bt->visTriangle();
		}
		i++;
	}

}

// If we hit this terrain adjust our position to be on top of it.
int csTerrain::CollisionDetect( csTransform *transform )
{
  float h;
  // Translate us into terrain coordinate space.
  csVector3 p = transform->GetOrigin () - _pos;
  // If our location is above or outside the terrain then we cannot hit is.
  if (p[0] < 0 || p[2] < 0 || p[0] > _size[0] || p[2] > _size[2] ||
      p[1]>_size[1])
    return 0;

  // Return height of terrain at this location in Y coord.
  h = mesh->height (p[0],p[2])+2;
  if (h < p[1])
    return 0;
  p[1] = h;
  // Translate us back.
  p = p + _pos;
  transform->SetOrigin (p);
  return 1;
}
<|endoftext|>


<commit_before>/*
 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>
#include "tm1637.h"

int
main(int argc, char **argv)
{
    uint8_t data[] = { 0xaa, 0xff, 0xff, 0xff };

    upm::TM1637 *display = new upm::TM1637(8, 9); // di - 8, dcki - 9
    display->write ("1981");

    std::cout << "exiting application" << std::endl;

    delete display;

    return 0;
}
<commit_msg>4digitdisplay.cxx: add Interesting tag and remove pointless array<commit_after>/*
 * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <unistd.h>
#include <iostream>
#include "tm1637.h"

int
main(int argc, char **argv)
{
    //! [Interesting]
    upm::TM1637 *display = new upm::TM1637(8, 9); // di - 8, dcki - 9
    display->write ("1337");
    //! [Interesting]

    std::cout << "exiting application" << std::endl;

    delete display;

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <QSoundEffect>
#include "cereal/gen/cpp/log.capnp.h"

typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;

static std::map<AudibleAlert, std::pair<const char *, int>> sound_map {
  // AudibleAlert, (file path, loop count)
  {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}},
  {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}},
  {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}},
  {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}},
  {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", 3}},
  {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", -1}},
  {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}},
  {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}}
};

class Sound {
public:
  Sound();
  void play(AudibleAlert alert);
  void stop();
  float volume = 0;

private:
  std::map<AudibleAlert, QSoundEffect> sounds;
};
<commit_msg>infinite orange alert sound (#20723)<commit_after>#pragma once

#include <map>
#include <QSoundEffect>
#include "cereal/gen/cpp/log.capnp.h"

typedef cereal::CarControl::HUDControl::AudibleAlert AudibleAlert;

static std::map<AudibleAlert, std::pair<const char *, int>> sound_map {
  // AudibleAlert, (file path, loop count)
  {AudibleAlert::CHIME_DISENGAGE, {"../assets/sounds/disengaged.wav", 0}},
  {AudibleAlert::CHIME_ENGAGE, {"../assets/sounds/engaged.wav", 0}},
  {AudibleAlert::CHIME_WARNING1, {"../assets/sounds/warning_1.wav", 0}},
  {AudibleAlert::CHIME_WARNING2, {"../assets/sounds/warning_2.wav", 0}},
  {AudibleAlert::CHIME_WARNING2_REPEAT, {"../assets/sounds/warning_2.wav", -1}},
  {AudibleAlert::CHIME_WARNING_REPEAT, {"../assets/sounds/warning_repeat.wav", -1}},
  {AudibleAlert::CHIME_ERROR, {"../assets/sounds/error.wav", 0}},
  {AudibleAlert::CHIME_PROMPT, {"../assets/sounds/error.wav", 0}}
};

class Sound {
public:
  Sound();
  void play(AudibleAlert alert);
  void stop();
  float volume = 0;

private:
  std::map<AudibleAlert, QSoundEffect> sounds;
};
<|endoftext|>