<commit_before>#include <bts/app/application.hpp>
#include <bts/app/plugin.hpp>
#include <bts/app/api.hpp>

#include <bts/net/core_messages.hpp>

#include <bts/chain/time.hpp>

#include <fc/rpc/api_connection.hpp>
#include <fc/rpc/websocket_api.hpp>

namespace bts { namespace app {
using net::item_hash_t;
using net::item_id;
using net::message;
using net::block_message;
using net::trx_message;

using chain::block;
using chain::block_id_type;

using std::vector;

namespace detail {

   class application_impl : public net::node_delegate
   {
      void reset_p2p_node(const fc::path& data_dir, const application::daemon_configuration& cfg)
      {
         _p2p_network = std::make_shared<net::node>("Graphene Reference Implementation");

         _p2p_network->load_configuration(data_dir / "p2p");
         _p2p_network->set_node_delegate(this);

         for( const fc::ip::endpoint& node : cfg.seed_nodes )
         {
            ilog("Adding seed node ${ip}", ("ip", node));
            _p2p_network->add_node(node);
            _p2p_network->connect_to_endpoint(node);
         }

         _p2p_network->listen_on_port(cfg.p2p_endpoint.port(), true);
         _p2p_network->listen_to_p2p_network();
         ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint()));

         _p2p_network->connect_to_p2p_network();
         _p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type,
                                              _chain_db->head_block_id()),
                                 std::vector<uint32_t>());
      }

      void reset_websocket_server(const application::daemon_configuration& cfg)
      {
         _websocket_server = std::make_shared<fc::http::websocket_server>();

         _websocket_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
            auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
            auto login = std::make_shared<bts::app::login_api>( std::ref(*_self) );
            wsc->register_api(fc::api<bts::app::login_api>(login));
            c->set_session_data( wsc );
         });
         _websocket_server->listen( cfg.websocket_endpoint );
         _websocket_server->start_accept();
      }

      void initialize_configuration()
      {
         _configuration["daemon"] = application::daemon_configuration();
         save_configuration();
      }

   public:
      void save_configuration()
      {
         fc::json::save_to_file(_configuration, _data_dir/"config.json");
      }

      application_impl(application* self)
         : _self(self),
           _chain_db(std::make_shared<chain::database>())
      {
      }

      void configure( const fc::path& data_dir )
      {
         _data_dir = data_dir,
         _chain_db->open(data_dir / "blockchain");
         if( fc::exists(data_dir / "config.json") ) {
            try {
               _configuration = fc::json::from_file(data_dir / "config.json").as<application::config>();
            } catch( fc::exception& e ) {
               elog("Failed to read config file:\n${e}", ("e", e.to_detail_string()));
               initialize_configuration();
            }
         } else {
            initialize_configuration();
         }
         for( const auto& p : _plugins )
            p.second->init();

         auto daemon_config = _configuration["daemon"].as<application::daemon_configuration>();
         reset_p2p_node(data_dir, daemon_config);
         reset_websocket_server(daemon_config);
      }

      void apply_configuration()
      { try {
         save_configuration();

         auto daemon_config = _configuration["daemon"].as<application::daemon_configuration>();
         reset_p2p_node(_data_dir, daemon_config);
         reset_websocket_server(daemon_config);
      } FC_CAPTURE_AND_RETHROW() }

      /**
       *  If delegate has the item, the network has no need to fetch it.
       */
      virtual bool has_item( const net::item_id& id ) override
      { try {
          if( id.item_type == bts::net::block_message_type )
          {
             return _chain_db->is_known_block( id.item_hash );
          }
          else
          {
             return _chain_db->is_known_transaction( id.item_hash );
          }
      } FC_CAPTURE_AND_RETHROW( (id) ) }

      /**
       *  @brief allows the application to validate an item prior to
       *         broadcasting to peers.
       *
       *  @param sync_mode true if the message was fetched through the sync process, false during normal operation
       *  @returns true if this message caused the blockchain to switch forks, false if it did not
       *
       *  @throws exception if error validating the item, otherwise the item is
       *          safe to broadcast on.
       */
      virtual bool handle_block( const bts::net::block_message& blk_msg, bool sync_mode ) override
      { try {
         ilog("Got block #${n} from network", ("n", blk_msg.block.block_num()));
         try {
            return _chain_db->push_block( blk_msg.block );
         } catch( const fc::exception& e ) {
            elog("Error when pushing block:\n${e}", ("e", e.to_detail_string()));
            throw;
         }
      } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) }

      virtual bool handle_transaction( const bts::net::trx_message& trx_msg, bool sync_mode ) override
      { try {
         ilog("Got transaction from network");
         _chain_db->push_transaction( trx_msg.trx );
         return false;
      } FC_CAPTURE_AND_RETHROW( (trx_msg)(sync_mode) ) }

      /**
       *  Assuming all data elements are ordered in some way, this method should
       *  return up to limit ids that occur *after* the last ID in synopsis that
       *  we recognize.
       *
       *  On return, remaining_item_count will be set to the number of items
       *  in our blockchain after the last item returned in the result,
       *  or 0 if the result contains the last item in the blockchain
       */
      virtual std::vector<item_hash_t> get_item_ids(uint32_t item_type,
                                                    const std::vector<item_hash_t>& blockchain_synopsis,
                                                    uint32_t& remaining_item_count,
                                                    uint32_t limit ) override
      { try {
         FC_ASSERT( item_type == bts::net::block_message_type );
         vector<block_id_type>  result;
         remaining_item_count = 0;
         if( _chain_db->head_block_num() == 0 )
            return result;

         result.reserve(limit);
         block_id_type last_known_block_id;
         auto itr = blockchain_synopsis.rbegin();
         while( itr != blockchain_synopsis.rend() )
         {
            if( _chain_db->is_known_block( *itr ) || *itr == block_id_type() )
            {
               last_known_block_id = *itr;
               break;
            }
            ++itr;
         }

         for( auto num = block::num_from_id(last_known_block_id);
              num <= _chain_db->head_block_num() && result.size() < limit;
              ++num )
            if( num > 0 )
               result.push_back(_chain_db->get_block_id_for_num(num));

         if( block::num_from_id(result.back()) < _chain_db->head_block_num() )
            remaining_item_count = _chain_db->head_block_num() - block::num_from_id(result.back());

         idump((blockchain_synopsis)(limit)(result)(remaining_item_count));
         return result;
      } FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) }

      /**
       *  Given the hash of the requested data, fetch the body.
       */
      virtual message get_item( const item_id& id ) override
      { try {
         ilog("Request for item ${id}", ("id", id));
         if( id.item_type == bts::net::block_message_type )
         {
            auto opt_block = _chain_db->fetch_block_by_id( id.item_hash );
            if( !opt_block )
               elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}",
                    ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block::num_from_id(id.item_hash))));
            FC_ASSERT( opt_block.valid() );
            ilog("Serving up block #${num}", ("num", opt_block->block_num()));
            return block_message( std::move(*opt_block) );
         }
         return trx_message( _chain_db->get_recent_transaction( id.item_hash ) );
      } FC_CAPTURE_AND_RETHROW( (id) ) }

      virtual fc::sha256 get_chain_id()const override
      {
         return fc::sha256();
      }

      /**
       * Returns a synopsis of the blockchain used for syncing.
       * This consists of a list of selected item hashes from our current preferred
       * blockchain, exponentially falling off into the past.  Horrible explanation.
       *
       * If the blockchain is empty, it will return the empty list.
       * If the blockchain has one block, it will return a list containing just that block.
       * If it contains more than one block:
       *   the first element in the list will be the hash of the genesis block
       *   the second element will be the hash of an item at the half way point in the blockchain
       *   the third will be ~3/4 of the way through the block chain
       *   the fourth will be at ~7/8...
       *     &c.
       *   the last item in the list will be the hash of the most recent block on our preferred chain
       */
      virtual std::vector<item_hash_t> get_blockchain_synopsis( uint32_t item_type,
                                                                const bts::net::item_hash_t& reference_point,
                                                                uint32_t number_of_blocks_after_reference_point ) override
      { try {
         std::vector<item_hash_t> result;
         result.reserve(30);
         auto head_block_num = _chain_db->head_block_num();
         result.push_back( _chain_db->head_block_id() );
         auto current = 1;
         while( current < head_block_num )
         {
            result.push_back( _chain_db->get_block_id_for_num( head_block_num - current ) );
            current = current*2;
         }
         std::reverse( result.begin(), result.end() );
         idump((reference_point)(number_of_blocks_after_reference_point)(result));
         return result;
      } FC_CAPTURE_AND_RETHROW( (reference_point)(number_of_blocks_after_reference_point) ) }

      /**
       *  Call this after the call to handle_message succeeds.
       *
       *  @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
       *  @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
       *                    After `item_count` more calls to handle_item(), the node will be in sync
       */
      virtual void     sync_status( uint32_t item_type, uint32_t item_count ) override
      {
         // any status reports to GUI go here
      }

      /**
       *  Call any time the number of connected peers changes.
       */
      virtual void     connection_count_changed( uint32_t c ) override
      {
        // any status reports to GUI go here
      }

      virtual uint32_t get_block_number(const item_hash_t& block_id) override
      { try {
         return block::num_from_id(block_id);
      } FC_CAPTURE_AND_RETHROW( (block_id) ) }

      /**
       * Returns the time a block was produced (if block_id = 0, returns genesis time).
       * If we don't know about the block, returns time_point_sec::min()
       */
      virtual fc::time_point_sec get_block_time(const item_hash_t& block_id) override
      { try {
         auto opt_block = _chain_db->fetch_block_by_id( block_id );
         if( opt_block.valid() ) return opt_block->timestamp;
         return fc::time_point_sec::min();
      } FC_CAPTURE_AND_RETHROW( (block_id) ) }

      /** returns bts::blockchain::now() */
      virtual fc::time_point_sec get_blockchain_now() override
      {
         return bts::chain::now();
      }

      virtual item_hash_t get_head_block_id() const override
      {
         return _chain_db->head_block_id();
      }

      virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override
      {
         return 0; // there are no forks in graphene
      }

      virtual void error_encountered(const std::string& message, const fc::oexception& error) override
      {
         // notify GUI or something cool
      }

      application* _self;

      fc::path _data_dir;

      std::shared_ptr<bts::chain::database>        _chain_db;
      std::shared_ptr<bts::net::node>              _p2p_network;
      std::shared_ptr<fc::http::websocket_server>  _websocket_server;
      application::config                          _configuration;

      std::map<string, std::shared_ptr<abstract_plugin>> _plugins;
   };

}

