<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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 "Entity/Aspect.h"
#include "Ecs.h"

#include "Entity/Entity.h"
#include "Entity/Index.h"
#include "Entity/Archetype.h"
#include "System/SystemGroup.h"

#include <time.h>

DC_BEGIN_DREEMCHEST

namespace Ecs {

IMPLEMENT_LOGGER( log )

// -------------------------------------------------------------- Ecs -------------------------------------------------------------- //

// ** Ecs::Ecs
Ecs::Ecs( const EntityIdGeneratorPtr& entityIdGenerator ) : m_entityId( entityIdGenerator )
{
}

// ** Ecs::create
EcsPtr Ecs::create( const EntityIdGeneratorPtr& entityIdGenerator )
{
	DC_BREAK_IF( entityIdGenerator == EntityIdGeneratorPtr() );
	return DC_NEW Ecs( entityIdGenerator );
}

// ** Ecs::setEntityIdGenerator
void Ecs::setEntityIdGenerator( const EntityIdGeneratorPtr& value )
{
	m_entityId = value;
}

// ** Ecs::generateId
EntityId Ecs::generateId( void ) const
{
	EntityId id;

	do {
		id = m_entityId->generate();
	} while( isUsedId( id ) );

	return id;
}

// ** Ecs::addEntity
void Ecs::addEntity( EntityPtr entity )
{
	DC_BREAK_IF( !entity.valid() );

	const EntityId& id = entity->id();
	DC_BREAK_IF( isUsedId( id ) );

	// Setup entity
	entity->setEcs( this );

	// Register the entity
	m_entities[id] = entity;

	// Queue entity for notification.
	m_changed.insert( entity );
}

// ** Ecs::createArchetypeByName
ArchetypePtr Ecs::createArchetypeByName( const String& name, const EntityId& id, const Io::KeyValue& data ) const
{
	// Create archetype instance by name
	ArchetypePtr instance = m_archetypeFactory.construct( name );
	DC_BREAK_IF( !instance.valid() );

	// Ensure we found the archetype type
	if( !instance.valid() ) {
		log::error( "Ecs::createArchetypeByName : unknown archetype '%s'\n", name.c_str() );
		return ArchetypePtr();
	}

	// Initialize the entity id
	EntityId eid = id.isNull() ? generateId() : id;
	instance->setId( eid );

	// Construct the archetype
	instance->construct();

	// Set the parent ECS
	instance->setEcs( const_cast<Ecs*>( this ) );

	// Load from data
	if( !data.isNull() ) {
        SerializationContext ctx( const_cast<Ecs*>( this ) );
		instance->deserialize( ctx, data );
	}

	return instance;
}

// ** Ecs::createComponentByName
ComponentPtr Ecs::createComponentByName( const String& name, const Io::KeyValue& data ) const
{
	ComponentPtr instance = m_componentFactory.construct( name );
	DC_BREAK_IF( !instance.valid() );

	// Ensure we found the component type
	if( !instance.valid() ) {
		log::error( "Ecs::createComponentByName : unknown component '%s'\n", name.c_str() );
		return ComponentPtr();
	}

	// Load from data
	if( !data.isNull() ) {
        SerializationContext ctx( const_cast<Ecs*>( this ) );
		instance->deserialize( ctx, data );
	}

	return instance;
}

// ** Ecs::createEntity
EntityPtr Ecs::createEntity( const EntityId& id )
{
	DC_BREAK_IF( isUsedId( id ) );

	EntityPtr entity( DC_NEW Entity );
	entity->setId( id );
	//addEntity( entity );

	return entity;
}

// ** Ecs::createEntity
EntityPtr Ecs::createEntity( void )
{
	EntityId id = generateId();
	return createEntity( id );
}

// ** Ecs::cloneEntity
EntityPtr Ecs::cloneEntity( EntityWPtr entity )
{
    // Serialize source to a key-value archive
    Io::KeyValue ar;
    SerializationContext ctx( this );
    entity->serialize( ctx, ar );

    // Create entity instance
    EntityPtr instance = createEntity();

    // Deserialize
    instance->deserialize( ctx, ar );

    return instance;
}

// ** Ecs::findEntity
EntityPtr Ecs::findEntity( const EntityId& id ) const
{
	Entities::const_iterator i = m_entities.find( id );
	return i != m_entities.end() ? i->second : EntityPtr();
}

// ** Ecs::findByAspect
EntitySet Ecs::findByAspect( const Aspect& aspect ) const
{
	EntitySet result;

	for( Entities::const_iterator i = m_entities.begin(), end = m_entities.end(); i != end; ++i ) {
		if( aspect.hasIntersection( i->second ) ) {
			result.insert( i->second );
		}
	}

	return result;
}

// ** Ecs::removeEntity
void Ecs::removeEntity( const EntityId& id )
{
	DC_BREAK_IF( !isUsedId( id ) );

	Entities::iterator i = m_entities.find( id );

	if( i == m_entities.end() ) {
		return;
	}

	i->second->markAsRemoved();

	m_changed.insert( i->second );
	m_removed.insert( i->second );
}

// ** Ecs::isUsedId
bool Ecs::isUsedId( const EntityId& id ) const
{
	return m_entities.find( id ) != m_entities.end();
}

// ** Ecs::requestIndex
IndexPtr Ecs::requestIndex( const String& name, const Aspect& aspect )
{
	Indices::iterator i = m_indices.find( aspect );

	if( i != m_indices.end() ) {
		return i->second;
	}

	IndexPtr index( DC_NEW Index( this, name, aspect ) );
	m_indices[aspect] = index;

	return index;
}

// ** Ecs::createGroup
SystemGroupPtr Ecs::createGroup( const String& name, u32 mask )
{
	SystemGroupPtr group( DC_NEW SystemGroup( this, name, mask ) );
	m_systems.push_back( group );
	return group;
}

// ** Ecs::notifyEntityChanged
void Ecs::notifyEntityChanged( const EntityId& id )
{
	if( !isUsedId( id ) ) {
		log::error( "Ecs::notifyEntityChanged : no such entity ID %s\n", id.toString().c_str() );
		return;
	}

	Entities::iterator i = m_entities.find( id );

	if( i != m_entities.end() ) {
		m_changed.insert( i->second );
	}
}

// ** Ecs::rebuildSystems
void Ecs::rebuildSystems( void )
{
	// Process all entities
	for( Entities::iterator i = m_entities.begin(), end = m_entities.end(); i != end; ++i ) {
		// Notify each index
		for( Indices::iterator j = m_indices.begin(), jend = m_indices.end(); j != jend; j++ ) {
			j->second->notifyEntityChanged( i->second );
		}
	}
}

// ** Ecs::rebuildChangedEntities
void Ecs::rebuildChangedEntities( void )
{
	while( m_changed.size() ) {
		EntitySet changed = m_changed;
		m_changed.clear();

		for( EntitySet::iterator i = changed.begin(), end = changed.end(); i != end; ++i ) {
			for( Indices::iterator j = m_indices.begin(), jend = m_indices.end(); j != jend; j++ ) {
				j->second->notifyEntityChanged( *i );
			}
		}
	}
}

// ** Ecs::cleanupRemovedEntities
void Ecs::cleanupRemovedEntities( void )
{
	while( m_removed.size() ) {
		EntitySet removed = m_removed;
		m_removed.clear();

		for( EntitySet::iterator i = removed.begin(), end = removed.end(); i != end; ++i ) {
			m_entities.erase( (*i)->id() );
		}
	}
}

// ** Ecs::update
void Ecs::update( u32 currentTime, f32 dt, u32 systems )
{
	// Process all changed entities.
    rebuildChangedEntities();

	// Remove all queued entities
    cleanupRemovedEntities();

	// Update all system groups.
	for( u32 i = 0, n = ( u32 )m_systems.size(); i < n; i++ ) {
		SystemGroupPtr& group = m_systems[i];

		if( group->mask() & systems ) {
			group->update( currentTime, dt );
		}
	}
}

// ** EntityIdGenerator::EntityIdGenerator
EntityIdGenerator::EntityIdGenerator( void )
{
#if DC_ECS_INTEGER_IDS
	m_nextId = 1;
#else
	srand( static_cast<u32>( time( NULL ) ) );
#endif
}

// ** EntityIdGenerator::generate
EntityId EntityIdGenerator::generate( void )
{
#if DC_ECS_INTEGER_IDS
	return m_nextId++;
#else
	return Guid::generate();
#endif
}

// ---------------------------------------------------------- SerializationContext ---------------------------------------------------------- //

// ** SerializationContext::SerializationContext
SerializationContext::SerializationContext( EcsWPtr ecs ) : m_ecs( ecs )
{

}

// ** SerializationContext::ecs
EcsWPtr SerializationContext::ecs( void ) const
{
    return m_ecs;
}

// ** SerializationContext::findById
EntityPtr SerializationContext::findById( const EntityId& id ) const
{
    return m_ecs->findEntity( id );
}

// ** SerializationContext::createComponent
ComponentPtr SerializationContext::createComponent( const String& name ) const
{
    return m_ecs->createComponentByName( name );
}

// ** SerializationContext::createEntity
EntityPtr SerializationContext::createEntity( const String& name ) const
{
    if( name == "Entity" ) {
        return const_cast<SerializationContext*>( this )->m_ecs->createEntity();
    }

    return m_ecs->createArchetypeByName( name );
}

} // namespace Ecs