application::application()
   : my(new detail::application_impl(this))
{}

application::~application()
{
   if( my->_p2p_network )
   {
      ilog("Closing p2p node");
      my->_p2p_network->close();
   }
   if( my->_chain_db )
   {
      ilog("Closing chain database");
      my->_chain_db->close();
   }
}

void application::configure( const fc::path& data_dir )
{
   my->configure( data_dir );
}

std::shared_ptr<abstract_plugin> application::get_plugin(const string& name) const
{
   return my->_plugins[name];
}

application::config& application::configuration()
{
   return my->_configuration;
}

const application::config& application::configuration() const
{
   return my->_configuration;
}

void application::apply_configuration()
{
   my->apply_configuration();
}

void application::save_configuration() const
{
   my->save_configuration();
}

net::node_ptr application::p2p_node()
{
   return my->_p2p_network;
}

std::shared_ptr<chain::database> application::chain_database() const
{
   return my->_chain_db;
}

void bts::app::application::add_plugin(const string& name, std::shared_ptr<bts::app::abstract_plugin> p)
{
   my->_plugins[name] = p;
}

// namespace detail
} }
<commit_msg>fix whitespace<commit_after>#include <bts/app/application.hpp>
#include <bts/app/plugin.hpp>
#include <bts/app/api.hpp>

#include <bts/net/core_messages.hpp>

#include <bts/chain/time.hpp>

#include <fc/rpc/api_connection.hpp>
#include <fc/rpc/websocket_api.hpp>

namespace bts { namespace app {
using net::item_hash_t;
using net::item_id;
using net::message;
using net::block_message;
using net::trx_message;

using chain::block;
using chain::block_id_type;

using std::vector;

namespace detail {

   class application_impl : public net::node_delegate
   {
      void reset_p2p_node(const fc::path& data_dir, const application::daemon_configuration& cfg)
      {
         _p2p_network = std::make_shared<net::node>("Graphene Reference Implementation");

         _p2p_network->load_configuration(data_dir / "p2p");
         _p2p_network->set_node_delegate(this);

         for( const fc::ip::endpoint& node : cfg.seed_nodes )
         {
            ilog("Adding seed node ${ip}", ("ip", node));
            _p2p_network->add_node(node);
            _p2p_network->connect_to_endpoint(node);
         }

         _p2p_network->listen_on_port(cfg.p2p_endpoint.port(), true);
         _p2p_network->listen_to_p2p_network();
         ilog("Configured p2p node to listen on ${ip}", ("ip", _p2p_network->get_actual_listening_endpoint()));

         _p2p_network->connect_to_p2p_network();
         _p2p_network->sync_from(net::item_id(net::core_message_type_enum::block_message_type,
                                              _chain_db->head_block_id()),
                                 std::vector<uint32_t>());
      }

      void reset_websocket_server(const application::daemon_configuration& cfg)
      {
         _websocket_server = std::make_shared<fc::http::websocket_server>();

         _websocket_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){
            auto wsc = std::make_shared<fc::rpc::websocket_api_connection>(*c);
            auto login = std::make_shared<bts::app::login_api>( std::ref(*_self) );
            wsc->register_api(fc::api<bts::app::login_api>(login));
            c->set_session_data( wsc );
         });
         _websocket_server->listen( cfg.websocket_endpoint );
         _websocket_server->start_accept();
      }

      void initialize_configuration()
      {
         _configuration["daemon"] = application::daemon_configuration();
         save_configuration();
      }

   public:
      void save_configuration()
      {
         fc::json::save_to_file(_configuration, _data_dir/"config.json");
      }

      application_impl(application* self)
         : _self(self),
           _chain_db(std::make_shared<chain::database>())
      {
      }

      void configure( const fc::path& data_dir )
      {
         _data_dir = data_dir,
         _chain_db->open(data_dir / "blockchain");
         if( fc::exists(data_dir / "config.json") )
         {
            try
            {
               _configuration = fc::json::from_file(data_dir / "config.json").as<application::config>();
            }
            catch( fc::exception& e )
            {
               elog("Failed to read config file:\n${e}", ("e", e.to_detail_string()));
               initialize_configuration();
            }
         }
         else
         {
            initialize_configuration();
         }
         for( const auto& p : _plugins )
            p.second->init();

         auto daemon_config = _configuration["daemon"].as<application::daemon_configuration>();
         reset_p2p_node(data_dir, daemon_config);
         reset_websocket_server(daemon_config);
      }

      void apply_configuration()
      { try {
         save_configuration();

         auto daemon_config = _configuration["daemon"].as<application::daemon_configuration>();
         reset_p2p_node(_data_dir, daemon_config);
         reset_websocket_server(daemon_config);
      } FC_CAPTURE_AND_RETHROW() }

      /**
       *  If delegate has the item, the network has no need to fetch it.
       */
      virtual bool has_item( const net::item_id& id ) override
      { try {
          if( id.item_type == bts::net::block_message_type )
          {
             return _chain_db->is_known_block( id.item_hash );
          }
          else
          {
             return _chain_db->is_known_transaction( id.item_hash );
          }
      } FC_CAPTURE_AND_RETHROW( (id) ) }

      /**
       *  @brief allows the application to validate an item prior to
       *         broadcasting to peers.
       *
       *  @param sync_mode true if the message was fetched through the sync process, false during normal operation
       *  @returns true if this message caused the blockchain to switch forks, false if it did not
       *
       *  @throws exception if error validating the item, otherwise the item is
       *          safe to broadcast on.
       */
      virtual bool handle_block( const bts::net::block_message& blk_msg, bool sync_mode ) override
      { try {
         ilog("Got block #${n} from network", ("n", blk_msg.block.block_num()));
         try {
            return _chain_db->push_block( blk_msg.block );
         } catch( const fc::exception& e ) {
            elog("Error when pushing block:\n${e}", ("e", e.to_detail_string()));
            throw;
         }
      } FC_CAPTURE_AND_RETHROW( (blk_msg)(sync_mode) ) }

      virtual bool handle_transaction( const bts::net::trx_message& trx_msg, bool sync_mode ) override
      { try {
         ilog("Got transaction from network");
         _chain_db->push_transaction( trx_msg.trx );
         return false;
      } FC_CAPTURE_AND_RETHROW( (trx_msg)(sync_mode) ) }

      /**
       *  Assuming all data elements are ordered in some way, this method should
       *  return up to limit ids that occur *after* the last ID in synopsis that
       *  we recognize.
       *
       *  On return, remaining_item_count will be set to the number of items
       *  in our blockchain after the last item returned in the result,
       *  or 0 if the result contains the last item in the blockchain
       */
      virtual std::vector<item_hash_t> get_item_ids(uint32_t item_type,
                                                    const std::vector<item_hash_t>& blockchain_synopsis,
                                                    uint32_t& remaining_item_count,
                                                    uint32_t limit ) override
      { try {
         FC_ASSERT( item_type == bts::net::block_message_type );
         vector<block_id_type>  result;
         remaining_item_count = 0;
         if( _chain_db->head_block_num() == 0 )
            return result;

         result.reserve(limit);
         block_id_type last_known_block_id;
         auto itr = blockchain_synopsis.rbegin();
         while( itr != blockchain_synopsis.rend() )
         {
            if( _chain_db->is_known_block( *itr ) || *itr == block_id_type() )
            {
               last_known_block_id = *itr;
               break;
            }
            ++itr;
         }

         for( auto num = block::num_from_id(last_known_block_id);
              num <= _chain_db->head_block_num() && result.size() < limit;
              ++num )
            if( num > 0 )
               result.push_back(_chain_db->get_block_id_for_num(num));

         if( block::num_from_id(result.back()) < _chain_db->head_block_num() )
            remaining_item_count = _chain_db->head_block_num() - block::num_from_id(result.back());

         idump((blockchain_synopsis)(limit)(result)(remaining_item_count));
         return result;
      } FC_CAPTURE_AND_RETHROW( (blockchain_synopsis)(remaining_item_count)(limit) ) }

      /**
       *  Given the hash of the requested data, fetch the body.
       */
      virtual message get_item( const item_id& id ) override
      { try {
         ilog("Request for item ${id}", ("id", id));
         if( id.item_type == bts::net::block_message_type )
         {
            auto opt_block = _chain_db->fetch_block_by_id( id.item_hash );
            if( !opt_block )
               elog("Couldn't find block ${id} -- corresponding ID in our chain is ${id2}",
                    ("id", id.item_hash)("id2", _chain_db->get_block_id_for_num(block::num_from_id(id.item_hash))));
            FC_ASSERT( opt_block.valid() );
            ilog("Serving up block #${num}", ("num", opt_block->block_num()));
            return block_message( std::move(*opt_block) );
         }
         return trx_message( _chain_db->get_recent_transaction( id.item_hash ) );
      } FC_CAPTURE_AND_RETHROW( (id) ) }

      virtual fc::sha256 get_chain_id()const override
      {
         return fc::sha256();
      }

      /**
       * Returns a synopsis of the blockchain used for syncing.
       * This consists of a list of selected item hashes from our current preferred
       * blockchain, exponentially falling off into the past.  Horrible explanation.
       *
       * If the blockchain is empty, it will return the empty list.
       * If the blockchain has one block, it will return a list containing just that block.
       * If it contains more than one block:
       *   the first element in the list will be the hash of the genesis block
       *   the second element will be the hash of an item at the half way point in the blockchain
       *   the third will be ~3/4 of the way through the block chain
       *   the fourth will be at ~7/8...
       *     &c.
       *   the last item in the list will be the hash of the most recent block on our preferred chain
       */
      virtual std::vector<item_hash_t> get_blockchain_synopsis( uint32_t item_type,
                                                                const bts::net::item_hash_t& reference_point,
                                                                uint32_t number_of_blocks_after_reference_point ) override
      { try {
         std::vector<item_hash_t> result;
         result.reserve(30);
         auto head_block_num = _chain_db->head_block_num();
         result.push_back( _chain_db->head_block_id() );
         auto current = 1;
         while( current < head_block_num )
         {
            result.push_back( _chain_db->get_block_id_for_num( head_block_num - current ) );
            current = current*2;
         }
         std::reverse( result.begin(), result.end() );
         idump((reference_point)(number_of_blocks_after_reference_point)(result));
         return result;
      } FC_CAPTURE_AND_RETHROW( (reference_point)(number_of_blocks_after_reference_point) ) }

      /**
       *  Call this after the call to handle_message succeeds.
       *
       *  @param item_type the type of the item we're synchronizing, will be the same as item passed to the sync_from() call
       *  @param item_count the number of items known to the node that haven't been sent to handle_item() yet.
       *                    After `item_count` more calls to handle_item(), the node will be in sync
       */
      virtual void     sync_status( uint32_t item_type, uint32_t item_count ) override
      {
         // any status reports to GUI go here
      }

      /**
       *  Call any time the number of connected peers changes.
       */
      virtual void     connection_count_changed( uint32_t c ) override
      {
        // any status reports to GUI go here
      }

      virtual uint32_t get_block_number(const item_hash_t& block_id) override
      { try {
         return block::num_from_id(block_id);
      } FC_CAPTURE_AND_RETHROW( (block_id) ) }

      /**
       * Returns the time a block was produced (if block_id = 0, returns genesis time).
       * If we don't know about the block, returns time_point_sec::min()
       */
      virtual fc::time_point_sec get_block_time(const item_hash_t& block_id) override
      { try {
         auto opt_block = _chain_db->fetch_block_by_id( block_id );
         if( opt_block.valid() ) return opt_block->timestamp;
         return fc::time_point_sec::min();
      } FC_CAPTURE_AND_RETHROW( (block_id) ) }

      /** returns bts::blockchain::now() */
      virtual fc::time_point_sec get_blockchain_now() override
      {
         return bts::chain::now();
      }

      virtual item_hash_t get_head_block_id() const override
      {
         return _chain_db->head_block_id();
      }

      virtual uint32_t estimate_last_known_fork_from_git_revision_timestamp(uint32_t unix_timestamp) const override
      {
         return 0; // there are no forks in graphene
      }

      virtual void error_encountered(const std::string& message, const fc::oexception& error) override
      {
         // notify GUI or something cool
      }

      application* _self;

      fc::path _data_dir;

      std::shared_ptr<bts::chain::database>        _chain_db;
      std::shared_ptr<bts::net::node>              _p2p_network;
      std::shared_ptr<fc::http::websocket_server>  _websocket_server;
      application::config                          _configuration;

      std::map<string, std::shared_ptr<abstract_plugin>> _plugins;
   };

}

application::application()
   : my(new detail::application_impl(this))
{}

application::~application()
{
   if( my->_p2p_network )
   {
      ilog("Closing p2p node");
      my->_p2p_network->close();
   }
   if( my->_chain_db )
   {
      ilog("Closing chain database");
      my->_chain_db->close();
   }
}

void application::configure( const fc::path& data_dir )
{
   my->configure( data_dir );
}

std::shared_ptr<abstract_plugin> application::get_plugin(const string& name) const
{
   return my->_plugins[name];
}

application::config& application::configuration()
{
   return my->_configuration;
}

const application::config& application::configuration() const
{
   return my->_configuration;
}

void application::apply_configuration()
{
   my->apply_configuration();
}

void application::save_configuration() const
{
   my->save_configuration();
}

net::node_ptr application::p2p_node()
{
   return my->_p2p_network;
}

std::shared_ptr<chain::database> application::chain_database() const
{
   return my->_chain_db;
}

void bts::app::application::add_plugin(const string& name, std::shared_ptr<bts::app::abstract_plugin> p)
{
   my->_plugins[name] = p;
}

// namespace detail
} }
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "DeclarationVisitorHeader.h"

#include "VisitorDefs.h"

#include "OOModel/src/declarations/Project.h"
#include "OOModel/src/declarations/NameImport.h"

#include "Export/src/tree/SourceDir.h"
#include "Export/src/tree/SourceFile.h"
#include "Export/src/tree/CompositeFragment.h"
#include "Export/src/tree/TextFragment.h"

using namespace Export;
using namespace OOModel;