DC_END_DREEMCHEST<commit_msg>Removed: old assertion from Ecs::createEntity method<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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 "Entity/Aspect.h"
#include "Ecs.h"

#include "Entity/Entity.h"
#include "Entity/Index.h"
#include "Entity/Archetype.h"
#include "System/SystemGroup.h"

#include <time.h>

DC_BEGIN_DREEMCHEST

namespace Ecs {

IMPLEMENT_LOGGER( log )

// -------------------------------------------------------------- Ecs -------------------------------------------------------------- //

// ** Ecs::Ecs
Ecs::Ecs( const EntityIdGeneratorPtr& entityIdGenerator ) : m_entityId( entityIdGenerator )
{
}

// ** Ecs::create
EcsPtr Ecs::create( const EntityIdGeneratorPtr& entityIdGenerator )
{
	DC_BREAK_IF( entityIdGenerator == EntityIdGeneratorPtr() );
	return DC_NEW Ecs( entityIdGenerator );
}

// ** Ecs::setEntityIdGenerator
void Ecs::setEntityIdGenerator( const EntityIdGeneratorPtr& value )
{
	m_entityId = value;
}

// ** Ecs::generateId
EntityId Ecs::generateId( void ) const
{
	EntityId id;

	do {
		id = m_entityId->generate();
	} while( isUsedId( id ) );

	return id;
}

// ** Ecs::addEntity
void Ecs::addEntity( EntityPtr entity )
{
	DC_BREAK_IF( !entity.valid() );

	const EntityId& id = entity->id();
	DC_BREAK_IF( isUsedId( id ) );

	// Setup entity
	entity->setEcs( this );

	// Register the entity
	m_entities[id] = entity;

	// Queue entity for notification.
	m_changed.insert( entity );
}

// ** Ecs::createArchetypeByName
ArchetypePtr Ecs::createArchetypeByName( const String& name, const EntityId& id, const Io::KeyValue& data ) const
{
	// Create archetype instance by name
	ArchetypePtr instance = m_archetypeFactory.construct( name );
	DC_BREAK_IF( !instance.valid() );

	// Ensure we found the archetype type
	if( !instance.valid() ) {
		log::error( "Ecs::createArchetypeByName : unknown archetype '%s'\n", name.c_str() );
		return ArchetypePtr();
	}

	// Initialize the entity id
	EntityId eid = id.isNull() ? generateId() : id;
	instance->setId( eid );

	// Construct the archetype
	instance->construct();

	// Set the parent ECS
	instance->setEcs( const_cast<Ecs*>( this ) );

	// Load from data
	if( !data.isNull() ) {
        SerializationContext ctx( const_cast<Ecs*>( this ) );
		instance->deserialize( ctx, data );
	}

	return instance;
}

// ** Ecs::createComponentByName
ComponentPtr Ecs::createComponentByName( const String& name, const Io::KeyValue& data ) const
{
	ComponentPtr instance = m_componentFactory.construct( name );
	DC_BREAK_IF( !instance.valid() );

	// Ensure we found the component type
	if( !instance.valid() ) {
		log::error( "Ecs::createComponentByName : unknown component '%s'\n", name.c_str() );
		return ComponentPtr();
	}

	// Load from data
	if( !data.isNull() ) {
        SerializationContext ctx( const_cast<Ecs*>( this ) );
		instance->deserialize( ctx, data );
	}

	return instance;
}

// ** Ecs::createEntity
EntityPtr Ecs::createEntity( const EntityId& id )
{
	EntityPtr entity( DC_NEW Entity );
	entity->setId( id );
	//addEntity( entity );

	return entity;
}

// ** Ecs::createEntity
EntityPtr Ecs::createEntity( void )
{
	EntityId id = generateId();
	return createEntity( id );
}

// ** Ecs::cloneEntity
EntityPtr Ecs::cloneEntity( EntityWPtr entity )
{
    // Serialize source to a key-value archive
    Io::KeyValue ar;
    SerializationContext ctx( this );
    entity->serialize( ctx, ar );

    // Create entity instance
    EntityPtr instance = createEntity();

    // Deserialize
    instance->deserialize( ctx, ar );

    return instance;
}

// ** Ecs::findEntity
EntityPtr Ecs::findEntity( const EntityId& id ) const
{
	Entities::const_iterator i = m_entities.find( id );
	return i != m_entities.end() ? i->second : EntityPtr();
}

// ** Ecs::findByAspect
EntitySet Ecs::findByAspect( const Aspect& aspect ) const
{
	EntitySet result;

	for( Entities::const_iterator i = m_entities.begin(), end = m_entities.end(); i != end; ++i ) {
		if( aspect.hasIntersection( i->second ) ) {
			result.insert( i->second );
		}
	}

	return result;
}

// ** Ecs::removeEntity
void Ecs::removeEntity( const EntityId& id )
{
	DC_BREAK_IF( !isUsedId( id ) );

	Entities::iterator i = m_entities.find( id );

	if( i == m_entities.end() ) {
		return;
	}

	i->second->markAsRemoved();

	m_changed.insert( i->second );
	m_removed.insert( i->second );
}

// ** Ecs::isUsedId
bool Ecs::isUsedId( const EntityId& id ) const
{
	return m_entities.find( id ) != m_entities.end();
}

// ** Ecs::requestIndex
IndexPtr Ecs::requestIndex( const String& name, const Aspect& aspect )
{
	Indices::iterator i = m_indices.find( aspect );

	if( i != m_indices.end() ) {
		return i->second;
	}

	IndexPtr index( DC_NEW Index( this, name, aspect ) );
	m_indices[aspect] = index;

	return index;
}

// ** Ecs::createGroup
SystemGroupPtr Ecs::createGroup( const String& name, u32 mask )
{
	SystemGroupPtr group( DC_NEW SystemGroup( this, name, mask ) );
	m_systems.push_back( group );
	return group;
}

// ** Ecs::notifyEntityChanged
void Ecs::notifyEntityChanged( const EntityId& id )
{
	if( !isUsedId( id ) ) {
		log::error( "Ecs::notifyEntityChanged : no such entity ID %s\n", id.toString().c_str() );
		return;
	}

	Entities::iterator i = m_entities.find( id );

	if( i != m_entities.end() ) {
		m_changed.insert( i->second );
	}
}

// ** Ecs::rebuildSystems
void Ecs::rebuildSystems( void )
{
	// Process all entities
	for( Entities::iterator i = m_entities.begin(), end = m_entities.end(); i != end; ++i ) {
		// Notify each index
		for( Indices::iterator j = m_indices.begin(), jend = m_indices.end(); j != jend; j++ ) {
			j->second->notifyEntityChanged( i->second );
		}
	}
}

// ** Ecs::rebuildChangedEntities
void Ecs::rebuildChangedEntities( void )
{
	while( m_changed.size() ) {
		EntitySet changed = m_changed;
		m_changed.clear();

		for( EntitySet::iterator i = changed.begin(), end = changed.end(); i != end; ++i ) {
			for( Indices::iterator j = m_indices.begin(), jend = m_indices.end(); j != jend; j++ ) {
				j->second->notifyEntityChanged( *i );
			}
		}
	}
}

// ** Ecs::cleanupRemovedEntities
void Ecs::cleanupRemovedEntities( void )
{
	while( m_removed.size() ) {
		EntitySet removed = m_removed;
		m_removed.clear();

		for( EntitySet::iterator i = removed.begin(), end = removed.end(); i != end; ++i ) {
			m_entities.erase( (*i)->id() );
		}
	}
}

// ** Ecs::update
void Ecs::update( u32 currentTime, f32 dt, u32 systems )
{
	// Process all changed entities.
    rebuildChangedEntities();

	// Remove all queued entities
    cleanupRemovedEntities();

	// Update all system groups.
	for( u32 i = 0, n = ( u32 )m_systems.size(); i < n; i++ ) {
		SystemGroupPtr& group = m_systems[i];

		if( group->mask() & systems ) {
			group->update( currentTime, dt );
		}
	}
}

// ** EntityIdGenerator::EntityIdGenerator
EntityIdGenerator::EntityIdGenerator( void )
{
#if DC_ECS_INTEGER_IDS
	m_nextId = 1;
#else
	srand( static_cast<u32>( time( NULL ) ) );
#endif
}

// ** EntityIdGenerator::generate
EntityId EntityIdGenerator::generate( void )
{
#if DC_ECS_INTEGER_IDS
	return m_nextId++;
#else
	return Guid::generate();
#endif
}

// ---------------------------------------------------------- SerializationContext ---------------------------------------------------------- //

// ** SerializationContext::SerializationContext
SerializationContext::SerializationContext( EcsWPtr ecs ) : m_ecs( ecs )
{

}

// ** SerializationContext::ecs
EcsWPtr SerializationContext::ecs( void ) const
{
    return m_ecs;
}

// ** SerializationContext::findById
EntityPtr SerializationContext::findById( const EntityId& id ) const
{
    return m_ecs->findEntity( id );
}

// ** SerializationContext::createComponent
ComponentPtr SerializationContext::createComponent( const String& name ) const
{
    return m_ecs->createComponentByName( name );
}

// ** SerializationContext::createEntity
EntityPtr SerializationContext::createEntity( const String& name ) const
{
    if( name == "Entity" ) {
        return const_cast<SerializationContext*>( this )->m_ecs->createEntity();
    }

    return m_ecs->createArchetypeByName( name );
}

} // namespace Ecs

DC_END_DREEMCHEST<|endoftext|>


<commit_before>/*
 * RenderItemMergeFunction.hpp
 *
 *  Created on: Feb 16, 2009
 *      Author: struktured
 */

#ifndef RenderItemMergeFunction_HPP_
#define RenderItemMergeFunction_HPP_

#include "Common.hpp"s
#include "Renderable.hpp"
#include <limits>
#include <functional>
#include <map>

/// Merges two render items and returns zero if they are virtually equivalent and large values
/// when they are dissimilar. If two render items cannot be compared, NOT_COMPARABLE_VALUE is returned.
class RenderItemMergeFunction : public std::binary_function<const RenderItem*, const RenderItem*, RenderItem*> {
public:s
  virtual RenderItem * operator()(const RenderItem * r1, const RenderItem * r2) const = 0;
  virtual TypeIdPair typeIdPair() const = 0;
};

// A base class to construct render item distance mergeFunctions. Just specify your two concrete
// render item types as template parameters and override the computeMerge() function.
template <class R1, class R2=R1, class R3=R2>
class RenderItemMerge : public RenderItemMergeFunction {

protected:
// Override to create your own distance mergeFunction for your specified custom types.
virtual R3 * computeMerge(const R1 * r1, const R2 * r2) const = 0;

public:

inline virtual RenderItem * operator()(const RenderItem * r1, const RenderItem * r2) const {
	if (supported(r1, r2))
		return computeMerge(dynamic_cast<const R1*>(r1), dynamic_cast<const R2*>(r2));
	else if (supported(r2,r1))
		return computeMerge(dynamic_cast<const R1*>(r2), dynamic_cast<const R2*>(r1));
	else
		return 0;
}

// Returns true if and only if r1 and r2 are of type R1 and R2 respectively.
inline bool supported(const RenderItem * r1, const RenderItem * r2) const {
	return typeid(r1) == typeid(const R1 *) && typeid(r2) == typeid(const R2 *);
}

inline TypeIdPair typeIdPair() const {
	return TypeIdPair(typeid(const R1*).name(), typeid(const R2*).name());
}

};

/// EXAMPLE ONLY!!!
class ShapeXYMerge : public RenderItemMerge<Shape> {

public:

	ShapeXYMerge() {}
	virtual ~ShapeXYMerge() {}

protected:

	virtual inline Shape * computeMerge(const Shape * lhs, const Shape * rhs) const {

	    Shape * shape  = new Shape();
	    shape->x = (lhs->x + rhs->x)/2;
	    shape->y = (lhs->y + rhs->y)/2;
	    return shape;
	}

};

class MasterRenderItemMerge : public RenderItemMerge<RenderItem> {
s
typedef std::map<TypeIdPair, RenderItemMergeFunction*> MergeFunctionMap;
public:

	MasterRenderItemDistance() {}
	virtual ~MasterRenderItemDistance() {}

	inline void add(RenderItemMergeFunction * fun) {
		_mergeFunctionMap[fun->typeIdPair()] = fun;
	}

protected:
	virtual inline RenderItem * computeMerge(const RenderItem * lhs, const RenderItem * rhs) const {

		RenderItemMergeFunction * mergeFunction;

		TypeIdPair pair(typeid(lhs), typeid(rhs));
		if (_mergeFunctionMap.count(pair)) {
			mergeFunction = _mergeFunctionMap[pair];
		} else if (_mergeFunctionMap.count(pair = TypeIdPair(typeid(rhs), typeid(lhs)))) {
			mergeFunction = _mergeFunctionMap[pair];
		} else {
			mergeFunction  = 0;
		}

		// If specialized mergeFunction exists, use it to get higher granularity
		// of correctness
		if (mergeFunction)
			return (*mergeFunction)(lhs, rhs);
		else return 0;
	}

private:
	mutable MergeFunctionMap _mergeFunctionMap;
};

#endif /* RenderItemMergeFunction_HPP_ */
<commit_msg>name fixes<commit_after>/*
 * RenderItemMergeFunction.hpp
 *
 *  Created on: Feb 16, 2009
 *      Author: struktured
 */

#ifndef RenderItemMergeFunction_HPP_
#define RenderItemMergeFunction_HPP_

#include "Common.hpp"s
#include "Renderable.hpp"
#include <limits>
#include <functional>
#include <map>

/// Merges two render items and returns zero if they are virtually equivalent and large values
/// when they are dissimilar. If two render items cannot be compared, NOT_COMPARABLE_VALUE is returned.
class RenderItemMergeFunction : public std::binary_function<const RenderItem*, const RenderItem*, RenderItem*> {
public:s
  virtual RenderItem * operator()(const RenderItem * r1, const RenderItem * r2) const = 0;
  virtual TypeIdPair typeIdPair() const = 0;
};

// A base class to construct render item distance mergeFunctions. Just specify your two concrete
// render item types as template parameters and override the computeMerge() function.
template <class R1, class R2=R1, class R3=R2>
class RenderItemMerge : public RenderItemMergeFunction {

protected:
// Override to create your own distance mergeFunction for your specified custom types.
virtual R3 * computeMerge(const R1 * r1, const R2 * r2) const = 0;

public:

inline virtual RenderItem * operator()(const RenderItem * r1, const RenderItem * r2) const {
	if (supported(r1, r2))
		return computeMerge(dynamic_cast<const R1*>(r1), dynamic_cast<const R2*>(r2));
	else if (supported(r2,r1))
		return computeMerge(dynamic_cast<const R1*>(r2), dynamic_cast<const R2*>(r1));
	else
		return 0;
}

// Returns true if and only if r1 and r2 are of type R1 and R2 respectively.
inline bool supported(const RenderItem * r1, const RenderItem * r2) const {
	return typeid(r1) == typeid(const R1 *) && typeid(r2) == typeid(const R2 *);
}

inline TypeIdPair typeIdPair() const {
	return TypeIdPair(typeid(const R1*).name(), typeid(const R2*).name());
}

};

/// EXAMPLE ONLY!!!
class ShapeXYMerge : public RenderItemMerge<Shape> {

public:

	ShapeXYMerge() {}
	virtual ~ShapeXYMerge() {}

protected:

	virtual inline Shape * computeMerge(const Shape * lhs, const Shape * rhs) const {

	    Shape * shape  = new Shape();
	    shape->x = (lhs->x + rhs->x)/2;
	    shape->y = (lhs->y + rhs->y)/2;
	    return shape;
	}

};

class MasterRenderItemMerge : public RenderItemMerge<RenderItem> {

typedef std::map<TypeIdPair, RenderItemMergeFunction*> MergeFunctionMap;
public:

	MasterRenderItemMerge() {}
	virtual ~MasterRenderItemMerge() {}

	inline void add(RenderItemMergeFunction * fun) {
		_mergeFunctionMap[fun->typeIdPair()] = fun;
	}

protected:
	virtual inline RenderItem * computeMerge(const RenderItem * lhs, const RenderItem * rhs) const {

		RenderItemMergeFunction * mergeFunction;

		TypeIdPair pair(typeid(lhs), typeid(rhs));
		if (_mergeFunctionMap.count(pair)) {
			mergeFunction = _mergeFunctionMap[pair];
		} else if (_mergeFunctionMap.count(pair = TypeIdPair(typeid(rhs), typeid(lhs)))) {
			mergeFunction = _mergeFunctionMap[pair];
		} else {
			mergeFunction  = 0;
		}

		// If specialized mergeFunction exists, use it to get higher granularity
		// of correctness
		if (mergeFunction)
			return (*mergeFunction)(lhs, rhs);
		else return 0;
	}

private:
	mutable MergeFunctionMap _mergeFunctionMap;
};

#endif /* RenderItemMergeFunction_HPP_ */
<|endoftext|>


<commit_before>//===-- swift-demangle.cpp - Swift Demangler app ---------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the entry point.
//
//===----------------------------------------------------------------------===//

#include "swift/Basic/DemangleWrappers.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"

#include <string>

static llvm::cl::opt<bool>
ExpandMode("expand",
               llvm::cl::desc("Expand mode (show node structure of the demangling)"));

static llvm::cl::opt<bool>
CompactMode("compact",
          llvm::cl::desc("Compact mode (only emit the demangled names)"));

static llvm::cl::opt<bool>
TreeOnly("tree-only",
           llvm::cl::desc("Tree-only mode (do not show the demangled string)"));

static llvm::cl::opt<bool>
DisableSugar("no-sugar",
           llvm::cl::desc("No sugar mode (disable common language idioms such as ? and [] from the output)"));

static llvm::cl::list<std::string>
InputNames(llvm::cl::Positional, llvm::cl::desc("[mangled name...]"),
               llvm::cl::ZeroOrMore);

static void demangle(llvm::raw_ostream &os, llvm::StringRef name,
                     const swift::Demangle::DemangleOptions &options) {
  if (name.startswith("__"))
    name = name.substr(1);
  swift::Demangle::NodePointer pointer =
      swift::demangle_wrappers::demangleSymbolAsNode(name);
  if (ExpandMode) {
    llvm::outs() << "Demangling for " << name << '\n';
    swift::demangle_wrappers::NodeDumper(pointer).print(llvm::outs());
  }
  if (!TreeOnly) {
    std::string string = swift::Demangle::nodeToString(pointer, options);
    if (!CompactMode)
      llvm::outs() << name << " ---> ";
    llvm::outs() << (string.empty() ? name : llvm::StringRef(string));
  }
}

static llvm::StringRef substrBefore(llvm::StringRef whole,
                                    llvm::StringRef part) {
  return whole.slice(0, part.data() - whole.data());
}

static llvm::StringRef substrAfter(llvm::StringRef whole,
                                   llvm::StringRef part) {
  return whole.substr((part.data() - whole.data()) + part.size());
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm::cl::ParseCommandLineOptions(argc, argv);

  swift::Demangle::DemangleOptions options;
  options.SynthesizeSugarOnTypes = !DisableSugar;

  if (InputNames.empty()) {
    CompactMode = true;
    auto input = llvm::MemoryBuffer::getSTDIN();
    if (!input) {
      llvm::errs() << input.getError().message() << '\n';
      return EXIT_FAILURE;
    }
    llvm::StringRef inputContents = input.get()->getBuffer();

    // This doesn't handle Unicode symbols, but maybe that's okay.
    llvm::Regex maybeSymbol("_T[_a-zA-Z0-9]+");
    llvm::SmallVector<llvm::StringRef, 1> matches;
    while (maybeSymbol.match(inputContents, &matches)) {
      llvm::outs() << substrBefore(inputContents, matches.front());
      demangle(llvm::outs(), matches.front(), options);
      inputContents = substrAfter(inputContents, matches.front());
    }
    llvm::outs() << inputContents;

  } else {
    for (llvm::StringRef name : InputNames) {
      demangle(llvm::outs(), name, options);
      llvm::outs() << '\n';
    }
  }

  return EXIT_SUCCESS;
}
<commit_msg>The --tree-only option to swift-demangle was not doing what it promised to do, instead refusing to print anything. Fix it<commit_after>//===-- swift-demangle.cpp - Swift Demangler app ---------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the entry point.
//
//===----------------------------------------------------------------------===//

#include "swift/Basic/DemangleWrappers.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"

#include <string>

static llvm::cl::opt<bool>
ExpandMode("expand",
               llvm::cl::desc("Expand mode (show node structure of the demangling)"));

static llvm::cl::opt<bool>
CompactMode("compact",
          llvm::cl::desc("Compact mode (only emit the demangled names)"));

static llvm::cl::opt<bool>
TreeOnly("tree-only",
           llvm::cl::desc("Tree-only mode (do not show the demangled string)"));

static llvm::cl::opt<bool>
DisableSugar("no-sugar",
           llvm::cl::desc("No sugar mode (disable common language idioms such as ? and [] from the output)"));

static llvm::cl::list<std::string>
InputNames(llvm::cl::Positional, llvm::cl::desc("[mangled name...]"),
               llvm::cl::ZeroOrMore);

static void demangle(llvm::raw_ostream &os, llvm::StringRef name,
                     const swift::Demangle::DemangleOptions &options) {
  if (name.startswith("__"))
    name = name.substr(1);
  swift::Demangle::NodePointer pointer =
      swift::demangle_wrappers::demangleSymbolAsNode(name);
  if (ExpandMode || TreeOnly) {
    llvm::outs() << "Demangling for " << name << '\n';
    swift::demangle_wrappers::NodeDumper(pointer).print(llvm::outs());
  }
  if (!TreeOnly) {
    std::string string = swift::Demangle::nodeToString(pointer, options);
    if (!CompactMode)
      llvm::outs() << name << " ---> ";
    llvm::outs() << (string.empty() ? name : llvm::StringRef(string));
  }
}

static llvm::StringRef substrBefore(llvm::StringRef whole,
                                    llvm::StringRef part) {
  return whole.slice(0, part.data() - whole.data());
}