namespace CppExport {

SourceFragment* DeclarationVisitorHeader::visit(Declaration* declaration)
{
	if (auto castDeclaration = DCast<Method>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<Class>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<VariableDeclaration>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<TypeAlias>(declaration)) return visit(castDeclaration);

	notAllowed(declaration);

	// TODO: handle comments
	auto fragment = new CompositeFragment(declaration);
	*fragment << "Invalid Declaration";
	return fragment;
}

SourceDir* DeclarationVisitorHeader::visitProject(Project* project, SourceDir* parent)
{
	auto projectDir = parent ? &parent->subDir(project->name()) : new SourceDir(nullptr, "src");

	for (auto node : *project->projects()) visitProject(node, projectDir);
	for (auto node : *project->modules()) visitModule(node, projectDir);
	for (auto node : *project->classes()) visitTopLevelClass(node, projectDir);

	notAllowed(project->methods());
	notAllowed(project->fields());

	return projectDir;
}

SourceDir* DeclarationVisitorHeader::visitModule(Module* module, SourceDir* parent)
{
	Q_ASSERT(parent);
	auto moduleDir = &parent->subDir(module->name());

	for (auto node : *module->modules()) visitModule(node, moduleDir);
	for (auto node : *module->classes()) visitTopLevelClass(node, moduleDir);

	notAllowed(module->methods());
	notAllowed(module->fields());

	return moduleDir;
}

SourceFile* DeclarationVisitorHeader::visitTopLevelClass(Class* classs, SourceDir* parent)
{
	Q_ASSERT(parent);
	auto classFile = &parent->file(classs->name() + ".h");

	CompositeFragment* fragment = classFile->append(new CompositeFragment(classs, "sections"));

	auto imports = fragment->append(new CompositeFragment(classs, "vertical"));
	for (auto node : *classs->subDeclarations())
	{
		if (auto ni = DCast<NameImport>(node)) *imports << visit(ni);
		else notAllowed(node);
	}

	*fragment << visit(classs);

	return classFile;
}

SourceFragment* DeclarationVisitorHeader::visitTopLevelClass(Class* classs)
{
	CompositeFragment* fragment = new CompositeFragment(classs, "sections");

	auto imports = fragment->append(new CompositeFragment(classs, "vertical"));
	for (auto node : *classs->subDeclarations())
	{
		if (auto ni = DCast<NameImport>(node)) *imports << visit(ni);
		else notAllowed(node);
	}

	*fragment << visit(classs);

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(Class* classs)
{
	auto fragment = new CompositeFragment(classs);
	if (Class::ConstructKind::Class == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "class " << classs->nameNode();
	else if (Class::ConstructKind::Struct == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "struct " << classs->nameNode();
	else if (Class::ConstructKind::Enum == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "enum " << classs->nameNode();
	else
		notAllowed(classs);

	if (!classs->typeArguments()->isEmpty())
		*fragment << list(classs->typeArguments(), ElementVisitorHeader(data()), "typeArgsList");

	if (!classs->baseClasses()->isEmpty())
		*fragment << list(classs->baseClasses(), ExpressionVisitorHeader(data()), "baseClasses");

	notAllowed(classs->friends());

	auto sections = fragment->append( new CompositeFragment(classs, "bodySections"));

	if (classs->enumerators()->size() > 0)
		error(classs->enumerators(), "Enum unhandled"); // TODO

	auto publicSection = new CompositeFragment(classs, "accessorSections");
	auto publicFilter = [](Declaration* declaration) { return declaration->modifiers()->isSet(Modifier::Public); };
	bool hasPublicSection = addMemberDeclarations(classs, publicSection, publicFilter);
	if (hasPublicSection)
	{
		*sections << "public:";
		sections->append(publicSection);
	}

	auto protectedSection = new CompositeFragment(classs, "accessorSections");
	auto protectedFilter = [](Declaration* declaration) { return declaration->modifiers()->isSet(Modifier::Protected); };
	bool hasProtectedSection = addMemberDeclarations(classs, protectedSection, protectedFilter);
	if (hasProtectedSection)
	{
		if (hasPublicSection) *sections << "\n"; // add newline between two accessor sections

		*sections << "protected:";
		sections->append(protectedSection);
	}

	auto privateSection = new CompositeFragment(classs, "accessorSections");
	auto privateFilter = [](Declaration* declaration) { return !declaration->modifiers()->isSet(Modifier::Public) &&
																				  !declaration->modifiers()->isSet(Modifier::Protected); };
	bool hasPrivateSection = addMemberDeclarations(classs, privateSection, privateFilter);
	if (hasPrivateSection)
	{
		if (hasPublicSection || hasProtectedSection) *sections << "\n"; // add newline between two accessor sections

		*sections << "private:";
		sections->append(privateSection);
	}

	return fragment;
}

template<typename Predicate>
bool DeclarationVisitorHeader::addMemberDeclarations(Class* classs, CompositeFragment* section, Predicate filter)
{
	auto subDeclarations = list(classs->subDeclarations(), this, "declarations", filter);
	auto fields = list(classs->fields(), this, "vertical", filter);
	auto classes = list(classs->classes(), this, "declarations", filter);
	auto methods = list(classs->methods(), this, "sections", filter);

	*section << subDeclarations << fields << classes << methods;
	return !subDeclarations->fragments().empty() ||
			 !fields->fragments().empty() ||
			 !classes->fragments().empty() ||
			 !methods->fragments().empty();
}

SourceFragment* DeclarationVisitorHeader::visit(Method* method)
{
	auto fragment = new CompositeFragment(method);
	*fragment << printAnnotationsAndModifiers(method);

	if (method->results()->size() > 1)
		error(method->results(), "Cannot have more than one return value in C++");

	if (method->methodKind() != Method::MethodKind::Constructor &&
		 method->methodKind() != Method::MethodKind::Destructor)
	{
		if (!method->results()->isEmpty())
			*fragment << expression(method->results()->at(0)->typeExpression()) << " ";
		else
			*fragment << "void ";
	}

	if (method->methodKind() == Method::MethodKind::Destructor)
	{
		if (!method->name().startsWith("~"))
			*fragment << "~";
	}
	*fragment << method->nameNode();

	if (!method->typeArguments()->isEmpty())
		*fragment << list(method->typeArguments(), ElementVisitorHeader(data()), "typeArgsList");

	*fragment << list(method->arguments(), ElementVisitorHeader(data()), "argsList");

	if (!method->throws()->isEmpty())
	{
		*fragment << " throw (";
		*fragment << list(method->throws(), ExpressionVisitorHeader(data()), "comma");
		*fragment << ")";
	}

	notAllowed(method->subDeclarations());
	notAllowed(method->memberInitializers());

	*fragment << ";";

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(VariableDeclaration* vd)
{
	auto fragment = new CompositeFragment(vd);
	*fragment << printAnnotationsAndModifiers(vd);
	*fragment << expression(vd->typeExpression()) << " " << vd->nameNode();
	if (vd->initialValue())
		*fragment << " = " << expression(vd->initialValue());

	if (!DCast<Expression>(vd->parent())) *fragment << ";";
	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(NameImport* nameImport)
{
	error(nameImport, "NameImport unhandled"); // TODO
	return new TextFragment(nameImport);
}

SourceFragment* DeclarationVisitorHeader::printAnnotationsAndModifiers(Declaration* declaration)
{
	auto fragment = new CompositeFragment(declaration, "vertical");
	if (!declaration->annotations()->isEmpty()) // avoid an extra new line if there are no annotations
		*fragment << list(declaration->annotations(), StatementVisitorHeader(data()), "vertical");
	auto header = fragment->append(new CompositeFragment(declaration, "space"));

	if (declaration->modifiers()->isSet(Modifier::Static))
		*header << new TextFragment(declaration->modifiers(), "static");

	if (declaration->modifiers()->isSet(Modifier::Final))
		*header << new TextFragment(declaration->modifiers(), "final");
	if (declaration->modifiers()->isSet(Modifier::Abstract))
		*header << new TextFragment(declaration->modifiers(), "abstract");

	if (declaration->modifiers()->isSet(Modifier::Virtual))
		*header << new TextFragment(declaration->modifiers(), "virtual");
	if (declaration->modifiers()->isSet(Modifier::Override))
		*header << new TextFragment(declaration->modifiers(), "override");
	if (declaration->modifiers()->isSet(Modifier::Inline))
		*header << new TextFragment(declaration->modifiers(), "inline");

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(ExplicitTemplateInstantiation* eti)
{
	error(eti, "ExplicitTemplateInstantiation unhandled"); // TODO
	return new TextFragment(eti);
}

SourceFragment* DeclarationVisitorHeader::visit(TypeAlias* typeAlias)
{
	auto fragment = new CompositeFragment(typeAlias);
	*fragment << "using " << typeAlias->nameNode() << " = " << expression(typeAlias->typeExpression()) << ";";
	return fragment;
}

}
<commit_msg>move override keyword<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "DeclarationVisitorHeader.h"

#include "VisitorDefs.h"

#include "OOModel/src/declarations/Project.h"
#include "OOModel/src/declarations/NameImport.h"

#include "Export/src/tree/SourceDir.h"
#include "Export/src/tree/SourceFile.h"
#include "Export/src/tree/CompositeFragment.h"
#include "Export/src/tree/TextFragment.h"

using namespace Export;
using namespace OOModel;

namespace CppExport {

SourceFragment* DeclarationVisitorHeader::visit(Declaration* declaration)
{
	if (auto castDeclaration = DCast<Method>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<Class>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<VariableDeclaration>(declaration)) return visit(castDeclaration);
	if (auto castDeclaration = DCast<TypeAlias>(declaration)) return visit(castDeclaration);

	notAllowed(declaration);

	// TODO: handle comments
	auto fragment = new CompositeFragment(declaration);
	*fragment << "Invalid Declaration";
	return fragment;
}

SourceDir* DeclarationVisitorHeader::visitProject(Project* project, SourceDir* parent)
{
	auto projectDir = parent ? &parent->subDir(project->name()) : new SourceDir(nullptr, "src");

	for (auto node : *project->projects()) visitProject(node, projectDir);
	for (auto node : *project->modules()) visitModule(node, projectDir);
	for (auto node : *project->classes()) visitTopLevelClass(node, projectDir);

	notAllowed(project->methods());
	notAllowed(project->fields());

	return projectDir;
}

SourceDir* DeclarationVisitorHeader::visitModule(Module* module, SourceDir* parent)
{
	Q_ASSERT(parent);
	auto moduleDir = &parent->subDir(module->name());

	for (auto node : *module->modules()) visitModule(node, moduleDir);
	for (auto node : *module->classes()) visitTopLevelClass(node, moduleDir);

	notAllowed(module->methods());
	notAllowed(module->fields());

	return moduleDir;
}

SourceFile* DeclarationVisitorHeader::visitTopLevelClass(Class* classs, SourceDir* parent)
{
	Q_ASSERT(parent);
	auto classFile = &parent->file(classs->name() + ".h");

	CompositeFragment* fragment = classFile->append(new CompositeFragment(classs, "sections"));

	auto imports = fragment->append(new CompositeFragment(classs, "vertical"));
	for (auto node : *classs->subDeclarations())
	{
		if (auto ni = DCast<NameImport>(node)) *imports << visit(ni);
		else notAllowed(node);
	}

	*fragment << visit(classs);

	return classFile;
}

SourceFragment* DeclarationVisitorHeader::visitTopLevelClass(Class* classs)
{
	CompositeFragment* fragment = new CompositeFragment(classs, "sections");

	auto imports = fragment->append(new CompositeFragment(classs, "vertical"));
	for (auto node : *classs->subDeclarations())
	{
		if (auto ni = DCast<NameImport>(node)) *imports << visit(ni);
		else notAllowed(node);
	}

	*fragment << visit(classs);

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(Class* classs)
{
	auto fragment = new CompositeFragment(classs);
	if (Class::ConstructKind::Class == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "class " << classs->nameNode();
	else if (Class::ConstructKind::Struct == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "struct " << classs->nameNode();
	else if (Class::ConstructKind::Enum == classs->constructKind())
		*fragment << printAnnotationsAndModifiers(classs) << "enum " << classs->nameNode();
	else
		notAllowed(classs);

	if (!classs->typeArguments()->isEmpty())
		*fragment << list(classs->typeArguments(), ElementVisitorHeader(data()), "typeArgsList");

	if (!classs->baseClasses()->isEmpty())
		*fragment << list(classs->baseClasses(), ExpressionVisitorHeader(data()), "baseClasses");

	notAllowed(classs->friends());

	auto sections = fragment->append( new CompositeFragment(classs, "bodySections"));

	if (classs->enumerators()->size() > 0)
		error(classs->enumerators(), "Enum unhandled"); // TODO

	auto publicSection = new CompositeFragment(classs, "accessorSections");
	auto publicFilter = [](Declaration* declaration) { return declaration->modifiers()->isSet(Modifier::Public); };
	bool hasPublicSection = addMemberDeclarations(classs, publicSection, publicFilter);
	if (hasPublicSection)
	{
		*sections << "public:";
		sections->append(publicSection);
	}

	auto protectedSection = new CompositeFragment(classs, "accessorSections");
	auto protectedFilter = [](Declaration* declaration) { return declaration->modifiers()->isSet(Modifier::Protected); };
	bool hasProtectedSection = addMemberDeclarations(classs, protectedSection, protectedFilter);
	if (hasProtectedSection)
	{
		if (hasPublicSection) *sections << "\n"; // add newline between two accessor sections

		*sections << "protected:";
		sections->append(protectedSection);
	}

	auto privateSection = new CompositeFragment(classs, "accessorSections");
	auto privateFilter = [](Declaration* declaration) { return !declaration->modifiers()->isSet(Modifier::Public) &&
																				  !declaration->modifiers()->isSet(Modifier::Protected); };
	bool hasPrivateSection = addMemberDeclarations(classs, privateSection, privateFilter);
	if (hasPrivateSection)
	{
		if (hasPublicSection || hasProtectedSection) *sections << "\n"; // add newline between two accessor sections

		*sections << "private:";
		sections->append(privateSection);
	}

	return fragment;
}

template<typename Predicate>
bool DeclarationVisitorHeader::addMemberDeclarations(Class* classs, CompositeFragment* section, Predicate filter)
{
	auto subDeclarations = list(classs->subDeclarations(), this, "declarations", filter);
	auto fields = list(classs->fields(), this, "vertical", filter);
	auto classes = list(classs->classes(), this, "declarations", filter);
	auto methods = list(classs->methods(), this, "sections", filter);

	*section << subDeclarations << fields << classes << methods;
	return !subDeclarations->fragments().empty() ||
			 !fields->fragments().empty() ||
			 !classes->fragments().empty() ||
			 !methods->fragments().empty();
}

SourceFragment* DeclarationVisitorHeader::visit(Method* method)
{
	auto fragment = new CompositeFragment(method);
	*fragment << printAnnotationsAndModifiers(method);

	if (method->results()->size() > 1)
		error(method->results(), "Cannot have more than one return value in C++");

	if (method->methodKind() != Method::MethodKind::Constructor &&
		 method->methodKind() != Method::MethodKind::Destructor)
	{
		if (!method->results()->isEmpty())
			*fragment << expression(method->results()->at(0)->typeExpression()) << " ";
		else
			*fragment << "void ";
	}

	if (method->methodKind() == Method::MethodKind::Destructor)
	{
		if (!method->name().startsWith("~"))
			*fragment << "~";
	}
	*fragment << method->nameNode();

	if (!method->typeArguments()->isEmpty())
		*fragment << list(method->typeArguments(), ElementVisitorHeader(data()), "typeArgsList");

	*fragment << list(method->arguments(), ElementVisitorHeader(data()), "argsList");

	if (!method->throws()->isEmpty())
	{
		*fragment << " throw (";
		*fragment << list(method->throws(), ExpressionVisitorHeader(data()), "comma");
		*fragment << ")";
	}

	notAllowed(method->subDeclarations());
	notAllowed(method->memberInitializers());

	if (method->modifiers()->isSet(Modifier::Override))
		*fragment << " " << new TextFragment(method->modifiers(), "override");

	*fragment << ";";

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(VariableDeclaration* vd)
{
	auto fragment = new CompositeFragment(vd);
	*fragment << printAnnotationsAndModifiers(vd);
	*fragment << expression(vd->typeExpression()) << " " << vd->nameNode();
	if (vd->initialValue())
		*fragment << " = " << expression(vd->initialValue());

	if (!DCast<Expression>(vd->parent())) *fragment << ";";
	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(NameImport* nameImport)
{
	error(nameImport, "NameImport unhandled"); // TODO
	return new TextFragment(nameImport);
}

SourceFragment* DeclarationVisitorHeader::printAnnotationsAndModifiers(Declaration* declaration)
{
	auto fragment = new CompositeFragment(declaration, "vertical");
	if (!declaration->annotations()->isEmpty()) // avoid an extra new line if there are no annotations
		*fragment << list(declaration->annotations(), StatementVisitorHeader(data()), "vertical");
	auto header = fragment->append(new CompositeFragment(declaration, "space"));

	if (declaration->modifiers()->isSet(Modifier::Static))
		*header << new TextFragment(declaration->modifiers(), "static");

	if (declaration->modifiers()->isSet(Modifier::Final))
		*header << new TextFragment(declaration->modifiers(), "final");
	if (declaration->modifiers()->isSet(Modifier::Abstract))
		*header << new TextFragment(declaration->modifiers(), "abstract");

	if (declaration->modifiers()->isSet(Modifier::Virtual))
		*header << new TextFragment(declaration->modifiers(), "virtual");
	if (declaration->modifiers()->isSet(Modifier::Inline))
		*header << new TextFragment(declaration->modifiers(), "inline");

	return fragment;
}

SourceFragment* DeclarationVisitorHeader::visit(ExplicitTemplateInstantiation* eti)
{
	error(eti, "ExplicitTemplateInstantiation unhandled"); // TODO
	return new TextFragment(eti);
}

SourceFragment* DeclarationVisitorHeader::visit(TypeAlias* typeAlias)
{
	auto fragment = new CompositeFragment(typeAlias);
	*fragment << "using " << typeAlias->nameNode() << " = " << expression(typeAlias->typeExpression()) << ";";
	return fragment;
}

}
<|endoftext|>


<commit_before><commit_msg>fix bugs in base client<commit_after><|endoftext|>


<commit_before>/*
 * Simulator.cpp
 *
 *  Created on: Mar 10, 2016
 *      Author: vens
 */

#include <iostream>
#include "SimTask.h"
#include "Scheduler/Scheduler.h"
#include "Simulator.h"

/*
std::list<SimTask*> not_arrived_list;
	std::list<SimTask*> ready_list;
	std::list<SimTask*> blocked_list;
	std::list<SimTask*> finished_list;
*/
Simulator::Simulator()
{
	// TODO Auto-generated constructor stub
	this->wave_root.AddSignal("Running");
}

Simulator::~Simulator() {
	// TODO Auto-generated destructor stub
}

void Simulator::MakeTaskList(json_value * array)
{
	this->num_tasks = array->u.array.length;
	for(int x=0;x<this->num_tasks;x++)
	{
		SimTask * task = new SimTask(array->u.array.values[x], &this->wave_root);
		this->not_arrived_list.push_back(task);
	}
	this->remaining_tasks = this->num_tasks;

	this->not_arrived_list.sort();

//	for(std::list<SimTask*>::iterator it = not_arrived_list.begin(); it != not_arrived_list.end(); ++it)
//	{
//		std::cout << (*it)->name << std::endl;
//	}
}

bool Simulator::IsDone()
{
	return this->remaining_tasks == 0;
}

void Simulator::RunTick()
{
	std::list<SimTask*>::iterator it;

	for(std::list<SimTask*>::iterator it = not_arrived_list.begin(); it != not_arrived_list.end(); ++it)
	{
		std::cout << (*it)->name << std::endl;
	}

	// for each task in the not arrived list, see if it has arrived and if so move it to ready
	for(it=this->not_arrived_list.begin(); it != this->not_arrived_list.end(); )
	{
		SimTask* this_task = *it;
		if((*it)->GetArrivalTime() == this->sys_time)
		{
		//	this->ready_list.splice(this->ready_list.begin(), this->not_arrived_list, it);
			it = this->not_arrived_list.erase(it);
			this_task->OnReady(this->sys_time);
			this->ready_list.push_back(this_task);
			//++it;
		}
		else
		{
			++it;
		}
	}

	// for each task in the blocked list, see if it is done being blocked
	for(it=this->blocked_list.begin(); it != this->blocked_list.end();)
	{
		SimTask* this_task = *it;
		if(this_task->GetArrivalTime() == this->sys_time)
		{
			it = this->blocked_list.erase(it);
			this_task->OnReady(this->sys_time);
			this->ready_list.push_back(this_task);
		}
		else
		{
			++it;
		}
	}

	// run the sys tick on the scheduler
//	Scheduler::OnSysTick(sys_time);

	if(this->running_task)
	{
		this->running_task->OnRunTick(sys_time);
	}

	// advance the sys time to show the end of this tick
	this->sys_time ++;
}

void Simulator::ExportWaveform(std::ofstream& out)
{
	char * buf = this->wave_root.Export();
	out << std::string(buf);
}
<commit_msg>added couple notes<commit_after>/*
 * Simulator.cpp
 *
 *  Created on: Mar 10, 2016
 *      Author: vens
 */

#include <iostream>
#include "SimTask.h"
#include "Scheduler/Scheduler.h"
#include "Simulator.h"

/*
std::list<SimTask*> not_arrived_list;
	std::list<SimTask*> ready_list;
	std::list<SimTask*> blocked_list;
	std::list<SimTask*> finished_list;
*/
Simulator::Simulator()
{
	// TODO Auto-generated constructor stub
	this->wave_root.AddSignal("Running");
}

Simulator::~Simulator() {
	// TODO Auto-generated destructor stub
}

void Simulator::MakeTaskList(json_value * array)
{
	this->num_tasks = array->u.array.length;
	for(int x=0;x<this->num_tasks;x++)
	{
		SimTask * task = new SimTask(array->u.array.values[x], &this->wave_root);
		this->not_arrived_list.push_back(task);
	}
	this->remaining_tasks = this->num_tasks;

	this->not_arrived_list.sort();

//	for(std::list<SimTask*>::iterator it = not_arrived_list.begin(); it != not_arrived_list.end(); ++it)
//	{
//		std::cout << (*it)->name << std::endl;
//	}
}

bool Simulator::IsDone()
{
	return this->remaining_tasks == 0;
}

void Simulator::RunTick()
{
	std::list<SimTask*>::iterator it;

	// for each task in system
	// call OnTick(sys_time)
		// Task handels own lifecycle by calling scheduler directly
		// returns its state (not_arrived, ready, running, blocked, finished);

	/*for(std::list<SimTask*>::iterator it = not_arrived_list.begin(); it != not_arrived_list.end(); ++it)
	{
		std::cout << (*it)->name << std::endl;
	}*/

	// for each task in the not arrived list, see if it has arrived and if so move it to ready
	for(it=this->not_arrived_list.begin(); it != this->not_arrived_list.end(); )
	{
		SimTask* this_task = *it;
		if((*it)->GetArrivalTime() == this->sys_time)
		{
		//	this->ready_list.splice(this->ready_list.begin(), this->not_arrived_list, it);
			it = this->not_arrived_list.erase(it);
			this_task->OnReady(this->sys_time);
			this->ready_list.push_back(this_task);
			//++it;
		}
		else
		{
			++it;
		}
	}

	// for each task in the blocked list, see if it is done being blocked
	for(it=this->blocked_list.begin(); it != this->blocked_list.end();)
	{
		SimTask* this_task = *it;
		if(this_task->GetArrivalTime() == this->sys_time)
		{
			it = this->blocked_list.erase(it);
			this_task->OnReady(this->sys_time);
			this->ready_list.push_back(this_task);
		}
		else
		{
			++it;
		}
	}

	// run the sys tick on the scheduler
//	Scheduler::OnSysTick(sys_time);

	if(this->running_task)
	{
		this->running_task->OnRunTick(sys_time);
	}

	// advance the sys time to show the end of this tick
	this->sys_time ++;
}

void Simulator::ExportWaveform(std::ofstream& out)
{
	char * buf = this->wave_root.Export();
	out << std::string(buf);
}
<|endoftext|>


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

#include "itkRandomImageSource.h"
#include "itkThresholdImageFilter.h"
#include "itkTextOutput.h"

#include <sstream>

int
itkThresholdImageFilterTest(int, char *[])
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  // Uncomment the following if you want to see each message independently
  // itk::OutputWindow::GetInstance()->PromptUserOn();

  using FloatImage2DType = itk::Image<float, 2>;

  itk::RandomImageSource<FloatImage2DType>::Pointer random;
  random = itk::RandomImageSource<FloatImage2DType>::New();
  random->SetMin(0.0);
  random->SetMax(1000.0);
  random->ReleaseDataFlagOn();

  FloatImage2DType::SpacingValueType spacing[2] = { 0.7, 2.1 };
  random->SetSpacing(spacing);

  FloatImage2DType::PointValueType origin[2] = { 15, 400 };
  random->SetOrigin(origin);

  std::ostringstream * os;

  // Test #1, filter goes out of scope
  itk::OutputWindow::GetInstance()->DisplayText("Test #1: Filter goes out of scope -----------------");
  {
    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();
    threshold->SetInput(random->GetOutput());

    // Exercise threshold setting functions
    threshold->ThresholdAbove(10.0);
    threshold->ThresholdBelow(900.0);
    threshold->ThresholdOutside(5.0, 40.0);

    // Call update multiple times to make sure that the RandomImageSource
    // is releasing and regenerating its data
    threshold->Update();
    threshold->Modified();
    threshold->Update();

    std::cout << "Input spacing: " << random->GetOutput()->GetSpacing()[0] << ", "
              << random->GetOutput()->GetSpacing()[1] << std::endl;
    std::cout << "Output spacing: " << threshold->GetOutput()->GetSpacing()[0] << ", "
              << threshold->GetOutput()->GetSpacing()[1] << std::endl;

    os = new std::ostringstream();
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    itk::OutputWindow::GetInstance()->DisplayText("Ending Test #1: filter goes out of scope");
    itk::OutputWindow::GetInstance()->DisplayText("End of Test #1 -----------------------------------");
  }

  // Test #2, user keeps an extra handle to an output
  itk::OutputWindow::GetInstance()->DisplayText("Test #2: User keeps an extra hold on an output  -----------------");
  {
    FloatImage2DType::Pointer keep;

    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();
    threshold->SetInput(random->GetOutput());
    threshold->Update();

    os = new std::ostringstream();
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    keep = threshold->GetOutput(0);

    itk::OutputWindow::GetInstance()->DisplayText("End of Test #2: last handle on output 0 should go out of scope");
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #2 -----------------------------------");

  // Test #3, user disconnects a data object from the pipeline
  itk::OutputWindow::GetInstance()->DisplayText(
    "Test #3: user disconnects a data object from the pipeline  -----------------");
  {
    FloatImage2DType::Pointer keep;

    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();
    threshold->SetInput(random->GetOutput());
    threshold->Update();

    os = new std::ostringstream;
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    keep = threshold->GetOutput(0);
    keep->DisconnectPipeline();

    itk::OutputWindow::GetInstance()->DisplayText("End of Test #3: last handle on output 0 should go out of scope");
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #3 -----------------------------------");

  // Test #4, threshold values
  itk::OutputWindow::GetInstance()->DisplayText("Test #4: threshold values  -----------------");
  {
    using IntImage1DType = itk::Image<int, 1>;
    IntImage1DType::Pointer          input = IntImage1DType::New();
    IntImage1DType::SpacingValueType inputSpacing[1] = { 0.7 };
    input->SetSpacing(inputSpacing);
    IntImage1DType::PointValueType inputOrigin[1] = { 15 };
    input->SetOrigin(inputOrigin);
    IntImage1DType::SizeValueType inputSize = 1;
    IntImage1DType::RegionType    inputRegion;
    inputRegion.SetSize(0, inputSize);
    input->SetRegions(inputRegion);
    input->Allocate();
    // The inputValue can be any random value.
    int inputValue = 9;
    input->FillBuffer(inputValue);

    itk::ThresholdImageFilter<IntImage1DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<IntImage1DType>::New();
    threshold->SetInput(input);
    int outsideValue = 99;
    threshold->SetOutsideValue(outsideValue);
    IntImage1DType::IndexType index;
    index.Fill(0);

    int outputValue;
    // Above inputValue-1
    threshold->ThresholdAbove(inputValue - 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Above inputValue+1
    threshold->ThresholdAbove(inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Above inputValue
    // By definition, the values greater than the value are set to OutsideValue.
    // So, with the threshold set to inputValue, the output should still be equal to the input.
    threshold->ThresholdAbove(inputValue);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue-1
    threshold->ThresholdBelow(inputValue - 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue+1
    threshold->ThresholdBelow(inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue
    // By definition, the values less than the value are set to OutsideValue
    // So, with the threshold set to inputValue, the output should still be equal to the input.
    threshold->ThresholdBelow(inputValue);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue-1 inputValue+1]
    threshold->ThresholdOutside(inputValue - 1, inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter outside failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue, inputValue+2]
    // By definition, the values outside the range (less than lower or greater than upper) are set to OutsideValue
    // So, with the threshold including inputValue=0, the output should still be equal to the input.
    threshold->ThresholdOutside(inputValue, inputValue + 2);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter outside failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue+1, inputValue+3]
    threshold->ThresholdOutside(inputValue + 1, inputValue + 3);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #4 -----------------------------------");

  return EXIT_SUCCESS;
}
<commit_msg>ENH: Improve `itk::ThresholdImageFilter` class coverage<commit_after>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkRandomImageSource.h"
#include "itkThresholdImageFilter.h"
#include "itkTestingMacros.h"
#include "itkTextOutput.h"

#include <sstream>

int
itkThresholdImageFilterTest(int, char *[])
{
  // Comment the following if you want to use the itk text output window
  itk::OutputWindow::SetInstance(itk::TextOutput::New());

  // Uncomment the following if you want to see each message independently
  // itk::OutputWindow::GetInstance()->PromptUserOn();

  using FloatImage2DType = itk::Image<float, 2>;

  itk::RandomImageSource<FloatImage2DType>::Pointer random;
  random = itk::RandomImageSource<FloatImage2DType>::New();
  random->SetMin(0.0);
  random->SetMax(1000.0);
  random->ReleaseDataFlagOn();

  FloatImage2DType::SpacingValueType spacing[2] = { 0.7, 2.1 };
  random->SetSpacing(spacing);

  FloatImage2DType::PointValueType origin[2] = { 15, 400 };
  random->SetOrigin(origin);

  std::ostringstream * os;

  // Test #1, filter goes out of scope
  itk::OutputWindow::GetInstance()->DisplayText("Test #1: Filter goes out of scope -----------------");
  {
    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();

    ITK_EXERCISE_BASIC_OBJECT_METHODS(threshold, ThresholdImageFilter, InPlaceImageFilter);

    threshold->SetInput(random->GetOutput());

    // Exercise threshold setting functions
    threshold->ThresholdAbove(10.0);
    threshold->ThresholdBelow(900.0);
    threshold->ThresholdOutside(5.0, 40.0);

    // Call update multiple times to make sure that the RandomImageSource
    // is releasing and regenerating its data
    threshold->Update();
    threshold->Modified();
    threshold->Update();

    std::cout << "Input spacing: " << random->GetOutput()->GetSpacing()[0] << ", "
              << random->GetOutput()->GetSpacing()[1] << std::endl;
    std::cout << "Output spacing: " << threshold->GetOutput()->GetSpacing()[0] << ", "
              << threshold->GetOutput()->GetSpacing()[1] << std::endl;

    os = new std::ostringstream();
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    itk::OutputWindow::GetInstance()->DisplayText("Ending Test #1: filter goes out of scope");
    itk::OutputWindow::GetInstance()->DisplayText("End of Test #1 -----------------------------------");
  }

  // Test #2, user keeps an extra handle to an output
  itk::OutputWindow::GetInstance()->DisplayText("Test #2: User keeps an extra hold on an output  -----------------");
  {
    FloatImage2DType::Pointer keep;

    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();
    threshold->SetInput(random->GetOutput());
    threshold->Update();

    os = new std::ostringstream();
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    keep = threshold->GetOutput(0);

    itk::OutputWindow::GetInstance()->DisplayText("End of Test #2: last handle on output 0 should go out of scope");
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #2 -----------------------------------");

  // Test #3, user disconnects a data object from the pipeline
  itk::OutputWindow::GetInstance()->DisplayText(
    "Test #3: user disconnects a data object from the pipeline  -----------------");
  {
    FloatImage2DType::Pointer keep;

    itk::ThresholdImageFilter<FloatImage2DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<FloatImage2DType>::New();
    threshold->SetInput(random->GetOutput());
    threshold->Update();

    os = new std::ostringstream;
    *os << "Filter: " << threshold.GetPointer();
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;
    os = new std::ostringstream();
    *os << "Output #0: " << threshold->GetOutput(0);
    itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
    delete os;

    keep = threshold->GetOutput(0);
    keep->DisconnectPipeline();

    itk::OutputWindow::GetInstance()->DisplayText("End of Test #3: last handle on output 0 should go out of scope");
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #3 -----------------------------------");

  // Test #4, threshold values
  itk::OutputWindow::GetInstance()->DisplayText("Test #4: threshold values  -----------------");
  {
    using PixelType = int;

    using IntImage1DType = itk::Image<PixelType, 1>;
    IntImage1DType::Pointer          input = IntImage1DType::New();
    IntImage1DType::SpacingValueType inputSpacing[1] = { 0.7 };
    input->SetSpacing(inputSpacing);
    IntImage1DType::PointValueType inputOrigin[1] = { 15 };
    input->SetOrigin(inputOrigin);
    IntImage1DType::SizeValueType inputSize = 1;
    IntImage1DType::RegionType    inputRegion;
    inputRegion.SetSize(0, inputSize);
    input->SetRegions(inputRegion);
    input->Allocate();
    // The inputValue can be any random value.
    PixelType inputValue = 9;
    input->FillBuffer(inputValue);

    itk::ThresholdImageFilter<IntImage1DType>::Pointer threshold;
    threshold = itk::ThresholdImageFilter<IntImage1DType>::New();

    threshold->SetInput(input);
    PixelType outsideValue = 99;
    threshold->SetOutsideValue(outsideValue);
    ITK_TEST_SET_GET_VALUE(outsideValue, threshold->GetOutsideValue());
    IntImage1DType::IndexType index;
    index.Fill(0);

    PixelType lower = itk::NumericTraits<PixelType>::NonpositiveMin();
    threshold->SetLower(lower);
    ITK_TEST_SET_GET_VALUE(lower, threshold->GetLower());

    PixelType upper = itk::NumericTraits<PixelType>::max();
    threshold->SetUpper(upper);
    ITK_TEST_SET_GET_VALUE(upper, threshold->GetUpper());

    PixelType outputValue;
    // Above inputValue-1
    threshold->ThresholdAbove(inputValue - 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Above inputValue+1
    threshold->ThresholdAbove(inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Above inputValue
    // By definition, the values greater than the value are set to OutsideValue.
    // So, with the threshold set to inputValue, the output should still be equal to the input.
    threshold->ThresholdAbove(inputValue);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue-1
    threshold->ThresholdBelow(inputValue - 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue+1
    threshold->ThresholdBelow(inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Below inputValue
    // By definition, the values less than the value are set to OutsideValue
    // So, with the threshold set to inputValue, the output should still be equal to the input.
    threshold->ThresholdBelow(inputValue);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter below failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue-1 inputValue+1]
    threshold->ThresholdOutside(inputValue - 1, inputValue + 1);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter outside failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue, inputValue+2]
    // By definition, the values outside the range (less than lower or greater than upper) are set to OutsideValue
    // So, with the threshold including inputValue=0, the output should still be equal to the input.
    threshold->ThresholdOutside(inputValue, inputValue + 2);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != inputValue)
    {
      os = new std::ostringstream;
      *os << "Filter outside failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }

    // Outside [inputValue+1, inputValue+3]
    threshold->ThresholdOutside(inputValue + 1, inputValue + 3);
    threshold->Update();
    outputValue = threshold->GetOutput()->GetPixel(index);
    if (outputValue != outsideValue)
    {
      os = new std::ostringstream;
      *os << "Filter above failed:"
          << " lower: " << threshold->GetLower() << " upper: " << threshold->GetUpper() << " output: " << outputValue;
      itk::OutputWindow::GetInstance()->DisplayText(os->str().c_str());
      return EXIT_FAILURE;
    }
  }
  itk::OutputWindow::GetInstance()->DisplayText("End of Test #4 -----------------------------------");

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/// \file drawMeanPtRaw.C
/// \brief Macro to draw the Output of AliAnalysisTaskMeanPtRaw
///
/// This macro draws the output of AliAnalysisTaskMeanPtRaw. The first argument is the file, which should be used to plot,
/// the second argument contains additional information, which are put on the plot.
/// This second argument can contain pT cuts in the form lowerPt<pT<higherPt
/// All different information need to be seperated by ; and are then parsed in this macro.
///
/// \author Philipp Luettig <philipp.luettig@cern.ch>, University of Frankfurt, Germany
/// \date May 12th, 2015

#include "TFile.h"
#include "TList.h"
#include "TProfile.h"
#include "TH1.h"
#include "TH2.h"
#include "THnSparse.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TLatex.h"
#include "TLegend.h"
#include <vector>

Int_t GetMaxBin(std::vector<TProfile> &vec);
Double_t GetMaxPt(std::vector<TProfile> &vec);

void drawMeanPtRaw(const char *fInput = "AnalysisResults.root", const char * cInformation ="")
{
  TFile *f = TFile::Open(fInput,"READ");
  TDirectoryFile *d = (TDirectoryFile*)f->Get("MeanPtRaw");
  TList *l = (TList*)d->Get("MeanPtRaw");
  //l->ls();
  THnSparse *hsMpt = (THnSparse*)l->FindObject("fPtVsMultRaw");
  TH1I *hCutNames = (TH1I*)l->FindObject("fTrackCutName");

  Double_t pTmin = 0.15;
  Double_t pTmax = 10;

  const Int_t colors[] = {kBlue+1, kRed+1, kBlack, kGreen+3, kMagenta+1, kOrange-1,kCyan+2,kYellow+2};

  // parse information given as second argument
  TString sAdditionalInfo(cInformation);
  TObjArray *oAddInfo = sAdditionalInfo.Tokenize(";");

  std::vector<Bool_t> bDrawEntry;
  std::vector<Double_t> dVecPtMin;
  std::vector<Double_t> dVecPtMax;
  Int_t nPtCuts = 0;

  for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
  {
	bDrawEntry.push_back(kTRUE);
  }

  for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
  {
	TObjString *osAdd = (TObjString*)oAddInfo->At(iEntry);
	if(osAdd->GetString().Contains("pT"))
	{
	  TObjArray *oPt = osAdd->GetString().Tokenize("<");
	  TObjString *osPtMin = (TObjString*)oPt->At(0);
	  TObjString *osPtMax = (TObjString*)oPt->At(2);

	  dVecPtMin.push_back(atof(osPtMin->GetString().Data()));
	  dVecPtMax.push_back(atof(osPtMax->GetString().Data()));

	  bDrawEntry.at(iEntry) = kFALSE;
	  nPtCuts++;
	}
  }

  std::vector<std::vector<TProfile> > pVecMpt;

  Int_t nCutSettings = hsMpt->GetAxis(2)->GetNbins();

  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	hsMpt->GetAxis(2)->SetRange(iCutSetting, iCutSetting);
	std::vector<TProfile> pVecTemp;
	for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	  hsMpt->GetAxis(1)->SetRangeUser(dVecPtMin.at(iPtCut), dVecPtMax.at(iPtCut));
	  TProfile pMpt(*(TProfile*)hsMpt->Projection(1,0)->ProfileX());
	  pMpt.SetName(Form("pMpt_%i_%i", iCutSetting, iPtCut));
	  pMpt.SetMarkerStyle(20);
	  pMpt.SetMarkerColor(colors[iPtCut%9]);
	  pVecTemp.push_back(pMpt);
	}
	pVecMpt.push_back(pVecTemp);
  }

  Int_t maxBin = -1;
  Double_t maxPt = -1;
  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	if(GetMaxBin(pVecMpt.at(iCutSetting)) > maxBin)  { maxBin = GetMaxBin(pVecMpt.at(iCutSetting)); }
	if(GetMaxPt(pVecMpt.at(iCutSetting)) > maxPt)  { maxPt = GetMaxPt(pVecMpt.at(iCutSetting)); }
  }

  TH1F hDummy("hDummy",";n_{acc} (raw);#LT #it{p}_{T} #GT (raw) (GeV/c)",3500,-0.5,3499.5);
  hDummy.GetXaxis()->SetRangeUser(0, maxBin);
  hDummy.GetYaxis()->SetRangeUser(0, maxPt);
  hDummy.GetYaxis()->SetTitleOffset(1.2);
  hDummy.SetTitleFont(43);
  hDummy.SetTitleSize(18);

  TLatex lat;
  lat.SetTextFont(43);
  lat.SetTextSize(16);
  lat.SetTextColor(kBlack);

  TLegend leg(0.7, 0.7, 0.9, 0.9);
  leg.SetTextFont(43);
  leg.SetTextSize(15);
  leg.SetTextColor(kBlack);
  leg.SetBorderSize(0);
  leg.SetFillStyle(0);
  for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	leg.AddEntry(&pVecMpt.at(0).at(iPtCut), Form("%.2f < #it{p}_{T} < %.2f GeV/c", dVecPtMin.at(iPtCut), dVecPtMax.at(iPtCut)), "P");
  }

  Double_t dYPositionDefault = 0.38;
  Double_t dDeltaYDefault = 0.04;

  gStyle->SetOptStat(0);
  TCanvas c1("c1","c1",nCutSettings*600,600);
  c1.Divide(nCutSettings,1);
  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	c1.cd(iCutSetting+1);
	gPad->SetTopMargin(0.06);
    gPad->SetRightMargin(0.3);

	Double_t dYPosition = dYPositionDefault;
	Double_t dDeltaY = dDeltaYDefault;

	hDummy.SetTitle(hCutNames->GetXaxis()->GetBinLabel(iCutSetting+1));
	hDummy.DrawCopy();

	for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	  pVecMpt.at(iCutSetting).at(iPtCut).Draw("same");
	}

	for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
	{
	  if(bDrawEntry.at(iEntry)) {
		TObjString *osAdd = (TObjString*)oAddInfo->At(iEntry);
// 		lat.DrawLatex(10, dYPosition, Form("%s", osAdd->GetString().Data()));
// 		dYPosition -= dDeltaY;
		lat.DrawLatexNDC(0.72, dYPosition, Form("%s", osAdd->GetString().Data()));
		dYPosition -= dDeltaY;
	  }
	}

	leg.Draw();
  } // end iCutSetting

  c1.SaveAs("meanpt_vs_mult_raw.gif");
}

Int_t GetMaxBin(std::vector<TProfile> &vec)
{
  Int_t iMaxBin = -1;
  for(UInt_t iEntry = 0; iEntry < vec.size(); iEntry++) {
	for(Int_t i = 0; i < vec.at(iEntry).GetNbinsX(); i++)
	{
	  if( (vec.at(iEntry).GetBinContent(i)>0) && (vec.at(iEntry).GetBinError(i)>0))
	  {
		iMaxBin = vec.at(iEntry).GetBinCenter(i);
	  }
	}
  }
  return iMaxBin;
}

Double_t GetMaxPt(std::vector<TProfile> &vec)
{
  Double_t dMaxPt = -1;
  for(UInt_t iEntry = 0; iEntry < vec.size(); iEntry++) {
	for(Int_t i = 0; i < vec.at(iEntry).GetNbinsX(); i++)
	{
	  if( ((vec.at(iEntry).GetBinContent(i) + vec.at(iEntry).GetBinError(i)) > dMaxPt) )
	  {
		dMaxPt = (vec.at(iEntry).GetBinContent(i) + vec.at(iEntry).GetBinError(i));
	  }
	}
  }
  return dMaxPt;
}
<commit_msg>updated drawMeanPtRaw to take correct setting for different cut sets into account<commit_after>/// \file drawMeanPtRaw.C
/// \brief Macro to draw the Output of AliAnalysisTaskMeanPtRaw
///
/// This macro draws the output of AliAnalysisTaskMeanPtRaw. The first argument is the file, which should be used to plot,
/// the second argument contains additional information, which are put on the plot.
/// This second argument can contain pT cuts in the form lowerPt<pT<higherPt
/// All different information need to be seperated by ; and are then parsed in this macro.
///
/// \author Philipp Luettig <philipp.luettig@cern.ch>, University of Frankfurt, Germany
/// \date May 12th, 2015

#include "TFile.h"
#include "TList.h"
#include "TProfile.h"
#include "TH1.h"
#include "TH2.h"
#include "THnSparse.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TLatex.h"
#include "TLegend.h"
#include <vector>

Int_t GetMaxBin(std::vector<TProfile> &vec);
Double_t GetMaxPt(std::vector<TProfile> &vec);

void drawMeanPtRaw(const char *fInput = "AnalysisResults.root", const char * cInformation ="")
{
  TFile *f = TFile::Open(fInput,"READ");
  TDirectoryFile *d = (TDirectoryFile*)f->Get("MeanPtRaw");
  TList *l = (TList*)d->Get("MeanPtRaw");
  //l->ls();
  THnSparse *hsMpt = (THnSparse*)l->FindObject("fPtVsMultRaw");
  TH1I *hCutNames = (TH1I*)l->FindObject("fTrackCutName");

  Double_t pTmin = 0.15;
  Double_t pTmax = 10;

  const Int_t colors[] = {kBlue+1, kRed+1, kBlack, kGreen+3, kMagenta+1, kOrange-1,kCyan+2,kYellow+2};

  // parse information given as second argument
  TString sAdditionalInfo(cInformation);
  TObjArray *oAddInfo = sAdditionalInfo.Tokenize(";");

  std::vector<Bool_t> bDrawEntry;
  std::vector<Double_t> dVecPtMin;
  std::vector<Double_t> dVecPtMax;
  Int_t nPtCuts = 0;

  for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
  {
	bDrawEntry.push_back(kTRUE);
  }

  for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
  {
	TObjString *osAdd = (TObjString*)oAddInfo->At(iEntry);
	if(osAdd->GetString().Contains("pT"))
	{
	  TObjArray *oPt = osAdd->GetString().Tokenize("<");
	  TObjString *osPtMin = (TObjString*)oPt->At(0);
	  TObjString *osPtMax = (TObjString*)oPt->At(2);

	  dVecPtMin.push_back(atof(osPtMin->GetString().Data()));
	  dVecPtMax.push_back(atof(osPtMax->GetString().Data()));

	  bDrawEntry.at(iEntry) = kFALSE;
	  nPtCuts++;
	}
  }

  std::vector<std::vector<TProfile> > pVecMpt;

  Int_t nCutSettings = hsMpt->GetAxis(2)->GetNbins();

  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	hsMpt->GetAxis(2)->SetRange(iCutSetting+1, iCutSetting+1); // +1 to overcome underflow bin
	std::vector<TProfile> pVecTemp;
	for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	  hsMpt->GetAxis(1)->SetRangeUser(dVecPtMin.at(iPtCut), dVecPtMax.at(iPtCut));
	  TProfile pMpt(*(TProfile*)hsMpt->Projection(1,0)->ProfileX());
	  pMpt.SetName(Form("pMpt_%i_%i", iCutSetting, iPtCut));
	  pMpt.SetMarkerStyle(20);
	  pMpt.SetMarkerColor(colors[iPtCut%9]);
	  pVecTemp.push_back(pMpt);
	}
	pVecMpt.push_back(pVecTemp);
  }

  Int_t maxBin = -1;
  Double_t maxPt = -1;
  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	if(GetMaxBin(pVecMpt.at(iCutSetting)) > maxBin)  { maxBin = GetMaxBin(pVecMpt.at(iCutSetting)); }
	if(GetMaxPt(pVecMpt.at(iCutSetting)) > maxPt)  { maxPt = GetMaxPt(pVecMpt.at(iCutSetting)); }
  }

  TH1F hDummy("hDummy",";n_{acc} (raw);#LT #it{p}_{T} #GT (raw) (GeV/c)",3500,-0.5,3499.5);
  hDummy.GetXaxis()->SetRangeUser(0, maxBin);
  hDummy.GetYaxis()->SetRangeUser(0, maxPt);
  hDummy.GetYaxis()->SetTitleOffset(1.2);
  hDummy.SetTitleFont(43);
  hDummy.SetTitleSize(18);

  TLatex lat;
  lat.SetTextFont(43);
  lat.SetTextSize(16);
  lat.SetTextColor(kBlack);

  TLegend leg(0.7, 0.7, 0.9, 0.9);
  leg.SetTextFont(43);
  leg.SetTextSize(15);
  leg.SetTextColor(kBlack);
  leg.SetBorderSize(0);
  leg.SetFillStyle(0);
  for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	leg.AddEntry(&pVecMpt.at(0).at(iPtCut), Form("%.2f < #it{p}_{T} < %.2f GeV/c", dVecPtMin.at(iPtCut), dVecPtMax.at(iPtCut)), "P");
  }

  Double_t dYPositionDefault = 0.38;
  Double_t dDeltaYDefault = 0.04;

  gStyle->SetOptStat(0);
  TCanvas c1("c1","c1",nCutSettings*600,600);
  c1.Divide(nCutSettings,1);
  for(Int_t iCutSetting = 0; iCutSetting < nCutSettings; iCutSetting++) {
	c1.cd(iCutSetting+1);
	gPad->SetTopMargin(0.06);
    gPad->SetRightMargin(0.3);

	Double_t dYPosition = dYPositionDefault;
	Double_t dDeltaY = dDeltaYDefault;

	hDummy.SetTitle(hCutNames->GetXaxis()->GetBinLabel(iCutSetting+1));
	hDummy.DrawCopy();

	for(Int_t iPtCut = 0; iPtCut < nPtCuts; iPtCut++) {
	  pVecMpt.at(iCutSetting).at(iPtCut).Draw("same");
	}

	for(Int_t iEntry = 0; iEntry < oAddInfo->GetEntries(); iEntry++)
	{
	  if(bDrawEntry.at(iEntry)) {
		TObjString *osAdd = (TObjString*)oAddInfo->At(iEntry);
// 		lat.DrawLatex(10, dYPosition, Form("%s", osAdd->GetString().Data()));
// 		dYPosition -= dDeltaY;
		lat.DrawLatexNDC(0.72, dYPosition, Form("%s", osAdd->GetString().Data()));
		dYPosition -= dDeltaY;
	  }
	}

	leg.Draw();
  } // end iCutSetting

  c1.SaveAs("meanpt_vs_mult_raw.gif");
}

Int_t GetMaxBin(std::vector<TProfile> &vec)
{
  Int_t iMaxBin = -1;
  for(UInt_t iEntry = 0; iEntry < vec.size(); iEntry++) {
	for(Int_t i = 0; i < vec.at(iEntry).GetNbinsX(); i++)
	{
	  if( (vec.at(iEntry).GetBinContent(i)>0) && (vec.at(iEntry).GetBinError(i)>0))
	  {
		iMaxBin = vec.at(iEntry).GetBinCenter(i);
	  }
	}
  }
  return iMaxBin;
}

Double_t GetMaxPt(std::vector<TProfile> &vec)
{
  Double_t dMaxPt = -1;
  for(UInt_t iEntry = 0; iEntry < vec.size(); iEntry++) {
	for(Int_t i = 0; i < vec.at(iEntry).GetNbinsX(); i++)
	{
	  if( ((vec.at(iEntry).GetBinContent(i) + vec.at(iEntry).GetBinError(i)) > dMaxPt) )
	  {
		dMaxPt = (vec.at(iEntry).GetBinContent(i) + vec.at(iEntry).GetBinError(i));
	  }
	}
  }
  return dMaxPt;
}
<|endoftext|>