static llvm::StringRef substrAfter(llvm::StringRef whole,
                                   llvm::StringRef part) {
  return whole.substr((part.data() - whole.data()) + part.size());
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm::cl::ParseCommandLineOptions(argc, argv);

  swift::Demangle::DemangleOptions options;
  options.SynthesizeSugarOnTypes = !DisableSugar;

  if (InputNames.empty()) {
    CompactMode = true;
    auto input = llvm::MemoryBuffer::getSTDIN();
    if (!input) {
      llvm::errs() << input.getError().message() << '\n';
      return EXIT_FAILURE;
    }
    llvm::StringRef inputContents = input.get()->getBuffer();

    // This doesn't handle Unicode symbols, but maybe that's okay.
    llvm::Regex maybeSymbol("_T[_a-zA-Z0-9]+");
    llvm::SmallVector<llvm::StringRef, 1> matches;
    while (maybeSymbol.match(inputContents, &matches)) {
      llvm::outs() << substrBefore(inputContents, matches.front());
      demangle(llvm::outs(), matches.front(), options);
      inputContents = substrAfter(inputContents, matches.front());
    }
    llvm::outs() << inputContents;

  } else {
    for (llvm::StringRef name : InputNames) {
      demangle(llvm::outs(), name, options);
      llvm::outs() << '\n';
    }
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * NotebookAlternateEngines.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "SessionExecuteChunkOperation.hpp"
#include "NotebookCache.hpp"
#include "NotebookAlternateEngines.hpp"

#include <boost/algorithm/string.hpp>

#include <core/StringUtils.hpp>
#include <core/Algorithm.hpp>
#include <core/Exec.hpp>
#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

namespace {

class ChunkExecCompletedScope : boost::noncopyable
{
public:
   ChunkExecCompletedScope(const std::string& docId,
                           const std::string& chunkId)
      : docId_(docId), chunkId_(chunkId)
   {
   }

   ~ChunkExecCompletedScope()
   {
      events().onChunkExecCompleted(
               docId_,
               chunkId_,
               notebookCtxId());
   }

private:
   std::string docId_;
   std::string chunkId_;
};

Error prepareCacheConsoleOutputFile(const std::string& docId,
                                    const std::string& chunkId,
                                    const std::string& nbCtxId,
                                    FilePath* pChunkOutputFile)
{
   // forward declare error
   Error error;

   // prepare chunk directory
   FilePath cachePath = notebook::chunkOutputPath(
            docId,
            chunkId,
            notebook::ContextExact);

   error = cachePath.resetDirectory();
   if (error)
      return error;

   // prepare cache console output file
   *pChunkOutputFile =
         notebook::chunkOutputFile(docId, chunkId, nbCtxId, ChunkOutputText);

   return Success();
}

void chunkConsoleOutputHandler(module_context::ConsoleOutputType type,
                               const std::string& output,
                               const FilePath& targetPath)
{
   using namespace module_context;

   Error error = appendConsoleOutput(
            type == ConsoleOutputNormal ? kChunkConsoleOutput : kChunkConsoleError,
            output,
            targetPath);
   if (error)
      LOG_ERROR(error);
}

void reportChunkExecutionError(const std::string& docId,
                               const std::string& chunkId,
                               const std::string& nbCtxId,
                               const std::string& message,
                               const FilePath& targetPath)
{
   // emit chunk error
   chunkConsoleOutputHandler(
            module_context::ConsoleOutputError,
            message,
            targetPath);

   // forward failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            nbCtxId,
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);
}

Error executeRcppEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const std::map<std::string, std::string>& options)
{
   // forward declare error
   Error error;

   // always ensure we emit a 'execution complete' event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

   // prepare cache output file (use tempfile on failure)
   FilePath targetPath = module_context::tempFile("rcpp-cache", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &targetPath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        targetPath));

   // call Rcpp::sourceCpp on code
   std::string escaped = boost::regex_replace(
            code,
            boost::regex("(\\\\|\")"),
            "\\\\$1");

   std::string execCode =
         "Rcpp::sourceCpp(code = \"" + escaped + "\")";

   // write input code to cache
   error = appendConsoleOutput(
            kChunkConsoleInput,
            code,
            targetPath);
   if (error)
      LOG_ERROR(error);

   // execute code (output captured on success; on failure we
   // explicitly forward the error message returned)
   error = r::exec::executeString(execCode);
   if (error)
   {
      chunkConsoleOutputHandler(module_context::ConsoleOutputError,
                                r::endUserErrorMessage(error),
                                targetPath);
   }

   // forward success / failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            nbCtxId,
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);

   return error;
}

void reportStanExecutionError(const std::string& docId,
                              const std::string& chunkId,
                              const std::string& nbCtxId,
                              const FilePath& targetPath)
{
   std::string message =
         "engine.opts$x must be a character string providing a "
         "name for the returned `stanmodel` object";
   reportChunkExecutionError(docId, chunkId, nbCtxId, message, targetPath);
}

Error executeStanEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const std::map<std::string, std::string>& options)
{
   // forward-declare error
   Error error;

   // ensure we always emit an execution complete event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

   // prepare console output file -- use tempfile on failure
   FilePath targetPath = module_context::tempFile("stan-cache-", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &targetPath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        targetPath));

   // write code to file
   FilePath tempFile = module_context::tempFile("stan-", ".stan");
   error = writeStringToFile(tempFile, code);
   if (error)
   {
      reportChunkExecutionError(
               docId,
               chunkId,
               nbCtxId,
               r::endUserErrorMessage(error),
               targetPath);
      LOG_ERROR(error);
      return Success();
   }
   RemoveOnExitScope removeOnExitScope(tempFile, ERROR_LOCATION);

   // ensure existence of 'engine.opts' with 'x' parameter
   if (!options.count("engine.opts"))
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // evaluate engine options (so we can pass them through to stan call)
   r::sexp::Protect protect;
   SEXP engineOptsSEXP = R_NilValue;
   error = r::exec::evaluateString(
            options.at("engine.opts"),
            &engineOptsSEXP,
            &protect);

   if (error)
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // construct call to 'stan_model'
   r::exec::RFunction fStanEngine("rstan:::stan_model");
   std::vector<std::string> engineOptsNames;
   error = r::sexp::getNames(engineOptsSEXP, &engineOptsNames);
   if (error)
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // build parameters
   std::string modelName;
   for (std::size_t i = 0, n = r::sexp::length(engineOptsSEXP); i < n; ++i)
   {
      // skip 'x' engine option (this is the variable we wish to assign to
      // after evaluating the stan model)
      if (engineOptsNames[i] == "x")
      {
         modelName = r::sexp::asString(VECTOR_ELT(engineOptsSEXP, i));
         continue;
      }

      fStanEngine.addParam(
               engineOptsNames[i],
               VECTOR_ELT(engineOptsSEXP, i));
   }

   // if no model name was set, return error message
   if (modelName.empty())
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // if the 'file' option was not set, set it explicitly
   if (!core::algorithm::contains(engineOptsNames, "file"))
      fStanEngine.addParam("file", string_utils::utf8ToSystem(tempFile.absolutePath()));

   // evaluate stan_model call
   SEXP stanModelSEXP = R_NilValue;
   error = fStanEngine.call(&stanModelSEXP, &protect);
   if (error)
   {
      std::string msg = r::endUserErrorMessage(error);
      reportChunkExecutionError(docId, chunkId, nbCtxId, msg, targetPath);
      return Success();
   }

   // assign in global env on success
   if (stanModelSEXP != R_NilValue)
   {
      r::exec::RFunction assign("base:::assign");
      assign.addParam("x", modelName);
      assign.addParam("value", stanModelSEXP);
      error = assign.call();
      if (error)
      {
         std::string msg = r::endUserErrorMessage(error);
         reportChunkExecutionError(docId, chunkId, nbCtxId, msg, targetPath);
         LOG_ERROR(error);
         return Success();
      }
   }

   // forward success / failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            notebookCtxId(),
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);

   return Success();
}

Error executeSqlEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const json::Object& options)
{
   Error error;

   // ensure we always emit an execution complete event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

      // prepare console output file -- use tempfile on failure
   FilePath consolePath = module_context::tempFile("data-console-", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &consolePath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        consolePath));

   FilePath parentPath = notebook::chunkOutputPath(
       docId, chunkId, nbCtxId, ContextSaved);
   error = parentPath.ensureDirectory();
   if (error)
   {
      std::string message = "Failed to create SQL chunk directory";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, parentPath);

      return Success();
   }

   FilePath dataPath =
         notebook::chunkOutputFile(docId, chunkId, nbCtxId, ChunkOutputData);

   // check package dependencies
   if (!module_context::isPackageVersionInstalled("DBI", "0.4"))
   {
      std::string message = "Executing SQL chunks requires version 0.4 or "
                            "later of the DBI package";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, consolePath);
      return Success();
   }

   // run sql and save result
   error = r::exec::RFunction(
               ".rs.runSqlForDataCapture",
               code,
               string_utils::utf8ToSystem(dataPath.absolutePath()),
               options).call();
   if (error)
   {
      std::string message = "Failed to execute SQL chunk";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, consolePath);

      return Success();
   }

   if (dataPath.exists()) {
      // forward success / failure to chunk
      enqueueChunkOutput(
               docId,
               chunkId,
               notebookCtxId(),
               0, // no ordinal needed
               ChunkOutputData,
               dataPath);
   }

   // forward console output
   enqueueChunkOutput(
            docId,
            chunkId,
            notebookCtxId(),
            0, // no ordinal needed
            ChunkOutputText,
            consolePath);

   return Success();
}

Error interruptEngineChunk(const json::JsonRpcRequest& request,
                           json::JsonRpcResponse* pResponse)
{
   std::string docId, chunkId;
   Error error = json::readParams(request.params,
                                  &docId,
                                  &chunkId);
   if (error)
   {
      LOG_ERROR(error);
      return error;
   }

   interruptChunk(docId, chunkId);
   return Success();
}

} // anonymous namespace

Error executeAlternateEngineChunk(const std::string& docId,
                                  const std::string& chunkId,
                                  const std::string& nbCtxId,
                                  const std::string& engine,
                                  const std::string& code,
                                  const json::Object& jsonChunkOptions)
{
   // read json chunk options
   std::map<std::string, std::string> options;
   for (json::Object::const_iterator it = jsonChunkOptions.begin();
        it != jsonChunkOptions.end();
        ++it)
   {
      if (it->second.type() == json::StringType)
         options[it->first] = it->second.get_str();
   }

   // handle Rcpp specially
   if (engine == "Rcpp")
      return executeRcppEngineChunk(docId, chunkId, nbCtxId, code, options);
   else if (engine == "stan")
      return executeStanEngineChunk(docId, chunkId, nbCtxId, code, options);
   else if (engine == "sql")
      return executeSqlEngineChunk(docId, chunkId, nbCtxId, code, jsonChunkOptions);

   runChunk(docId, chunkId, nbCtxId, engine, code);
   return Success();
}

Error initAlternateEngines()
{
   using namespace module_context;

   ExecBlock initBlock;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "interrupt_chunk", interruptEngineChunk));
   return initBlock.execute();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<commit_msg>allow both 'output.var' and 'x' for specifying model name<commit_after>/*
 * NotebookAlternateEngines.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "SessionExecuteChunkOperation.hpp"
#include "NotebookCache.hpp"
#include "NotebookAlternateEngines.hpp"

#include <boost/algorithm/string.hpp>

#include <core/StringUtils.hpp>
#include <core/Algorithm.hpp>
#include <core/Exec.hpp>
#include <core/json/JsonRpc.hpp>

#include <r/RExec.hpp>

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

namespace {

class ChunkExecCompletedScope : boost::noncopyable
{
public:
   ChunkExecCompletedScope(const std::string& docId,
                           const std::string& chunkId)
      : docId_(docId), chunkId_(chunkId)
   {
   }

   ~ChunkExecCompletedScope()
   {
      events().onChunkExecCompleted(
               docId_,
               chunkId_,
               notebookCtxId());
   }

private:
   std::string docId_;
   std::string chunkId_;
};

Error prepareCacheConsoleOutputFile(const std::string& docId,
                                    const std::string& chunkId,
                                    const std::string& nbCtxId,
                                    FilePath* pChunkOutputFile)
{
   // forward declare error
   Error error;

   // prepare chunk directory
   FilePath cachePath = notebook::chunkOutputPath(
            docId,
            chunkId,
            notebook::ContextExact);

   error = cachePath.resetDirectory();
   if (error)
      return error;

   // prepare cache console output file
   *pChunkOutputFile =
         notebook::chunkOutputFile(docId, chunkId, nbCtxId, ChunkOutputText);

   return Success();
}

void chunkConsoleOutputHandler(module_context::ConsoleOutputType type,
                               const std::string& output,
                               const FilePath& targetPath)
{
   using namespace module_context;

   Error error = appendConsoleOutput(
            type == ConsoleOutputNormal ? kChunkConsoleOutput : kChunkConsoleError,
            output,
            targetPath);
   if (error)
      LOG_ERROR(error);
}

void reportChunkExecutionError(const std::string& docId,
                               const std::string& chunkId,
                               const std::string& nbCtxId,
                               const std::string& message,
                               const FilePath& targetPath)
{
   // emit chunk error
   chunkConsoleOutputHandler(
            module_context::ConsoleOutputError,
            message,
            targetPath);

   // forward failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            nbCtxId,
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);
}

Error executeRcppEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const std::map<std::string, std::string>& options)
{
   // forward declare error
   Error error;

   // always ensure we emit a 'execution complete' event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

   // prepare cache output file (use tempfile on failure)
   FilePath targetPath = module_context::tempFile("rcpp-cache", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &targetPath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        targetPath));

   // call Rcpp::sourceCpp on code
   std::string escaped = boost::regex_replace(
            code,
            boost::regex("(\\\\|\")"),
            "\\\\$1");

   std::string execCode =
         "Rcpp::sourceCpp(code = \"" + escaped + "\")";

   // write input code to cache
   error = appendConsoleOutput(
            kChunkConsoleInput,
            code,
            targetPath);
   if (error)
      LOG_ERROR(error);

   // execute code (output captured on success; on failure we
   // explicitly forward the error message returned)
   error = r::exec::executeString(execCode);
   if (error)
   {
      chunkConsoleOutputHandler(module_context::ConsoleOutputError,
                                r::endUserErrorMessage(error),
                                targetPath);
   }

   // forward success / failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            nbCtxId,
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);

   return error;
}

void reportStanExecutionError(const std::string& docId,
                              const std::string& chunkId,
                              const std::string& nbCtxId,
                              const FilePath& targetPath)
{
   std::string message =
         "engine.opts$output.var must be a character string providing a "
         "name for the returned `stanmodel` object";
   reportChunkExecutionError(docId, chunkId, nbCtxId, message, targetPath);
}

Error executeStanEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const std::map<std::string, std::string>& options)
{
   // forward-declare error
   Error error;

   // ensure we always emit an execution complete event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

   // prepare console output file -- use tempfile on failure
   FilePath targetPath = module_context::tempFile("stan-cache-", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &targetPath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        targetPath));

   // write code to file
   FilePath tempFile = module_context::tempFile("stan-", ".stan");
   error = writeStringToFile(tempFile, code);
   if (error)
   {
      reportChunkExecutionError(
               docId,
               chunkId,
               nbCtxId,
               r::endUserErrorMessage(error),
               targetPath);
      LOG_ERROR(error);
      return Success();
   }
   RemoveOnExitScope removeOnExitScope(tempFile, ERROR_LOCATION);

   // ensure existence of 'engine.opts' with 'output.var' parameter
   // ('x' also allowed for backwards compatibility)
   if (!options.count("engine.opts"))
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // evaluate engine options (so we can pass them through to stan call)
   r::sexp::Protect protect;
   SEXP engineOptsSEXP = R_NilValue;
   error = r::exec::evaluateString(
            options.at("engine.opts"),
            &engineOptsSEXP,
            &protect);

   if (error)
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // construct call to 'stan_model'
   r::exec::RFunction fStanEngine("rstan:::stan_model");
   std::vector<std::string> engineOptsNames;
   error = r::sexp::getNames(engineOptsSEXP, &engineOptsNames);
   if (error)
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // build parameters
   std::string modelName;
   for (std::size_t i = 0, n = r::sexp::length(engineOptsSEXP); i < n; ++i)
   {
      // skip 'output.var' engine option (this is the variable we wish to assign to
      // after evaluating the stan model)
      if (engineOptsNames[i] == "output.var" || engineOptsNames[i] == "x")
      {
         modelName = r::sexp::asString(VECTOR_ELT(engineOptsSEXP, i));
         continue;
      }

      fStanEngine.addParam(
               engineOptsNames[i],
               VECTOR_ELT(engineOptsSEXP, i));
   }

   // if no model name was set, return error message
   if (modelName.empty())
   {
      reportStanExecutionError(docId, chunkId, nbCtxId, targetPath);
      return Success();
   }

   // if the 'file' option was not set, set it explicitly
   if (!core::algorithm::contains(engineOptsNames, "file"))
      fStanEngine.addParam("file", string_utils::utf8ToSystem(tempFile.absolutePath()));

   // evaluate stan_model call
   SEXP stanModelSEXP = R_NilValue;
   error = fStanEngine.call(&stanModelSEXP, &protect);
   if (error)
   {
      std::string msg = r::endUserErrorMessage(error);
      reportChunkExecutionError(docId, chunkId, nbCtxId, msg, targetPath);
      return Success();
   }

   // assign in global env on success
   if (stanModelSEXP != R_NilValue)
   {
      r::exec::RFunction assign("base:::assign");
      assign.addParam("x", modelName);
      assign.addParam("value", stanModelSEXP);
      error = assign.call();
      if (error)
      {
         std::string msg = r::endUserErrorMessage(error);
         reportChunkExecutionError(docId, chunkId, nbCtxId, msg, targetPath);
         LOG_ERROR(error);
         return Success();
      }
   }

   // forward success / failure to chunk
   enqueueChunkOutput(
            docId,
            chunkId,
            notebookCtxId(),
            0, // no ordinal needed
            ChunkOutputText,
            targetPath);

   return Success();
}

Error executeSqlEngineChunk(const std::string& docId,
                             const std::string& chunkId,
                             const std::string& nbCtxId,
                             const std::string& code,
                             const json::Object& options)
{
   Error error;

   // ensure we always emit an execution complete event on exit
   ChunkExecCompletedScope execScope(docId, chunkId);

      // prepare console output file -- use tempfile on failure
   FilePath consolePath = module_context::tempFile("data-console-", "");
   error = prepareCacheConsoleOutputFile(docId, chunkId, nbCtxId, &consolePath);
   if (error)
      LOG_ERROR(error);

   // capture console output, error
   boost::signals::scoped_connection consoleHandler =
         module_context::events().onConsoleOutput.connect(
            boost::bind(chunkConsoleOutputHandler,
                        _1,
                        _2,
                        consolePath));

   FilePath parentPath = notebook::chunkOutputPath(
       docId, chunkId, nbCtxId, ContextSaved);
   error = parentPath.ensureDirectory();
   if (error)
   {
      std::string message = "Failed to create SQL chunk directory";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, parentPath);

      return Success();
   }

   FilePath dataPath =
         notebook::chunkOutputFile(docId, chunkId, nbCtxId, ChunkOutputData);

   // check package dependencies
   if (!module_context::isPackageVersionInstalled("DBI", "0.4"))
   {
      std::string message = "Executing SQL chunks requires version 0.4 or "
                            "later of the DBI package";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, consolePath);
      return Success();
   }

   // run sql and save result
   error = r::exec::RFunction(
               ".rs.runSqlForDataCapture",
               code,
               string_utils::utf8ToSystem(dataPath.absolutePath()),
               options).call();
   if (error)
   {
      std::string message = "Failed to execute SQL chunk";
      reportChunkExecutionError(docId, chunkId, nbCtxId, message, consolePath);

      return Success();
   }

   if (dataPath.exists()) {
      // forward success / failure to chunk
      enqueueChunkOutput(
               docId,
               chunkId,
               notebookCtxId(),
               0, // no ordinal needed
               ChunkOutputData,
               dataPath);
   }

   // forward console output
   enqueueChunkOutput(
            docId,
            chunkId,
            notebookCtxId(),
            0, // no ordinal needed
            ChunkOutputText,
            consolePath);

   return Success();
}

Error interruptEngineChunk(const json::JsonRpcRequest& request,
                           json::JsonRpcResponse* pResponse)
{
   std::string docId, chunkId;
   Error error = json::readParams(request.params,
                                  &docId,
                                  &chunkId);
   if (error)
   {
      LOG_ERROR(error);
      return error;
   }

   interruptChunk(docId, chunkId);
   return Success();
}

} // anonymous namespace

Error executeAlternateEngineChunk(const std::string& docId,
                                  const std::string& chunkId,
                                  const std::string& nbCtxId,
                                  const std::string& engine,
                                  const std::string& code,
                                  const json::Object& jsonChunkOptions)
{
   // read json chunk options
   std::map<std::string, std::string> options;
   for (json::Object::const_iterator it = jsonChunkOptions.begin();
        it != jsonChunkOptions.end();
        ++it)
   {
      if (it->second.type() == json::StringType)
         options[it->first] = it->second.get_str();
   }

   // handle Rcpp specially
   if (engine == "Rcpp")
      return executeRcppEngineChunk(docId, chunkId, nbCtxId, code, options);
   else if (engine == "stan")
      return executeStanEngineChunk(docId, chunkId, nbCtxId, code, options);
   else if (engine == "sql")
      return executeSqlEngineChunk(docId, chunkId, nbCtxId, code, jsonChunkOptions);

   runChunk(docId, chunkId, nbCtxId, engine, code);
   return Success();
}

Error initAlternateEngines()
{
   using namespace module_context;

   ExecBlock initBlock;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "interrupt_chunk", interruptEngineChunk));
   return initBlock.execute();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<|endoftext|>


<commit_before>//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements a clang-check tool that runs clang based on the info
//  stored in a compilation database.
//
//  This tool uses the Clang Tooling infrastructure, see
//    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
//  for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTConsumer.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"

using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp MoreHelp(
    "\tFor example, to run clang-check on all files in a subtree of the\n"
    "\tsource tree, use:\n"
    "\n"
    "\t  find path/in/subtree -name '*.cpp'|xargs clang-check\n"
    "\n"
    "\tor using a specific build path:\n"
    "\n"
    "\t  find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
    "\n"
    "\tNote, that path/in/subtree and current directory should follow the\n"
    "\trules described above.\n"
    "\n"
);

static cl::OptionCategory ClangCheckCategory("clang-check options");
static std::unique_ptr<opt::OptTable> Options(createDriverOptTable());
static cl::opt<bool>
ASTDump("ast-dump", cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)),
        cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTList("ast-list", cl::desc(Options->getOptionHelpText(options::OPT_ast_list)),
        cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTPrint("ast-print",
         cl::desc(Options->getOptionHelpText(options::OPT_ast_print)),
         cl::cat(ClangCheckCategory));
static cl::opt<std::string> ASTDumpFilter(
    "ast-dump-filter",
    cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)),
    cl::cat(ClangCheckCategory));
static cl::opt<bool>
Analyze("analyze", cl::desc(Options->getOptionHelpText(options::OPT_analyze)),
        cl::cat(ClangCheckCategory));

static cl::opt<bool>
Fixit("fixit", cl::desc(Options->getOptionHelpText(options::OPT_fixit)),
      cl::cat(ClangCheckCategory));
static cl::opt<bool> FixWhatYouCan(
    "fix-what-you-can",
    cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
    cl::cat(ClangCheckCategory));

namespace {

// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
// into a header file and reuse that.
class FixItOptions : public clang::FixItOptions {
public:
  FixItOptions() {
    FixWhatYouCan = ::FixWhatYouCan;
  }

  std::string RewriteFilename(const std::string& filename, int &fd) override {
    assert(llvm::sys::path::is_absolute(filename) &&
           "clang-fixit expects absolute paths only.");

    // We don't need to do permission checking here since clang will diagnose
    // any I/O errors itself.

    fd = -1;  // No file descriptor for file.

    return filename;
  }
};

/// Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
/// in the final error counts.
///
/// This has the side-effect that clang-check -fixit exits with code 0 on
/// successfully fixing all errors.
class FixItRewriter : public clang::FixItRewriter {
public:
  FixItRewriter(clang::DiagnosticsEngine& Diags,
                clang::SourceManager& SourceMgr,
                const clang::LangOptions& LangOpts,
                clang::FixItOptions* FixItOpts)
      : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
  }

  bool IncludeInDiagnosticCounts() const override { return false; }
};

/// Subclasses \c clang::FixItAction so that we can install the custom
/// \c FixItRewriter.
class FixItAction : public clang::FixItAction {
public:
  bool BeginSourceFileAction(clang::CompilerInstance& CI) override {
    FixItOpts.reset(new FixItOptions);
    Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
                                     CI.getLangOpts(), FixItOpts.get()));
    return true;
  }
};

class ClangCheckActionFactory {
public:
  std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
    if (ASTList)
      return clang::CreateASTDeclNodeLister();
    if (ASTDump)
      return clang::CreateASTDumper(nullptr /*Dump to stdout.*/,
                                    ASTDumpFilter,
                                    /*DumpDecls=*/true,
                                    /*Deserialize=*/false,
                                    /*DumpLookups=*/false);
    if (ASTPrint)
      return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
    return llvm::make_unique<clang::ASTConsumer>();
  }
};

} // namespace

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

  // Initialize targets for clang module support.
  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllAsmParsers();

  CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory);
  ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());

  // Clear adjusters because -fsyntax-only is inserted by the default chain.
  Tool.clearArgumentsAdjusters();
  Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());

  // Running the analyzer requires --analyze. Other modes can work with the
  // -fsyntax-only option.
  Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
      Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));

  ClangCheckActionFactory CheckFactory;
  std::unique_ptr<FrontendActionFactory> FrontendFactory;

  // Choose the correct factory based on the selected mode.
  if (Analyze)
    FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
  else if (Fixit)
    FrontendFactory = newFrontendActionFactory<FixItAction>();
  else
    FrontendFactory = newFrontendActionFactory(&CheckFactory);

  return Tool.run(FrontendFactory.get());
}
<commit_msg>clang-check: rename the local FixItAction<commit_after>//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements a clang-check tool that runs clang based on the info
//  stored in a compilation database.
//
//  This tool uses the Clang Tooling infrastructure, see
//    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
//  for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTConsumer.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"

using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp MoreHelp(
    "\tFor example, to run clang-check on all files in a subtree of the\n"
    "\tsource tree, use:\n"
    "\n"
    "\t  find path/in/subtree -name '*.cpp'|xargs clang-check\n"
    "\n"
    "\tor using a specific build path:\n"
    "\n"
    "\t  find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
    "\n"
    "\tNote, that path/in/subtree and current directory should follow the\n"
    "\trules described above.\n"
    "\n"
);

static cl::OptionCategory ClangCheckCategory("clang-check options");
static std::unique_ptr<opt::OptTable> Options(createDriverOptTable());
static cl::opt<bool>
ASTDump("ast-dump", cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)),
        cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTList("ast-list", cl::desc(Options->getOptionHelpText(options::OPT_ast_list)),
        cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTPrint("ast-print",
         cl::desc(Options->getOptionHelpText(options::OPT_ast_print)),
         cl::cat(ClangCheckCategory));
static cl::opt<std::string> ASTDumpFilter(
    "ast-dump-filter",
    cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)),
    cl::cat(ClangCheckCategory));
static cl::opt<bool>
Analyze("analyze", cl::desc(Options->getOptionHelpText(options::OPT_analyze)),
        cl::cat(ClangCheckCategory));

static cl::opt<bool>
Fixit("fixit", cl::desc(Options->getOptionHelpText(options::OPT_fixit)),
      cl::cat(ClangCheckCategory));
static cl::opt<bool> FixWhatYouCan(
    "fix-what-you-can",
    cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
    cl::cat(ClangCheckCategory));

namespace {

// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
// into a header file and reuse that.
class FixItOptions : public clang::FixItOptions {
public:
  FixItOptions() {
    FixWhatYouCan = ::FixWhatYouCan;
  }

  std::string RewriteFilename(const std::string& filename, int &fd) override {
    assert(llvm::sys::path::is_absolute(filename) &&
           "clang-fixit expects absolute paths only.");

    // We don't need to do permission checking here since clang will diagnose
    // any I/O errors itself.

    fd = -1;  // No file descriptor for file.

    return filename;
  }
};

/// Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
/// in the final error counts.
///
/// This has the side-effect that clang-check -fixit exits with code 0 on
/// successfully fixing all errors.
class FixItRewriter : public clang::FixItRewriter {
public:
  FixItRewriter(clang::DiagnosticsEngine& Diags,
                clang::SourceManager& SourceMgr,
                const clang::LangOptions& LangOpts,
                clang::FixItOptions* FixItOpts)
      : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
  }

  bool IncludeInDiagnosticCounts() const override { return false; }
};

/// Subclasses \c clang::FixItAction so that we can install the custom
/// \c FixItRewriter.
class ClangCheckFixItAction : public clang::FixItAction {
public:
  bool BeginSourceFileAction(clang::CompilerInstance& CI) override {
    FixItOpts.reset(new FixItOptions);
    Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
                                     CI.getLangOpts(), FixItOpts.get()));
    return true;
  }
};

class ClangCheckActionFactory {
public:
  std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
    if (ASTList)
      return clang::CreateASTDeclNodeLister();
    if (ASTDump)
      return clang::CreateASTDumper(nullptr /*Dump to stdout.*/,
                                    ASTDumpFilter,
                                    /*DumpDecls=*/true,
                                    /*Deserialize=*/false,
                                    /*DumpLookups=*/false);
    if (ASTPrint)
      return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
    return llvm::make_unique<clang::ASTConsumer>();
  }
};

} // namespace

int main(int argc, const char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);

  // Initialize targets for clang module support.
  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllAsmParsers();

  CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory);
  ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());

  // Clear adjusters because -fsyntax-only is inserted by the default chain.
  Tool.clearArgumentsAdjusters();
  Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());

  // Running the analyzer requires --analyze. Other modes can work with the
  // -fsyntax-only option.
  Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
      Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));

  ClangCheckActionFactory CheckFactory;
  std::unique_ptr<FrontendActionFactory> FrontendFactory;

  // Choose the correct factory based on the selected mode.
  if (Analyze)
    FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
  else if (Fixit)
    FrontendFactory = newFrontendActionFactory<ClangCheckFixItAction>();
  else
    FrontendFactory = newFrontendActionFactory(&CheckFactory);

  return Tool.run(FrontendFactory.get());
}
<|endoftext|>


<commit_before>//Run some very rudimentary tests on this random number generator.

#include "FibRng.h"
#include <stdio.h>

void main(int argc, char * argv[])
{
    FibRng gen;
    uint32_t bins[6] = { 0, 0, 0, 0, 0, 0 };

    for (int i = 0; i < 100000000; i++)
    {
        bins[gen.dice(6)]++;
    }

    for (int i = 0; i < 6; i++)
    {
        printf("Bin %d = %u \n", i+1, bins[i]);
    }

    //gen.dump();
    printf("Done\n");

}
<commit_msg>Added value compatibility test that fails.<commit_after>//Run some very rudimentary tests on this random number generator.

#include "FibRng.h"
#include <stdio.h>

void main(int argc, char * argv[])
{
    printf("Starting Bin Test.\n");

    FibRng gen;
    uint32_t bins[6] = { 0, 0, 0, 0, 0, 0 };

    for (int i = 0; i < 100000000; i++)
    {
        bins[gen.dice(6)]++;
    }

    for (int i = 0; i < 6; i++)
    {
        printf("Bin %d = %u \n", i+1, bins[i]);
    }

    //gen.dump();
    printf("Done Bin Test.\n");

    // Test from Ruby used to make sure incompatibilities do not creep in.
    // expected = [184, 93,   0, 240,  34, 184,   4, 220, 126, 132,
    //              13, 67, 166, 107, 165,  66,  68, 120, 102, 110,
    //             212, 99,  80, 167,   9,  56,  47, 167, 127, 195,
    //             169, 34, 184,  97, 136, 176, 214, 104, 218, 103,
    //             180, 16,  83, 204, 128,  81,  63,  56, 237, 165,
    //               0, 88, 129,  40, 152,  44, 189,  35, 205, 249,
    //              77, 94, 142,  18,  60, 248,  49, 172, 235,  83,
    //              84, 65, 181, 117,  16, 170, 222,  97, 130, 217]
    //
    // prng = FibonacciRng.new("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5")
    // result = Array.new(80){ prng.byte }
    //
    // assert_equal(expected, result)

    printf("\n\nStarting Value Test.\n");

    int expected[80] =
    {
        184, 93, 0, 240, 34, 184, 4, 220, 126, 132,
        13, 67, 166, 107, 165, 66, 68, 120, 102, 110,
        212, 99, 80, 167, 9, 56, 47, 167, 127, 195,
        169, 34, 184, 97, 136, 176, 214, 104, 218, 103,
        180, 16, 83, 204, 128, 81, 63, 56, 237, 165,
        0, 88, 129, 40, 152, 44, 189, 35, 205, 249,
        77, 94, 142, 18, 60, 248, 49, 172, 235, 83,
        84, 65, 181, 117, 16, 170, 222, 97, 130, 217
    };

    int result[80];
    FibRng test("%s*08^_Tg{NnirtZ-94)q9z2l+~bB5");
    int errors = 0;

    for (int i = 0; i < 80; i++)
    {
        result[i] = test.byte();

        if (expected[i] != result[i])
            errors++;
    }

    if (errors == 0)
        printf("Equal, no errors detected.\n");
    else
    {
        printf("Different %d times\n\n", errors);

        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 10; j++)
                printf("%4d", expected[10 * i + j]);

            printf("\n");

            for (int j = 0; j < 10; j++)
                printf("%4d", result[10 * i + j]);

            printf("\n\n");
        }
    }

    printf("Done Value Test.\n");

}
<|endoftext|>


<commit_before><commit_msg>harden lispsm code against div-by-zero <commit_after><|endoftext|>