<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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 <graphene/chain/database.hpp>

#include <graphene/chain/chain_property_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/special_authority_object.hpp>
#include <graphene/chain/operation_history_object.hpp>

#include <graphene/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>
#include <queue>
#include <tuple>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex( fc::path data_dir )
{ try {
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }
   if( last_block->block_num() <= head_block_num()) return;

   ilog( "reindexing blockchain" );
   auto start = fc::time_point::now();
   const auto last_block_num = last_block->block_num();
   uint32_t undo_point = last_block_num < GRAPHENE_MAX_UNDO_HISTORY ? 0 : last_block_num - GRAPHENE_MAX_UNDO_HISTORY;

   ilog( "Replaying blocks, starting at ${next}...", ("next",head_block_num() + 1) );
   if( head_block_num() >= undo_point )
   {
      if( head_block_num() > 0 )
         _fork_db.start_block( *fetch_block_by_number( head_block_num() ) );
   }
   else
      _undo_db.disable();

   uint32_t skip = node_properties().skip_flags;

   size_t total_block_size = _block_id_to_block.total_block_size();
   const auto& gpo = get_global_properties();
   std::queue< std::tuple< size_t, signed_block, fc::future< void > > > blocks;
   uint32_t next_block_num = head_block_num() + 1;
   uint32_t i = next_block_num;
   while( next_block_num <= last_block_num || !blocks.empty() )
   {
      if( next_block_num <= last_block_num && blocks.size() < 20 )
      {
         const size_t processed_block_size = _block_id_to_block.blocks_current_position();
         fc::optional< signed_block > block = _block_id_to_block.fetch_by_number( next_block_num++ );
         if( block.valid() )
         {
            if( block->timestamp >= last_block->timestamp - gpo.parameters.maximum_time_until_expiration )
               skip &= ~skip_transaction_dupe_check;
            blocks.emplace( processed_block_size, std::move(*block), fc::future<void>() );
            std::get<2>(blocks.back()) = precompute_parallel( std::get<1>(blocks.back()), skip );
         }
         else
         {
            wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
            uint32_t dropped_count = 0;
            while( true )
            {
               fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
               // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
               if( !last_id.valid() )
                  break;
               // we've caught up to the gap
               if( block_header::num_from_id( *last_id ) <= i )
                  break;
               _block_id_to_block.remove( *last_id );
               dropped_count++;
            }
            wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
            next_block_num = last_block_num + 1; // don't load more blocks
         }
      }
      else
      {
         std::get<2>(blocks.front()).wait();
         const signed_block& block = std::get<1>(blocks.front());

         if( i % 10000 == 0 )
         {
            std::stringstream bysize;
            std::stringstream bynum;
            bysize << std::fixed << std::setprecision(5) << double(std::get<0>(blocks.front())) / total_block_size * 100;
            bynum << std::fixed << std::setprecision(5) << double(i)*100/last_block_num;
            ilog(
               "   [by size: ${size}%   ${processed} of ${total}]   [by num: ${num}%   ${i} of ${last}]",
               ("size", bysize.str())
               ("processed", std::get<0>(blocks.front()))
               ("total", total_block_size)
               ("num", bynum.str())
               ("i", i)
               ("last", last_block_num)
            );
         }
         if( i == undo_point )
         {
            ilog( "Writing database to disk at block ${i}", ("i",i) );
            flush();
            ilog( "Done" );
         }
         if( i < undo_point )
            apply_block( block, skip );
         else
         {
            _undo_db.enable();
            push_block( block, skip );
         }
         blocks.pop();
         i++;
      }
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   if (_opened) {
     close();
   }
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader,
   const std::string& db_version)
{
   try
   {
      bool wipe_object_db = false;
      if( !fc::exists( data_dir / "db_version" ) )
         wipe_object_db = true;
      else
      {
         std::string version_string;
         fc::read_file_contents( data_dir / "db_version", version_string );
         wipe_object_db = ( version_string != db_version );
      }
      if( wipe_object_db ) {
          ilog("Wiping object_database due to missing or wrong version");
          object_database::wipe( data_dir );
          std::ofstream version_file( (data_dir / "db_version").generic_string().c_str(),
                                      std::ios::out | std::ios::binary | std::ios::trunc );
          version_file.write( db_version.c_str(), db_version.size() );
          version_file.close();
      }

      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());
      else
      {
         _p_core_asset_obj = &get( asset_id_type() );
         _p_core_dynamic_data_obj = &get( asset_dynamic_data_id_type() );
         _p_global_prop_obj = &get( global_property_id_type() );
         _p_chain_property_obj = &get( chain_property_id_type() );
         _p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() );
         _p_witness_schedule_obj = &get( witness_schedule_id_type() );
      }

      fc::optional<block_id_type> last_block = _block_id_to_block.last_id();
      if( last_block.valid() )
      {
         FC_ASSERT( *last_block >= head_block_id(),
                    "last block ID does not match current chain state",
                    ("last_block->id", last_block)("head_block_id",head_block_num()) );
         reindex( data_dir );
      }
      _opened = true;
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   if (!_opened)
      return;

   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         uint32_t cutoff = get_dynamic_global_properties().last_irreversible_block_num;

         ilog( "Rewinding from ${head} to ${cutoff}", ("head",head_block_num())("cutoff",cutoff) );
         while( head_block_num() > cutoff )
         {
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
         }
      }
      catch ( const fc::exception& e )
      {
         wlog( "Database close unexpected exception: ${e}", ("e", e) );
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();

   _opened = false;
}

} }
<commit_msg>Fix size calculation in replay status message<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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 <graphene/chain/database.hpp>

#include <graphene/chain/chain_property_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/special_authority_object.hpp>
#include <graphene/chain/operation_history_object.hpp>

#include <graphene/protocol/fee_schedule.hpp>

#include <fc/io/fstream.hpp>

#include <fstream>
#include <functional>
#include <iostream>
#include <queue>
#include <tuple>

namespace graphene { namespace chain {

database::database()
{
   initialize_indexes();
   initialize_evaluators();
}

database::~database()
{
   clear_pending();
}

void database::reindex( fc::path data_dir )
{ try {
   auto last_block = _block_id_to_block.last();
   if( !last_block ) {
      elog( "!no last block" );
      edump((last_block));
      return;
   }
   if( last_block->block_num() <= head_block_num()) return;

   ilog( "reindexing blockchain" );
   auto start = fc::time_point::now();
   const auto last_block_num = last_block->block_num();
   uint32_t undo_point = last_block_num < GRAPHENE_MAX_UNDO_HISTORY ? 0 : last_block_num - GRAPHENE_MAX_UNDO_HISTORY;

   ilog( "Replaying blocks, starting at ${next}...", ("next",head_block_num() + 1) );
   if( head_block_num() >= undo_point )
   {
      if( head_block_num() > 0 )
         _fork_db.start_block( *fetch_block_by_number( head_block_num() ) );
   }
   else
      _undo_db.disable();

   uint32_t skip = node_properties().skip_flags;

   size_t total_block_size = _block_id_to_block.total_block_size();
   const auto& gpo = get_global_properties();
   std::queue< std::tuple< size_t, signed_block, fc::future< void > > > blocks;
   uint32_t next_block_num = head_block_num() + 1;
   uint32_t i = next_block_num;
   while( next_block_num <= last_block_num || !blocks.empty() )
   {
      if( next_block_num <= last_block_num && blocks.size() < 20 )
      {
         const size_t processed_block_size = _block_id_to_block.blocks_current_position();
         fc::optional< signed_block > block = _block_id_to_block.fetch_by_number( next_block_num++ );
         if( block.valid() )
         {
            if( block->timestamp >= last_block->timestamp - gpo.parameters.maximum_time_until_expiration )
               skip &= ~skip_transaction_dupe_check;
            blocks.emplace( processed_block_size, std::move(*block), fc::future<void>() );
            std::get<2>(blocks.back()) = precompute_parallel( std::get<1>(blocks.back()), skip );
         }
         else
         {
            wlog( "Reindexing terminated due to gap:  Block ${i} does not exist!", ("i", i) );
            uint32_t dropped_count = 0;
            while( true )
            {
               fc::optional< block_id_type > last_id = _block_id_to_block.last_id();
               // this can trigger if we attempt to e.g. read a file that has block #2 but no block #1
               if( !last_id.valid() )
                  break;
               // we've caught up to the gap
               if( block_header::num_from_id( *last_id ) <= i )
                  break;
               _block_id_to_block.remove( *last_id );
               dropped_count++;
            }
            wlog( "Dropped ${n} blocks from after the gap", ("n", dropped_count) );
            next_block_num = last_block_num + 1; // don't load more blocks
         }
      }
      else
      {
         std::get<2>(blocks.front()).wait();
         const signed_block& block = std::get<1>(blocks.front());

         if( i % 10000 == 0 )
         {
            std::stringstream bysize;
            std::stringstream bynum;
            size_t current_pos = std::get<0>(blocks.front());
            if( current_pos > total_block_size )
               total_block_size = current_pos;
            bysize << std::fixed << std::setprecision(5) << double(current_pos) / total_block_size * 100;
            bynum << std::fixed << std::setprecision(5) << double(i)*100/last_block_num;
            ilog(
               "   [by size: ${size}%   ${processed} of ${total}]   [by num: ${num}%   ${i} of ${last}]",
               ("size", bysize.str())
               ("processed", current_pos)
               ("total", total_block_size)
               ("num", bynum.str())
               ("i", i)
               ("last", last_block_num)
            );
         }
         if( i == undo_point )
         {
            ilog( "Writing database to disk at block ${i}", ("i",i) );
            flush();
            ilog( "Done" );
         }
         if( i < undo_point )
            apply_block( block, skip );
         else
         {
            _undo_db.enable();
            push_block( block, skip );
         }
         blocks.pop();
         i++;
      }
   }
   _undo_db.enable();
   auto end = fc::time_point::now();
   ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) );
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }

void database::wipe(const fc::path& data_dir, bool include_blocks)
{
   ilog("Wiping database", ("include_blocks", include_blocks));
   if (_opened) {
     close();
   }
   object_database::wipe(data_dir);
   if( include_blocks )
      fc::remove_all( data_dir / "database" );
}

void database::open(
   const fc::path& data_dir,
   std::function<genesis_state_type()> genesis_loader,
   const std::string& db_version)
{
   try
   {
      bool wipe_object_db = false;
      if( !fc::exists( data_dir / "db_version" ) )
         wipe_object_db = true;
      else
      {
         std::string version_string;
         fc::read_file_contents( data_dir / "db_version", version_string );
         wipe_object_db = ( version_string != db_version );
      }
      if( wipe_object_db ) {
          ilog("Wiping object_database due to missing or wrong version");
          object_database::wipe( data_dir );
          std::ofstream version_file( (data_dir / "db_version").generic_string().c_str(),
                                      std::ios::out | std::ios::binary | std::ios::trunc );
          version_file.write( db_version.c_str(), db_version.size() );
          version_file.close();
      }

      object_database::open(data_dir);

      _block_id_to_block.open(data_dir / "database" / "block_num_to_block");

      if( !find(global_property_id_type()) )
         init_genesis(genesis_loader());
      else
      {
         _p_core_asset_obj = &get( asset_id_type() );
         _p_core_dynamic_data_obj = &get( asset_dynamic_data_id_type() );
         _p_global_prop_obj = &get( global_property_id_type() );
         _p_chain_property_obj = &get( chain_property_id_type() );
         _p_dyn_global_prop_obj = &get( dynamic_global_property_id_type() );
         _p_witness_schedule_obj = &get( witness_schedule_id_type() );
      }

      fc::optional<block_id_type> last_block = _block_id_to_block.last_id();
      if( last_block.valid() )
      {
         FC_ASSERT( *last_block >= head_block_id(),
                    "last block ID does not match current chain state",
                    ("last_block->id", last_block)("head_block_id",head_block_num()) );
         reindex( data_dir );
      }
      _opened = true;
   }
   FC_CAPTURE_LOG_AND_RETHROW( (data_dir) )
}

void database::close(bool rewind)
{
   if (!_opened)
      return;

   // TODO:  Save pending tx's on close()
   clear_pending();

   // pop all of the blocks that we can given our undo history, this should
   // throw when there is no more undo history to pop
   if( rewind )
   {
      try
      {
         uint32_t cutoff = get_dynamic_global_properties().last_irreversible_block_num;

         ilog( "Rewinding from ${head} to ${cutoff}", ("head",head_block_num())("cutoff",cutoff) );
         while( head_block_num() > cutoff )
         {
            block_id_type popped_block_id = head_block_id();
            pop_block();
            _fork_db.remove(popped_block_id); // doesn't throw on missing
         }
      }
      catch ( const fc::exception& e )
      {
         wlog( "Database close unexpected exception: ${e}", ("e", e) );
      }
   }

   // Since pop_block() will move tx's in the popped blocks into pending,
   // we have to clear_pending() after we're done popping to get a clean
   // DB state (issue #336).
   clear_pending();

   object_database::flush();
   object_database::close();

   if( _block_id_to_block.is_open() )
      _block_id_to_block.close();

   _fork_db.reset();

   _opened = false;
}

} }
<|endoftext|>


<commit_before>/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
**********/
// Copyright (c) 1996-2014, Live Networks, Inc.  All rights reserved
//	Help by Carlo Bonamico to get working for Windows
// Delay queue
// Implementation

#include "DelayQueue.hh"
#include "GroupsockHelper.hh"

static const int MILLION = 1000000;

///// Timeval /////

int Timeval::operator>=(const Timeval& arg2) const {
  return seconds() > arg2.seconds()
    || (seconds() == arg2.seconds()
	&& useconds() >= arg2.useconds());
}

void Timeval::operator+=(const DelayInterval& arg2) {
  secs() += arg2.seconds(); usecs() += arg2.useconds();
  if (useconds() >= MILLION) {
    usecs() -= MILLION;
    ++secs();
  }
}

void Timeval::operator-=(const DelayInterval& arg2) {
  secs() -= arg2.seconds(); usecs() -= arg2.useconds();
  if ((int)useconds() < 0) {
    usecs() += MILLION;
    --secs();
  }
  if ((int)seconds() < 0)
    secs() = usecs() = 0;

}

DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) {
  time_base_seconds secs = arg1.seconds() - arg2.seconds();
  time_base_seconds usecs = arg1.useconds() - arg2.useconds();

  if ((int)usecs < 0) {
    usecs += MILLION;
    --secs;
  }
  if ((int)secs < 0)
    return DELAY_ZERO;
  else
    return DelayInterval(secs, usecs);
}

///// DelayInterval /////

DelayInterval operator*(short arg1, const DelayInterval& arg2) {
  time_base_seconds result_seconds = arg1*arg2.seconds();
  time_base_seconds result_useconds = arg1*arg2.useconds();

  time_base_seconds carry = result_useconds/MILLION;
  result_useconds -= carry*MILLION;
  result_seconds += carry;

  return DelayInterval(result_seconds, result_useconds);
}

#ifndef INT_MAX
#define INT_MAX	0x7FFFFFFF
#endif
const DelayInterval DELAY_ZERO(0, 0);
const DelayInterval DELAY_SECOND(1, 0);
const DelayInterval DELAY_MINUTE = 60*DELAY_SECOND;
const DelayInterval DELAY_HOUR = 60*DELAY_MINUTE;
const DelayInterval DELAY_DAY = 24*DELAY_HOUR;
const DelayInterval ETERNITY(INT_MAX, MILLION-1);
// used internally to make the implementation work

///// DelayQueueEntry /////

intptr_t DelayQueueEntry::tokenCounter = 0;

DelayQueueEntry::DelayQueueEntry(DelayInterval delay)
  : fDeltaTimeRemaining(delay) {
  fNext = fPrev = this;
  fToken = ++tokenCounter;
}

DelayQueueEntry::~DelayQueueEntry() {
}

void DelayQueueEntry::handleTimeout() {
  delete this;
}

///// DelayQueue /////

DelayQueue::DelayQueue()
  : DelayQueueEntry(ETERNITY) {
  fLastSyncTime = TimeNow();
}

DelayQueue::~DelayQueue() {
  while (fNext != this) {
    DelayQueueEntry* entryToRemove = fNext;
    removeEntry(entryToRemove);
    delete entryToRemove;
  }
}

void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
  synchronize();

  DelayQueueEntry* cur = head();
  while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) {
    newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
    cur = cur->fNext;
  }

  cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining;

  // Add "newEntry" to the queue, just before "cur":
  newEntry->fNext = cur;
  newEntry->fPrev = cur->fPrev;
  cur->fPrev = newEntry->fPrev->fNext = newEntry;
}

void DelayQueue::updateEntry(DelayQueueEntry* entry, DelayInterval newDelay) {
  if (entry == NULL) return;

  removeEntry(entry);
  entry->fDeltaTimeRemaining = newDelay;
  addEntry(entry);
}

void DelayQueue::updateEntry(intptr_t tokenToFind, DelayInterval newDelay) {
  DelayQueueEntry* entry = findEntryByToken(tokenToFind);
  updateEntry(entry, newDelay);
}

void DelayQueue::removeEntry(DelayQueueEntry* entry) {
  if (entry == NULL || entry->fNext == NULL) return;

  entry->fNext->fDeltaTimeRemaining += entry->fDeltaTimeRemaining;
  entry->fPrev->fNext = entry->fNext;
  entry->fNext->fPrev = entry->fPrev;
  entry->fNext = entry->fPrev = NULL;
  // in case we should try to remove it again
}

DelayQueueEntry* DelayQueue::removeEntry(intptr_t tokenToFind) {
  DelayQueueEntry* entry = findEntryByToken(tokenToFind);
  removeEntry(entry);
  return entry;
}

DelayInterval const& DelayQueue::timeToNextAlarm() {
  if (head()->fDeltaTimeRemaining == DELAY_ZERO) return DELAY_ZERO; // a common case

  synchronize();
  return head()->fDeltaTimeRemaining;
}

void DelayQueue::handleAlarm() {
  if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize();

  if (head()->fDeltaTimeRemaining == DELAY_ZERO) {
    // This event is due to be handled:
    DelayQueueEntry* toRemove = head();
    removeEntry(toRemove); // do this first, in case handler accesses queue

    toRemove->handleTimeout();
  }
}

DelayQueueEntry* DelayQueue::findEntryByToken(intptr_t tokenToFind) {
  DelayQueueEntry* cur = head();
  while (cur != this) {
    if (cur->token() == tokenToFind) return cur;
    cur = cur->fNext;
  }

  return NULL;
}

void DelayQueue::synchronize() {
  // First, figure out how much time has elapsed since the last sync:
  EventTime timeNow = TimeNow();
  if (timeNow < fLastSyncTime) {
    // The system clock has apparently gone back in time; reset our sync time and return:
    fLastSyncTime  = timeNow;
    return;
  }
  DelayInterval timeSinceLastSync = timeNow - fLastSyncTime;
  fLastSyncTime = timeNow;

  // Then, adjust the delay queue for any entries whose time is up:
  DelayQueueEntry* curEntry = head();
  while (timeSinceLastSync >= curEntry->fDeltaTimeRemaining) {
    timeSinceLastSync -= curEntry->fDeltaTimeRemaining;
    curEntry->fDeltaTimeRemaining = DELAY_ZERO;
    curEntry = curEntry->fNext;
  }
  curEntry->fDeltaTimeRemaining -= timeSinceLastSync;
}

///// EventTime /////

EventTime TimeNow() {
  struct timeval tvNow;

  gettimeofday(&tvNow, NULL);

  return EventTime(tvNow.tv_sec, tvNow.tv_usec);
}

const EventTime THE_END_OF_TIME(INT_MAX);
<commit_msg>给DelayQueue类添加注释<commit_after>/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
**********/
// Copyright (c) 1996-2014, Live Networks, Inc.  All rights reserved
//	Help by Carlo Bonamico to get working for Windows
// Delay queue
// Implementation

#include "DelayQueue.hh"
#include "GroupsockHelper.hh"

static const int MILLION = 1000000;

///// Timeval /////

int Timeval::operator>=(const Timeval& arg2) const {
	return seconds() > arg2.seconds()
		|| (seconds() == arg2.seconds()
		&& useconds() >= arg2.useconds());
}

void Timeval::operator+=(const DelayInterval& arg2) {
	secs() += arg2.seconds(); usecs() += arg2.useconds();
	if (useconds() >= MILLION) {
		usecs() -= MILLION;
		++secs();
	}
}

void Timeval::operator-=(const DelayInterval& arg2) {
	secs() -= arg2.seconds(); usecs() -= arg2.useconds();
	if ((int)useconds() < 0) {
		usecs() += MILLION;
		--secs();
	}
	if ((int)seconds() < 0)
		secs() = usecs() = 0;

}

DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) {
	time_base_seconds secs = arg1.seconds() - arg2.seconds();
	time_base_seconds usecs = arg1.useconds() - arg2.useconds();

	if ((int)usecs < 0) {
		usecs += MILLION;
		--secs;
	}
	if ((int)secs < 0)
		return DELAY_ZERO;
	else
		return DelayInterval(secs, usecs);
}

///// DelayInterval /////

DelayInterval operator*(short arg1, const DelayInterval& arg2) {
	time_base_seconds result_seconds = arg1*arg2.seconds();
	time_base_seconds result_useconds = arg1*arg2.useconds();

	time_base_seconds carry = result_useconds / MILLION;
	result_useconds -= carry*MILLION;
	result_seconds += carry;

	return DelayInterval(result_seconds, result_useconds);
}

#ifndef INT_MAX
#define INT_MAX	0x7FFFFFFF
#endif
const DelayInterval DELAY_ZERO(0, 0);
const DelayInterval DELAY_SECOND(1, 0);
const DelayInterval DELAY_MINUTE = 60 * DELAY_SECOND;
const DelayInterval DELAY_HOUR = 60 * DELAY_MINUTE;
const DelayInterval DELAY_DAY = 24 * DELAY_HOUR;
const DelayInterval ETERNITY(INT_MAX, MILLION - 1);
// used internally to make the implementation work

///// DelayQueueEntry /////

intptr_t DelayQueueEntry::tokenCounter = 0;

DelayQueueEntry::DelayQueueEntry(DelayInterval delay)
: fDeltaTimeRemaining(delay) {
	//NextPrevָָԼ
	fNext = fPrev = this;
	//tokenCounter1
	fToken = ++tokenCounter;
}

DelayQueueEntry::~DelayQueueEntry() {
}

void DelayQueueEntry::handleTimeout() {
	delete this;
}

///// DelayQueue /////

DelayQueue::DelayQueue()
: DelayQueueEntry(ETERNITY) {
	//ǰʱΪһͬʱ
	fLastSyncTime = TimeNow();
}

DelayQueue::~DelayQueue() {
	while (fNext != this) {
		DelayQueueEntry* entryToRemove = fNext;
		removeEntry(entryToRemove);
		delete entryToRemove;
	}
}

void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
	synchronize();

	DelayQueueEntry* cur = head();
	while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) {
		newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
		cur = cur->fNext;
	}

	cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining;

	// Add "newEntry" to the queue, just before "cur":
	newEntry->fNext = cur;
	newEntry->fPrev = cur->fPrev;
	cur->fPrev = newEntry->fPrev->fNext = newEntry;
}

void DelayQueue::updateEntry(DelayQueueEntry* entry, DelayInterval newDelay) {
	if (entry == NULL) return;

	removeEntry(entry);
	entry->fDeltaTimeRemaining = newDelay;
	addEntry(entry);
}

void DelayQueue::updateEntry(intptr_t tokenToFind, DelayInterval newDelay) {
	DelayQueueEntry* entry = findEntryByToken(tokenToFind);
	updateEntry(entry, newDelay);
}

void DelayQueue::removeEntry(DelayQueueEntry* entry) {
	if (entry == NULL || entry->fNext == NULL) return;

	entry->fNext->fDeltaTimeRemaining += entry->fDeltaTimeRemaining;
	entry->fPrev->fNext = entry->fNext;
	entry->fNext->fPrev = entry->fPrev;
	entry->fNext = entry->fPrev = NULL;
	// in case we should try to remove it again
}

DelayQueueEntry* DelayQueue::removeEntry(intptr_t tokenToFind) {
	DelayQueueEntry* entry = findEntryByToken(tokenToFind);
	removeEntry(entry);
	return entry;
}

DelayInterval const& DelayQueue::timeToNextAlarm() {
	if (head()->fDeltaTimeRemaining == DELAY_ZERO) return DELAY_ZERO; // a common case

	synchronize();
	return head()->fDeltaTimeRemaining;
}

void DelayQueue::handleAlarm() {
	if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize();

	if (head()->fDeltaTimeRemaining == DELAY_ZERO) {
		// This event is due to be handled:
		DelayQueueEntry* toRemove = head();
		removeEntry(toRemove); // do this first, in case handler accesses queue

		toRemove->handleTimeout();
	}
}

DelayQueueEntry* DelayQueue::findEntryByToken(intptr_t tokenToFind) {
	DelayQueueEntry* cur = head();
	while (cur != this) {
		if (cur->token() == tokenToFind) return cur;
		cur = cur->fNext;
	}

	return NULL;
}

void DelayQueue::synchronize() {
	// First, figure out how much time has elapsed since the last sync:
	//ȣǰʱ̾һͬʱ̵ʱ
	EventTime timeNow = TimeNow();
	if (timeNow < fLastSyncTime) {
		// The system clock has apparently gone back in time; reset our sync time and return:
		//ǰʱСһͬʱ̣˵ϵͳʱǰˣôʱҪһͬʱ̣Ȼ󷵻ء
		fLastSyncTime = timeNow;
		return;
	}
	//ʱ
	DelayInterval timeSinceLastSync = timeNow - fLastSyncTime;
	fLastSyncTime = timeNow;

	// Then, adjust the delay queue for any entries whose time is up:
	//Ȼ󣬵ЩѾʱ˵Entry
	DelayQueueEntry* curEntry = head();
	while (timeSinceLastSync >= curEntry->fDeltaTimeRemaining) {
		timeSinceLastSync -= curEntry->fDeltaTimeRemaining;
		curEntry->fDeltaTimeRemaining = DELAY_ZERO;
		curEntry = curEntry->fNext;
	}
	curEntry->fDeltaTimeRemaining -= timeSinceLastSync;
}

///// EventTime /////

EventTime TimeNow() {
	struct timeval tvNow;
	//gettimeofdayȷ루msҸúϵͳ
	gettimeofday(&tvNow, NULL);

	return EventTime(tvNow.tv_sec, tvNow.tv_usec);
}

const EventTime THE_END_OF_TIME(INT_MAX);
<|endoftext|>


<commit_before>// $Id$
//***************************************************************************
// File:
//	Sparc.cpp
//
// Purpose:
//
// History:
//	7/15/01	 -  Vikram Adve  -  Created
//**************************************************************************/

#include "SparcInternals.h"
#include "llvm/Target/Sparc.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/CodeGen/InstrSelection.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include "llvm/CodeGen/MachineCodeForMethod.h"
#include "llvm/CodeGen/RegisterAllocation.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Method.h"
#include "llvm/PassManager.h"
#include <iostream>
using std::cerr;

// Build the MachineInstruction Description Array...
const MachineInstrDescriptor SparcMachineInstrDesc[] = {
#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
          NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS)             \
  { OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE,             \
          NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS },
#include "SparcInstr.def"
};

//----------------------------------------------------------------------------
// allocateSparcTargetMachine - Allocate and return a subclass of TargetMachine
// that implements the Sparc backend. (the llvm/CodeGen/Sparc.h interface)
//----------------------------------------------------------------------------
//

TargetMachine *allocateSparcTargetMachine() { return new UltraSparc(); }

//---------------------------------------------------------------------------
// class InsertPrologEpilogCode
//
// Insert SAVE/RESTORE instructions for the method
//
// Insert prolog code at the unique method entry point.
// Insert epilog code at each method exit point.
// InsertPrologEpilog invokes these only if the method is not compiled
// with the leaf method optimization.
//
//---------------------------------------------------------------------------
static MachineInstr* minstrVec[MAX_INSTR_PER_VMINSTR];

class InsertPrologEpilogCode : public MethodPass {
  TargetMachine &Target;
public:
  inline InsertPrologEpilogCode(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    MachineCodeForMethod &mcodeInfo = MachineCodeForMethod::get(M);
    if (!mcodeInfo.isCompiledAsLeafMethod()) {
      InsertPrologCode(M);
      InsertEpilogCode(M);
    }
    return false;
  }

  void InsertPrologCode(Method *M);
  void InsertEpilogCode(Method *M);
};

void InsertPrologEpilogCode::InsertPrologCode(Method* method)
{
  BasicBlock* entryBB = method->getEntryNode();
  unsigned N = GetInstructionsForProlog(entryBB, Target, minstrVec);
  assert(N <= MAX_INSTR_PER_VMINSTR);
  MachineCodeForBasicBlock& bbMvec = entryBB->getMachineInstrVec();
  bbMvec.insert(bbMvec.begin(), minstrVec, minstrVec+N);
}

void InsertPrologEpilogCode::InsertEpilogCode(Method* method)
{
  for (Method::iterator I=method->begin(), E=method->end(); I != E; ++I)
    if ((*I)->getTerminator()->getOpcode() == Instruction::Ret)
      {
        BasicBlock* exitBB = *I;
        unsigned N = GetInstructionsForEpilog(exitBB, Target, minstrVec);

        MachineCodeForBasicBlock& bbMvec = exitBB->getMachineInstrVec();
        MachineCodeForInstruction &termMvec =
          MachineCodeForInstruction::get(exitBB->getTerminator());

        // Remove the NOPs in the delay slots of the return instruction
        const MachineInstrInfo &mii = Target.getInstrInfo();
        unsigned numNOPs = 0;
        while (termMvec.back()->getOpCode() == NOP)
          {
            assert( termMvec.back() == bbMvec.back());
            termMvec.pop_back();
            bbMvec.pop_back();
            ++numNOPs;
          }
        assert(termMvec.back() == bbMvec.back());

        // Check that we found the right number of NOPs and have the right
        // number of instructions to replace them.
        unsigned ndelays = mii.getNumDelaySlots(termMvec.back()->getOpCode());
        assert(numNOPs == ndelays && "Missing NOPs in delay slots?");
        assert(N == ndelays && "Cannot use epilog code for delay slots?");

        // Append the epilog code to the end of the basic block.
        bbMvec.push_back(minstrVec[0]);
      }
}

//---------------------------------------------------------------------------
// class UltraSparcFrameInfo
//
// Purpose:
//   Interface to stack frame layout info for the UltraSPARC.
//   Starting offsets for each area of the stack frame are aligned at
//   a multiple of getStackFrameSizeAlignment().
//---------------------------------------------------------------------------

int
UltraSparcFrameInfo::getFirstAutomaticVarOffset(MachineCodeForMethod& ,
                                                bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  return StaticAreaOffsetFromFP;
}

int
UltraSparcFrameInfo::getRegSpillAreaOffset(MachineCodeForMethod& mcInfo,
                                           bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  unsigned int autoVarsSize = mcInfo.getAutomaticVarsSize();
  if (int mod = autoVarsSize % getStackFrameSizeAlignment())
    autoVarsSize += (getStackFrameSizeAlignment() - mod);
  return StaticAreaOffsetFromFP - autoVarsSize;
}

int
UltraSparcFrameInfo::getTmpAreaOffset(MachineCodeForMethod& mcInfo,
                                      bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  unsigned int autoVarsSize = mcInfo.getAutomaticVarsSize();
  unsigned int spillAreaSize = mcInfo.getRegSpillsSize();
  int offset = autoVarsSize + spillAreaSize;
  if (int mod = offset % getStackFrameSizeAlignment())
    offset += (getStackFrameSizeAlignment() - mod);
  return StaticAreaOffsetFromFP - offset;
}

int
UltraSparcFrameInfo::getDynamicAreaOffset(MachineCodeForMethod& mcInfo,
                                          bool& pos) const
{
  // dynamic stack area grows downwards starting at top of opt-args area
  unsigned int optArgsSize = mcInfo.getMaxOptionalArgsSize();
  int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP;
  assert(offset % getStackFrameSizeAlignment() == 0);
  return offset;
}

//---------------------------------------------------------------------------
// class UltraSparcMachine
//
// Purpose:
//   Primary interface to machine description for the UltraSPARC.
//   Primarily just initializes machine-dependent parameters in
//   class TargetMachine, and creates machine-dependent subclasses
//   for classes such as MachineInstrInfo.
//
//---------------------------------------------------------------------------

UltraSparc::UltraSparc()
  : TargetMachine("UltraSparc-Native"),
    instrInfo(*this),
    schedInfo(*this),
    regInfo(*this),
    frameInfo(*this),
    cacheInfo(*this)
{
  optSizeForSubWordData = 4;
  minMemOpWordSize = 8;
  maxAtomicMemOpWordSize = 8;
}

//===---------------------------------------------------------------------===//
// GenerateCodeForTarget Pass
//
// Native code generation for a specified target.
//===---------------------------------------------------------------------===//

class ConstructMachineCodeForMethod : public MethodPass {
  TargetMachine &Target;
public:
  inline ConstructMachineCodeForMethod(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    MachineCodeForMethod::construct(M, Target);
    return false;
  }
};

class InstructionSelection : public MethodPass {
  TargetMachine &Target;
public:
  inline InstructionSelection(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    if (SelectInstructionsForMethod(M, Target))
      cerr << "Instr selection failed for method " << M->getName() << "\n";
    return false;
  }
};

class InstructionScheduling : public MethodPass {
  TargetMachine &Target;
public:
  inline InstructionScheduling(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    if (ScheduleInstructionsWithSSA(M, Target))
      cerr << "Instr scheduling failed for method " << M->getName() << "\n\n";
    return false;
  }
};

struct FreeMachineCodeForMethod : public MethodPass {
  static void freeMachineCode(Instruction *I) {
    MachineCodeForInstruction::destroy(I);
  }

  bool runOnMethod(Method *M) {
    for_each(M->inst_begin(), M->inst_end(), freeMachineCode);
    // Don't destruct MachineCodeForMethod - The global printer needs it
    //MachineCodeForMethod::destruct(M);
    return false;
  }
};

// addPassesToEmitAssembly - This method controls the entire code generation
// process for the ultra sparc.
//
void UltraSparc::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) {
  // Construct and initialize the MachineCodeForMethod object for this method.
  PM.add(new ConstructMachineCodeForMethod(*this));

  PM.add(new InstructionSelection(*this));

  //PM.add(new InstructionScheduling(*this));

  PM.add(getRegisterAllocator(*this));

  //PM.add(new OptimizeLeafProcedures());
  //PM.add(new DeleteFallThroughBranches());
  //PM.add(new RemoveChainedBranches());    // should be folded with previous
  //PM.add(new RemoveRedundantOps());       // operations with %g0, NOP, etc.

  PM.add(new InsertPrologEpilogCode(*this));

  // Output assembly language to the .s file.  Assembly emission is split into
  // two parts: Method output and Global value output.  This is because method
  // output is pipelined with all of the rest of code generation stuff,
  // allowing machine code representations for methods to be free'd after the
  // method has been emitted.
  //
  PM.add(getMethodAsmPrinterPass(PM, Out));
  PM.add(new FreeMachineCodeForMethod());  // Free stuff no longer needed

  // Emit Module level assembly after all of the methods have been processed.
  PM.add(getModuleAsmPrinterPass(PM, Out));
}
<commit_msg>The interface to instruction scheduling is now just a call to get the pass.<commit_after>// $Id$
//***************************************************************************
// File:
//	Sparc.cpp
//
// Purpose:
//
// History:
//	7/15/01	 -  Vikram Adve  -  Created
//**************************************************************************/

#include "SparcInternals.h"
#include "llvm/Target/Sparc.h"
#include "llvm/CodeGen/InstrScheduling.h"
#include "llvm/CodeGen/InstrSelection.h"
#include "llvm/CodeGen/MachineCodeForInstruction.h"
#include "llvm/CodeGen/MachineCodeForMethod.h"
#include "llvm/CodeGen/RegisterAllocation.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Method.h"
#include "llvm/PassManager.h"
#include <iostream>
using std::cerr;

// Build the MachineInstruction Description Array...
const MachineInstrDescriptor SparcMachineInstrDesc[] = {
#define I(ENUM, OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE, \
          NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS)             \
  { OPCODESTRING, NUMOPERANDS, RESULTPOS, MAXIMM, IMMSE,             \
          NUMDELAYSLOTS, LATENCY, SCHEDCLASS, INSTFLAGS },
#include "SparcInstr.def"
};

//----------------------------------------------------------------------------
// allocateSparcTargetMachine - Allocate and return a subclass of TargetMachine
// that implements the Sparc backend. (the llvm/CodeGen/Sparc.h interface)
//----------------------------------------------------------------------------
//

TargetMachine *allocateSparcTargetMachine() { return new UltraSparc(); }

//---------------------------------------------------------------------------
// class InsertPrologEpilogCode
//
// Insert SAVE/RESTORE instructions for the method
//
// Insert prolog code at the unique method entry point.
// Insert epilog code at each method exit point.
// InsertPrologEpilog invokes these only if the method is not compiled
// with the leaf method optimization.
//
//---------------------------------------------------------------------------
static MachineInstr* minstrVec[MAX_INSTR_PER_VMINSTR];

class InsertPrologEpilogCode : public MethodPass {
  TargetMachine &Target;
public:
  inline InsertPrologEpilogCode(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    MachineCodeForMethod &mcodeInfo = MachineCodeForMethod::get(M);
    if (!mcodeInfo.isCompiledAsLeafMethod()) {
      InsertPrologCode(M);
      InsertEpilogCode(M);
    }
    return false;
  }

  void InsertPrologCode(Method *M);
  void InsertEpilogCode(Method *M);
};

void InsertPrologEpilogCode::InsertPrologCode(Method* method)
{
  BasicBlock* entryBB = method->getEntryNode();
  unsigned N = GetInstructionsForProlog(entryBB, Target, minstrVec);
  assert(N <= MAX_INSTR_PER_VMINSTR);
  MachineCodeForBasicBlock& bbMvec = entryBB->getMachineInstrVec();
  bbMvec.insert(bbMvec.begin(), minstrVec, minstrVec+N);
}

void InsertPrologEpilogCode::InsertEpilogCode(Method* method)
{
  for (Method::iterator I=method->begin(), E=method->end(); I != E; ++I)
    if ((*I)->getTerminator()->getOpcode() == Instruction::Ret)
      {
        BasicBlock* exitBB = *I;
        unsigned N = GetInstructionsForEpilog(exitBB, Target, minstrVec);

        MachineCodeForBasicBlock& bbMvec = exitBB->getMachineInstrVec();
        MachineCodeForInstruction &termMvec =
          MachineCodeForInstruction::get(exitBB->getTerminator());

        // Remove the NOPs in the delay slots of the return instruction
        const MachineInstrInfo &mii = Target.getInstrInfo();
        unsigned numNOPs = 0;
        while (termMvec.back()->getOpCode() == NOP)
          {
            assert( termMvec.back() == bbMvec.back());
            termMvec.pop_back();
            bbMvec.pop_back();
            ++numNOPs;
          }
        assert(termMvec.back() == bbMvec.back());

        // Check that we found the right number of NOPs and have the right
        // number of instructions to replace them.
        unsigned ndelays = mii.getNumDelaySlots(termMvec.back()->getOpCode());
        assert(numNOPs == ndelays && "Missing NOPs in delay slots?");
        assert(N == ndelays && "Cannot use epilog code for delay slots?");

        // Append the epilog code to the end of the basic block.
        bbMvec.push_back(minstrVec[0]);
      }
}

//---------------------------------------------------------------------------
// class UltraSparcFrameInfo
//
// Purpose:
//   Interface to stack frame layout info for the UltraSPARC.
//   Starting offsets for each area of the stack frame are aligned at
//   a multiple of getStackFrameSizeAlignment().
//---------------------------------------------------------------------------

int
UltraSparcFrameInfo::getFirstAutomaticVarOffset(MachineCodeForMethod& ,
                                                bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  return StaticAreaOffsetFromFP;
}

int
UltraSparcFrameInfo::getRegSpillAreaOffset(MachineCodeForMethod& mcInfo,
                                           bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  unsigned int autoVarsSize = mcInfo.getAutomaticVarsSize();
  if (int mod = autoVarsSize % getStackFrameSizeAlignment())
    autoVarsSize += (getStackFrameSizeAlignment() - mod);
  return StaticAreaOffsetFromFP - autoVarsSize;
}

int
UltraSparcFrameInfo::getTmpAreaOffset(MachineCodeForMethod& mcInfo,
                                      bool& pos) const
{
  pos = false;                          // static stack area grows downwards
  unsigned int autoVarsSize = mcInfo.getAutomaticVarsSize();
  unsigned int spillAreaSize = mcInfo.getRegSpillsSize();
  int offset = autoVarsSize + spillAreaSize;
  if (int mod = offset % getStackFrameSizeAlignment())
    offset += (getStackFrameSizeAlignment() - mod);
  return StaticAreaOffsetFromFP - offset;
}

int
UltraSparcFrameInfo::getDynamicAreaOffset(MachineCodeForMethod& mcInfo,
                                          bool& pos) const
{
  // dynamic stack area grows downwards starting at top of opt-args area
  unsigned int optArgsSize = mcInfo.getMaxOptionalArgsSize();
  int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP;
  assert(offset % getStackFrameSizeAlignment() == 0);
  return offset;
}

//---------------------------------------------------------------------------
// class UltraSparcMachine
//
// Purpose:
//   Primary interface to machine description for the UltraSPARC.
//   Primarily just initializes machine-dependent parameters in
//   class TargetMachine, and creates machine-dependent subclasses
//   for classes such as MachineInstrInfo.
//
//---------------------------------------------------------------------------

UltraSparc::UltraSparc()
  : TargetMachine("UltraSparc-Native"),
    instrInfo(*this),
    schedInfo(*this),
    regInfo(*this),
    frameInfo(*this),
    cacheInfo(*this)
{
  optSizeForSubWordData = 4;
  minMemOpWordSize = 8;
  maxAtomicMemOpWordSize = 8;
}

//===---------------------------------------------------------------------===//
// GenerateCodeForTarget Pass
//
// Native code generation for a specified target.
//===---------------------------------------------------------------------===//

class ConstructMachineCodeForMethod : public MethodPass {
  TargetMachine &Target;
public:
  inline ConstructMachineCodeForMethod(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    MachineCodeForMethod::construct(M, Target);
    return false;
  }
};

class InstructionSelection : public MethodPass {
  TargetMachine &Target;
public:
  inline InstructionSelection(TargetMachine &T) : Target(T) {}
  bool runOnMethod(Method *M) {
    if (SelectInstructionsForMethod(M, Target))
      cerr << "Instr selection failed for method " << M->getName() << "\n";
    return false;
  }
};

struct FreeMachineCodeForMethod : public MethodPass {
  static void freeMachineCode(Instruction *I) {
    MachineCodeForInstruction::destroy(I);
  }

  bool runOnMethod(Method *M) {
    for_each(M->inst_begin(), M->inst_end(), freeMachineCode);
    // Don't destruct MachineCodeForMethod - The global printer needs it
    //MachineCodeForMethod::destruct(M);
    return false;
  }
};

// addPassesToEmitAssembly - This method controls the entire code generation
// process for the ultra sparc.
//
void UltraSparc::addPassesToEmitAssembly(PassManager &PM, std::ostream &Out) {
  // Construct and initialize the MachineCodeForMethod object for this method.
  PM.add(new ConstructMachineCodeForMethod(*this));

  PM.add(new InstructionSelection(*this));

  //PM.add(createInstructionSchedulingWithSSAPass(*this));

  PM.add(getRegisterAllocator(*this));

  //PM.add(new OptimizeLeafProcedures());
  //PM.add(new DeleteFallThroughBranches());
  //PM.add(new RemoveChainedBranches());    // should be folded with previous
  //PM.add(new RemoveRedundantOps());       // operations with %g0, NOP, etc.

  PM.add(new InsertPrologEpilogCode(*this));

  // Output assembly language to the .s file.  Assembly emission is split into
  // two parts: Method output and Global value output.  This is because method
  // output is pipelined with all of the rest of code generation stuff,
  // allowing machine code representations for methods to be free'd after the
  // method has been emitted.
  //
  PM.add(getMethodAsmPrinterPass(PM, Out));
  PM.add(new FreeMachineCodeForMethod());  // Free stuff no longer needed

  // Emit Module level assembly after all of the methods have been processed.
  PM.add(getModuleAsmPrinterPass(PM, Out));
}
<|endoftext|>


<commit_before>#pragma once

#include "math.hpp"

// grody hack - this should go once C++11 is supported
// on all platforms.
#if defined (__PX4_NUTTX) || defined (__PX4_QURT)
#include <math.h>
#else
#include <cmath>
#endif

namespace matrix
{

template<typename Type>
bool is_finite(Type x) {
#if defined (__PX4_NUTTX) || defined (__PX4_QURT)
    return PX4_ISFINITE(x);
#else
    return std::isfinite(x);
#endif
}

template<typename Type>
Type wrap_pi(Type x)
{
    if (!is_finite(x)) {
        return x;
    }

    while (x >= Type(M_PI)) {
        x -= Type(2.0 * M_PI);

    }

    while (x < Type(-M_PI)) {
        x += Type(2.0 * M_PI);

    }

    return x;
}

}
<commit_msg>QuRT use __builtin_isfinite<commit_after>#pragma once

#include "math.hpp"

// grody hack - this should go once C++11 is supported
// on all platforms.
#if defined (__PX4_NUTTX) || defined (__PX4_QURT)
#include <math.h>
#else
#include <cmath>
#endif

namespace matrix
{

template<typename Type>
bool is_finite(Type x) {
#if defined (__PX4_NUTTX)
    return PX4_ISFINITE(x);
#elif defined (__PX4_QURT)
    return __builtin_isfinite(x);
#else
    return std::isfinite(x);
#endif
}

template<typename Type>
Type wrap_pi(Type x)
{
    if (!is_finite(x)) {
        return x;
    }

    while (x >= Type(M_PI)) {
        x -= Type(2.0 * M_PI);

    }

    while (x < Type(-M_PI)) {
        x += Type(2.0 * M_PI);

    }

    return x;
}

}
<|endoftext|>


<commit_before><commit_msg>Create 1478 - Square Matrix II.cpp<commit_after><|endoftext|>


<commit_before>// Alexis Giraudet
// Théo Cesbron

#ifndef DICTIONARY_HPP
#define DICTIONARY_HPP

#include <ostream>
#include <iostream>
#include <exception>

/**
 * Classe dictionary: tableau associatif
 * Implémentation avec double chaînage de couples.
**/
template <typename K, typename V>
class dictionary
{
    struct _link
    {
        K key;
        V value;
        _link *previous;
        _link *next;
    };

    private:
        _link *_head;
        _link *_tail;
        int _size;

    public:
        dictionary();
        ~dictionary();
        void clear();
        bool contains_key(K key);
        bool contains_value(V value);
        V get(K key);
        bool is_empty();
        K* keys_array();
        std::ostream& print();
        std::ostream& print(std::ostream &os);
        bool put(K key, V value);
        bool remove(K key);
        int size();
        V* values_array();
        void trousseau(K *clfs, int &n);
};

template <typename K, typename V>
dictionary<K,V>::dictionary(): _head(0), _tail(0), _size(0)
{
    ;
}

template <typename K, typename V>
dictionary<K,V>::~dictionary()
{
    clear();
}

/**
 * Vide le dictionnaire.
 * O(n)
**/
template <typename K, typename V>
void dictionary<K,V>::clear()
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        _link *del_link = tmp_link;
        tmp_link = (*tmp_link).next;
        delete del_link;
    }
    _head = 0;
    _tail = 0;
    _size = 0;
}

/**
 * Retourne vrai si le dictionnaire contient la clef key, retourne faux dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::contains_key(K key)
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne vrai si le dictionnaire contient la valeur value, retourne faux dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::contains_value(V value)
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).value == value)
        {
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne la valeur associée à la clef key si le dictionnaire contient la clef key, lève une exception dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
V dictionary<K,V>::get(K key)
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            return (*tmp_link).value;
        }
        tmp_link = (*tmp_link).next;
    }
    throw std::exception();
}

/**
 * Retourne vrai si le dictionnaire est vide, retourne faux dans le cas contraire.
 * O(1)
**/
template <typename K, typename V>
bool dictionary<K,V>::is_empty()
{
    return (_head == 0) && (_tail == 0);
}

/**
 * Retourne un tableau contenant toutes les clefs du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
K* dictionary<K,V>::keys_array()
{
    K *res = new K[_size];
    int i=0;
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        res[i] = (*tmp_link).key;
        i++;
        tmp_link = (*tmp_link).next;
    }
    return res;
}

/**
 * Affiche le dictionnaire sur la sortie standard.
 * O(n)
**/
template <typename K, typename V>
std::ostream& dictionary<K,V>::print()
{
    return print(std::cout);
}

/**
 * Affiche le dictionnaire sur la sortie os.
 * O(n)
**/
template <typename K, typename V>
std::ostream& dictionary<K,V>::print(std::ostream &os)
{
    _link *tmp_link = _head;
    os << "size = " << _size << std::endl;
    while(tmp_link != 0)
    {
        os << (*tmp_link).key << " : " << (*tmp_link).value << std::endl;
        tmp_link = (*tmp_link).next;
    }
    return os;
}

/**
 * Ajoute un nouveau couple clef/valeur au dictionnaire si celui-ci ne contient pas la clef key, si le dictionnaire contient la clef key alors la valeur associée à la clef sera remplacée par value.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::put(K key, V value)
{
    if(is_empty())
    {
        _link *new_link = new _link;
        (*new_link).key = key;
        (*new_link).value = value;
        (*new_link).previous = 0;
        (*new_link).next = 0;
        _head = new_link;
        _tail = new_link;
    }
    else
    {
        _link *tmp_link = _head;
        while(tmp_link != 0)
        {
            if((*tmp_link).key == key)
            {
                (*tmp_link).value = value;
                return false;
            }
            tmp_link = (*tmp_link).next;
        }
        _link *new_link = new _link;
        (*new_link).key = key;
        (*new_link).value = value;
        (*new_link).previous = _tail;
        (*new_link).next = 0;
        (*_tail).next = new_link;
        _tail = new_link;
    }
    _size++;
    return true;
}

/**
 * Supprime le couple clef/valeur associé à la clef key du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::remove(K key)
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            if(tmp_link == _head)
            {
                _head = (*tmp_link).next;
            }
            else
            {
                (*(*tmp_link).previous).next = (*tmp_link).next;
            }

            if(tmp_link == _tail)
            {
                _tail = (*tmp_link).previous;
            }
            else
            {
                (*(*tmp_link).next).previous = (*tmp_link).previous;
            }

            delete tmp_link;
            _size--;
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne la taille du dictionnaire.
 * O(1)
**/
template <typename K, typename V>
int dictionary<K,V>::size()
{
    return _size;
}

/**
 * Retourne un tableau contenant toutes les valeurs du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
V* dictionary<K,V>::values_array()
{
    V *res = new V[_size];
    int i=0;
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        res[i] = (*tmp_link).value;
        i++;
        tmp_link = (*tmp_link).next;
    }
    return res;
}

/**
 * Définition de l'opérateur << pour gérer les flux.
**/
template <typename K, typename V>
std::ostream& operator<< (std::ostream &os, dictionary<K,V> &m)//todo fix set const dictionary
{
    return m.print(os);
}

/**
 *
 * O(n)
**/
template <typename K, typename V>
void dictionary<K,V>::trousseau(K *clfs, int &n)
{
    n = _size;
    int i = 0;
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        clfs[i] = (*tmp_link).key;
        i++;
    }
}

#endif
<commit_msg>fix all const and add references to arguments<commit_after>// Alexis Giraudet
// Théo Cesbron

#ifndef DICTIONARY_HPP
#define DICTIONARY_HPP

#include <ostream>
#include <iostream>
#include <exception>

/**
 * Classe dictionary: tableau associatif
 * Implémentation avec double chaînage de couples.
**/
template <typename K, typename V>
class dictionary
{
    struct _link
    {
        K key;
        V value;
        _link *previous;
        _link *next;
    };

    private:
        _link *_head;
        _link *_tail;
        int _size;

    public:
        dictionary();
        ~dictionary();
        void clear();
        bool contains_key(const K& key) const;
        bool contains_value(const V& value) const;
        V get(const K& key) const;
        bool is_empty() const;
        K* keys_array() const;
        std::ostream& print() const;
        std::ostream& print(std::ostream& os) const;
        bool put(const K& key, const V& value);
        bool remove(const K& key);
        int size() const;
        V* values_array() const;
};

template <typename K, typename V>
dictionary<K,V>::dictionary(): _head(0), _tail(0), _size(0)
{
    ;
}

template <typename K, typename V>
dictionary<K,V>::~dictionary()
{
    clear();
}

/**
 * Vide le dictionnaire.
 * O(n)
**/
template <typename K, typename V>
void dictionary<K,V>::clear()
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        _link *del_link = tmp_link;
        tmp_link = (*tmp_link).next;
        delete del_link;
    }
    _head = 0;
    _tail = 0;
    _size = 0;
}

/**
 * Retourne vrai si le dictionnaire contient la clef key, retourne faux dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::contains_key(const K& key) const
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne vrai si le dictionnaire contient la valeur value, retourne faux dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::contains_value(const V& value) const
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).value == value)
        {
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne la valeur associée à la clef key si le dictionnaire contient la clef key, lève une exception dans le cas contraire.
 * O(n)
**/
template <typename K, typename V>
V dictionary<K,V>::get(const K& key) const
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            return (*tmp_link).value;
        }
        tmp_link = (*tmp_link).next;
    }
    throw std::exception();
}

/**
 * Retourne vrai si le dictionnaire est vide, retourne faux dans le cas contraire.
 * O(1)
**/
template <typename K, typename V>
bool dictionary<K,V>::is_empty() const
{
    return (_head == 0) && (_tail == 0);
}

/**
 * Retourne un tableau contenant toutes les clefs du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
K* dictionary<K,V>::keys_array() const
{
    K *res = new K[_size];
    int i=0;
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        res[i] = (*tmp_link).key;
        i++;
        tmp_link = (*tmp_link).next;
    }
    return res;
}

/**
 * Affiche le dictionnaire sur la sortie standard.
 * O(n)
**/
template <typename K, typename V>
std::ostream& dictionary<K,V>::print() const
{
    return print(std::cout);
}

/**
 * Affiche le dictionnaire sur la sortie os.
 * O(n)
**/
template <typename K, typename V>
std::ostream& dictionary<K,V>::print(std::ostream& os) const
{
    _link *tmp_link = _head;
    os << "size = " << _size << std::endl;
    while(tmp_link != 0)
    {
        os << (*tmp_link).key << " : " << (*tmp_link).value << std::endl;
        tmp_link = (*tmp_link).next;
    }
    return os;
}

/**
 * Ajoute un nouveau couple clef/valeur au dictionnaire si celui-ci ne contient pas la clef key, si le dictionnaire contient la clef key alors la valeur associée à la clef sera remplacée par value.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::put(const K& key, const V& value)
{
    if(is_empty())
    {
        _link *new_link = new _link;
        (*new_link).key = key;
        (*new_link).value = value;
        (*new_link).previous = 0;
        (*new_link).next = 0;
        _head = new_link;
        _tail = new_link;
    }
    else
    {
        _link *tmp_link = _head;
        while(tmp_link != 0)
        {
            if((*tmp_link).key == key)
            {
                (*tmp_link).value = value;
                return false;
            }
            tmp_link = (*tmp_link).next;
        }
        _link *new_link = new _link;
        (*new_link).key = key;
        (*new_link).value = value;
        (*new_link).previous = _tail;
        (*new_link).next = 0;
        (*_tail).next = new_link;
        _tail = new_link;
    }
    _size++;
    return true;
}

/**
 * Supprime le couple clef/valeur associé à la clef key du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
bool dictionary<K,V>::remove(const K& key)
{
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        if((*tmp_link).key == key)
        {
            if(tmp_link == _head)
            {
                _head = (*tmp_link).next;
            }
            else
            {
                (*(*tmp_link).previous).next = (*tmp_link).next;
            }

            if(tmp_link == _tail)
            {
                _tail = (*tmp_link).previous;
            }
            else
            {
                (*(*tmp_link).next).previous = (*tmp_link).previous;
            }

            delete tmp_link;
            _size--;
            return true;
        }
        tmp_link = (*tmp_link).next;
    }
    return false;
}

/**
 * Retourne la taille du dictionnaire.
 * O(1)
**/
template <typename K, typename V>
int dictionary<K,V>::size() const
{
    return _size;
}

/**
 * Retourne un tableau contenant toutes les valeurs du dictionnaire.
 * O(n)
**/
template <typename K, typename V>
V* dictionary<K,V>::values_array() const
{
    V *res = new V[_size];
    int i=0;
    _link *tmp_link = _head;
    while(tmp_link != 0)
    {
        res[i] = (*tmp_link).value;
        i++;
        tmp_link = (*tmp_link).next;
    }
    return res;
}

/**
 * Définition de l'opérateur << pour gérer les flux.
**/
template <typename K, typename V>
std::ostream& operator<<(std::ostream& os, const dictionary<K,V>& m)
{
    return m.print(os);
}

#endif
<|endoftext|>


<commit_before>// Time:  O(nlogn) for total n addNums, O(logn) per addNum, O(1) per findMedian.
// Space: O(n), total space

// Heap solution.
class MedianFinder {
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        // Balance smaller half and larger half.
        if (max_heap_.empty() || num > max_heap_.top()) {
            min_heap_.emplace(num);
            if (min_heap_.size() > max_heap_.size() + 1) {
                max_heap_.emplace(min_heap_.top());
                min_heap_.pop();
            }
        } else {
            max_heap_.emplace(num);
            if (max_heap_.size() > min_heap_.size()) {
                min_heap_.emplace(max_heap_.top());
                max_heap_.pop();
            }
        }
    }

    // Returns the median of current data stream
    double findMedian() {
        return min_heap_.size() == max_heap_.size() ?
                   (max_heap_.top() + min_heap_.top()) / 2.0 :
                   min_heap_.top();

    }

private:
    // min_heap_ stores the larger half seen so far.
    priority_queue<int, vector<int>, greater<int>> min_heap_;
    // max_heap_ stores the smaller half seen so far.
    priority_queue<int, vector<int>, less<int>> max_heap_;

};

// BST solution.
class MedianFinder2 {
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        // Balance smaller half and larger half.
        if (max_bst_.empty() || num > *max_bst_.cbegin()) {
            min_bst_.insert(num);
            if (min_bst_.size() > max_bst_.size() + 1) {
                max_bst_.insert(*min_bst_.cbegin());
                min_bst_.erase(min_bst_.cbegin());
            }
        } else {
            max_bst_.insert(num);
            if (max_bst_.size() > min_bst_.size()) {
                min_bst_.insert(*max_bst_.cbegin());
                max_bst_.erase(max_bst_.cbegin());
            }
        }
    }

    // Returns the median of current data stream
    double findMedian() {
        return min_bst_.size() == max_bst_.size() ?
                   (*max_bst_.cbegin() + *min_bst_.cbegin()) / 2.0 :
                   *min_bst_.cbegin();

    }

private:
   // min_bst_ stores the larger half seen so far.
    multiset<int, less<int>> min_bst_;
    // max_bst_ stores the smaller half seen so far.
    multiset<int, greater<int>> max_bst_;

};

// Your MedianFinder object will be instantiated and called as such:
// MedianFinder mf;
// mf.addNum(1);
// mf.findMedian();
<commit_msg>Update find-median-from-data-stream.cpp<commit_after>// Time:  O(nlogn) for total n addNums, O(logn) per addNum, O(1) per findMedian.
// Space: O(n), total space

// Heap solution.
class MedianFinder {
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        // Balance smaller half and larger half.
        if (max_heap_.empty() || num > max_heap_.top()) {
            min_heap_.emplace(num);
            if (min_heap_.size() > max_heap_.size() + 1) {
                max_heap_.emplace(min_heap_.top());
                min_heap_.pop();
            }
        } else {
            max_heap_.emplace(num);
            if (max_heap_.size() > min_heap_.size()) {
                min_heap_.emplace(max_heap_.top());
                max_heap_.pop();
            }
        }
    }

    // Returns the median of current data stream
    double findMedian() {
        return min_heap_.size() == max_heap_.size() ?
                   (max_heap_.top() + min_heap_.top()) / 2.0 :
                   min_heap_.top();

    }

private:
    // min_heap_ stores the larger half seen so far.
    priority_queue<int, vector<int>, greater<int>> min_heap_;
    // max_heap_ stores the smaller half seen so far.
    priority_queue<int, vector<int>, less<int>> max_heap_;
};

// BST solution.
class MedianFinder2 {
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        // Balance smaller half and larger half.
        if (max_bst_.empty() || num > *max_bst_.cbegin()) {
            min_bst_.insert(num);
            if (min_bst_.size() > max_bst_.size() + 1) {
                max_bst_.insert(*min_bst_.cbegin());
                min_bst_.erase(min_bst_.cbegin());
            }
        } else {
            max_bst_.insert(num);
            if (max_bst_.size() > min_bst_.size()) {
                min_bst_.insert(*max_bst_.cbegin());
                max_bst_.erase(max_bst_.cbegin());
            }
        }
    }

    // Returns the median of current data stream
    double findMedian() {
        return min_bst_.size() == max_bst_.size() ?
                   (*max_bst_.cbegin() + *min_bst_.cbegin()) / 2.0 :
                   *min_bst_.cbegin();

    }

private:
   // min_bst_ stores the larger half seen so far.
    multiset<int, less<int>> min_bst_;
    // max_bst_ stores the smaller half seen so far.
    multiset<int, greater<int>> max_bst_;
};

// Your MedianFinder object will be instantiated and called as such:
// MedianFinder mf;
// mf.addNum(1);
// mf.findMedian();
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "nearfieldmanager_symbian.h"
#include "nearfieldtargetfactory_symbian.h"
#include "../qnearfieldmanager_symbian_p.h"
#include "nearfieldutility_symbian.h"

#include <ndefmessage.h>
#include "debug.h"

/*!
    \class CNearFieldManager
    \brief The Symbain class provides symbian backend implementation to access NFC service.

    \ingroup connectivity-nfc
    \inmodule QtConnectivity

    A Symbian implementation class to support symbian NFC backend.
*/

/*!
    Constructs a CNearFieldManager.
*/
void CNearFieldManager::ConstructL()
    {
    BEGIN
    User::LeaveIfError(iServer.Open());

    //create LLCP provider api
    iLlcpProvider = CLlcpProvider::NewL( iServer );
    iLlcpProvider->AddLlcpLinkListenerL( *this );
    END
    }

/*!
    Start listening all type tags.
*/
void CNearFieldManager::StartTargetDetectionL(const QList<QNearFieldTarget::Type> &aTargetTypes)
    {
    BEGIN
    if (aTargetTypes.size() > 0)
        {
        if (!iNfcTagDiscovery)
            {
            iNfcTagDiscovery = CNfcTagDiscovery::NewL( iServer );
            User::LeaveIfError(iNfcTagDiscovery->AddTagConnectionListener( *this ));
            }

        if (!iTagSubscription)
            {
            iTagSubscription = CNfcTagSubscription::NewL();
            }
        else
            {
            iTagSubscription->RemoveAllConnectionModes();
            }
        for (int i = 0; i < aTargetTypes.size(); ++i)
            {
            switch(aTargetTypes[i])
                {
                case QNearFieldTarget::NfcTagType1:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType1);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 );
                    break;
                case QNearFieldTarget::NfcTagType2:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType2);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 );
                    break;
                case QNearFieldTarget::NfcTagType3:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType3);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 );
                    break;
                case QNearFieldTarget::NfcTagType4:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfc14443P4);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 );
                    break;
                case QNearFieldTarget::MifareTag:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcMifareStd);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd );
                    break;
                case QNearFieldTarget::AnyTarget:
                    iTagSubscription->RemoveAllConnectionModes();
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd );
                    break;
                case QNearFieldTarget::ProprietaryTag:
                    //No conterpart in symbian api
                    break;
                default:
                    break;
                }
            }
        }
    iNfcTagDiscovery->AddTagSubscriptionL( *iTagSubscription );
    END
    }

/*!
    Stop listening all type tags.
*/
void CNearFieldManager::stopTargetDetection()
    {
    BEGIN
    if (iNfcTagDiscovery)
        {
        iNfcTagDiscovery->RemoveTagConnectionListener();
        iNfcTagDiscovery->RemoveTagSubscription();

        if (iTagSubscription)
            {
            delete iTagSubscription;
            iTagSubscription = NULL;
            }
        delete iNfcTagDiscovery;
        iNfcTagDiscovery = NULL;
        }
    END
    }

CNdefRecord::TNdefRecordTnf CNearFieldManager::QTnf2CTnf(const QtMobility::QNdefRecord::TypeNameFormat aQTnf)
    {
    CNdefRecord::TNdefRecordTnf ret = CNdefRecord::EEmpty;
    switch(aQTnf)
        {
        case QtMobility::QNdefRecord::Empty:
            break;
        case QtMobility::QNdefRecord::NfcRtd:
            ret = CNdefRecord::ENfcWellKnown;
            break;
        case QtMobility::QNdefRecord::Mime:
            ret = CNdefRecord::EMime;
            break;
        case QtMobility::QNdefRecord::Uri:
            ret = CNdefRecord::EUri;
            break;
        case QtMobility::QNdefRecord::ExternalRtd:
            ret = CNdefRecord::ENfcExternal;
            break;
        case QtMobility::QNdefRecord::Unknown:
            ret = CNdefRecord::EUnknown;
            break;
        default:
            break;
        }
    return ret;
    }

/*!
    Register interested TNF NDEF message to NFC server.
*/
TInt CNearFieldManager::AddNdefSubscription( const QNdefRecord::TypeNameFormat aTnf,
                                       const QByteArray& aType )
    {
    BEGIN
    TInt err = KErrNone;
    if ( !iNdefDiscovery )
        {
        TRAP(err, iNdefDiscovery = CNdefDiscovery::NewL( iServer ));
        if (err != KErrNone)
            {
            END
            return err;
            }
        err = iNdefDiscovery->AddNdefMessageListener( *this );
        if (err != KErrNone)
            {
            END
            return err;
            }

        }
    TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType));
    err = iNdefDiscovery->AddNdefSubscription( QTnf2CTnf(aTnf), type );
    END
    return err;
    }

/*!
    Unregister interested TNF NDEF message to NFC server.
*/
void CNearFieldManager::RemoveNdefSubscription( const QNdefRecord::TypeNameFormat aTnf,
                                          const QByteArray& aType )
    {
    BEGIN
    if ( iNdefDiscovery )
        {
        TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType));
        iNdefDiscovery->RemoveNdefSubscription( QTnf2CTnf(aTnf), type );
        }
    END
    }

/*!
    Callback function when the tag found by NFC symbain services.
*/
void CNearFieldManager::TagDetected( MNfcTag* aNfcTag )
    {
    BEGIN
    if (aNfcTag)
        {
        QNearFieldTarget* tag = TNearFieldTargetFactory::CreateTargetL(aNfcTag, iServer, &iCallback);
        TInt error = KErrNone;
        QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag));
        Q_UNUSED(error);//just skip the error
        }
    END
    }

/*!
    Callback function when the tag lost event found by NFC symbain services.
*/
void CNearFieldManager::TagLost()
    {
    BEGIN
    TInt error = KErrNone;
    QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected());//just skip the error
    Q_UNUSED(error);//just skip the error
    END
    }

/*!
    Callback function when the LLCP peer found by NFC symbain services.
*/
void CNearFieldManager::LlcpRemoteFound()
    {
    BEGIN
    TInt error = KErrNone;
    QNearFieldTarget* tag = NULL;
    TRAP(error, tag = TNearFieldTargetFactory::CreateTargetL(NULL, iServer, &iCallback));
    if (error == KErrNone)
        {
        QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag) );
        Q_UNUSED(error);//just skip the error
        }
    END
    }

/*!
    Callback function when the LLCP peer lost event found by NFC symbain services.
*/
void CNearFieldManager::LlcpRemoteLost()
    {
    BEGIN
    TInt error = KErrNone;
    QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected());
    Q_UNUSED(error);//just skip the error
    END
    }

/*!
    Callback function when the registerd NDEF message found by NFC symbain services.
*/
void CNearFieldManager::MessageDetected( CNdefMessage* aMessage )
    {
    BEGIN
    if ( aMessage )
        {
        TInt error = KErrNone;
        QNdefMessage msg;
        TRAP(error, msg = QNFCNdefUtility::CNdefMsg2QNdefMsgL( *aMessage));
        if (error == KErrNone)
            {
            QT_TRYCATCH_ERROR(error, iCallback.invokeTargetDetectedHandler(msg));
            Q_UNUSED(error);//just skip the error
            }
        delete aMessage;
        }
    END
    }

/*!
    New a CNearFieldManager instance.
*/
CNearFieldManager::CNearFieldManager( QtMobility::QNearFieldManagerPrivateImpl& aCallback)
    : iCallback(aCallback)
    {
    }

/*!
    Create a new instance of this class.
*/
CNearFieldManager* CNearFieldManager::NewL( QtMobility::QNearFieldManagerPrivateImpl& aCallback)
    {
    BEGIN
    CNearFieldManager* self = new (ELeave) CNearFieldManager(aCallback);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    END
    return self;
    }

/*!
    Destructor.
*/
CNearFieldManager::~CNearFieldManager()
    {
    BEGIN
    if ( iNfcTagDiscovery )
        {
        iNfcTagDiscovery->RemoveTagConnectionListener();
        iNfcTagDiscovery->RemoveTagSubscription();
        }

    delete iTagSubscription;
    delete iNfcTagDiscovery;

    if (iLlcpProvider)
        {
        iLlcpProvider->RemoveLlcpLinkListener();
        }
    delete iLlcpProvider;

    if (iNdefDiscovery)
        {
        iNdefDiscovery->RemoveAllNdefSubscription();
        }
    delete iNdefDiscovery;

    iServer.Close();
    END
    }
//EOF
<commit_msg>fix cannot StartTargetDetectionL twice<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "nearfieldmanager_symbian.h"
#include "nearfieldtargetfactory_symbian.h"
#include "../qnearfieldmanager_symbian_p.h"
#include "nearfieldutility_symbian.h"

#include <ndefmessage.h>
#include "debug.h"

/*!
    \class CNearFieldManager
    \brief The Symbain class provides symbian backend implementation to access NFC service.

    \ingroup connectivity-nfc
    \inmodule QtConnectivity

    A Symbian implementation class to support symbian NFC backend.
*/

/*!
    Constructs a CNearFieldManager.
*/
void CNearFieldManager::ConstructL()
    {
    BEGIN
    User::LeaveIfError(iServer.Open());

    //create LLCP provider api
    iLlcpProvider = CLlcpProvider::NewL( iServer );
    iLlcpProvider->AddLlcpLinkListenerL( *this );
    END
    }

/*!
    Start listening all type tags.
*/
void CNearFieldManager::StartTargetDetectionL(const QList<QNearFieldTarget::Type> &aTargetTypes)
    {
    BEGIN
    if (aTargetTypes.size() > 0)
        {
        if (!iNfcTagDiscovery)
            {
            iNfcTagDiscovery = CNfcTagDiscovery::NewL( iServer );
            User::LeaveIfError(iNfcTagDiscovery->AddTagConnectionListener( *this ));
            }
        else
            {
            iNfcTagDiscovery->RemoveTagSubscription();
            }

        if (!iTagSubscription)
            {
            iTagSubscription = CNfcTagSubscription::NewL();
            }
        else
            {
            iTagSubscription->RemoveAllConnectionModes();
            }
        for (int i = 0; i < aTargetTypes.size(); ++i)
            {
            switch(aTargetTypes[i])
                {
                case QNearFieldTarget::NfcTagType1:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType1);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 );
                    break;
                case QNearFieldTarget::NfcTagType2:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType2);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 );
                    break;
                case QNearFieldTarget::NfcTagType3:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcType3);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 );
                    break;
                case QNearFieldTarget::NfcTagType4:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfc14443P4);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 );
                    break;
                case QNearFieldTarget::MifareTag:
                    iTagSubscription->RemoveConnectionMode(TNfcConnectionInfo::ENfcMifareStd);
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd );
                    break;
                case QNearFieldTarget::AnyTarget:
                    iTagSubscription->RemoveAllConnectionModes();
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType1 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType2 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcType3 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfc14443P4 );
                    iTagSubscription->AddConnectionModeL( TNfcConnectionInfo::ENfcMifareStd );
                    break;
                case QNearFieldTarget::ProprietaryTag:
                    //No conterpart in symbian api
                    break;
                default:
                    break;
                }
            }
        }
    iNfcTagDiscovery->AddTagSubscriptionL( *iTagSubscription );
    END
    }

/*!
    Stop listening all type tags.
*/
void CNearFieldManager::stopTargetDetection()
    {
    BEGIN
    if (iNfcTagDiscovery)
        {
        iNfcTagDiscovery->RemoveTagConnectionListener();
        iNfcTagDiscovery->RemoveTagSubscription();

        if (iTagSubscription)
            {
            delete iTagSubscription;
            iTagSubscription = NULL;
            }
        delete iNfcTagDiscovery;
        iNfcTagDiscovery = NULL;
        }
    END
    }

CNdefRecord::TNdefRecordTnf CNearFieldManager::QTnf2CTnf(const QtMobility::QNdefRecord::TypeNameFormat aQTnf)
    {
    CNdefRecord::TNdefRecordTnf ret = CNdefRecord::EEmpty;
    switch(aQTnf)
        {
        case QtMobility::QNdefRecord::Empty:
            break;
        case QtMobility::QNdefRecord::NfcRtd:
            ret = CNdefRecord::ENfcWellKnown;
            break;
        case QtMobility::QNdefRecord::Mime:
            ret = CNdefRecord::EMime;
            break;
        case QtMobility::QNdefRecord::Uri:
            ret = CNdefRecord::EUri;
            break;
        case QtMobility::QNdefRecord::ExternalRtd:
            ret = CNdefRecord::ENfcExternal;
            break;
        case QtMobility::QNdefRecord::Unknown:
            ret = CNdefRecord::EUnknown;
            break;
        default:
            break;
        }
    return ret;
    }

/*!
    Register interested TNF NDEF message to NFC server.
*/
TInt CNearFieldManager::AddNdefSubscription( const QNdefRecord::TypeNameFormat aTnf,
                                       const QByteArray& aType )
    {
    BEGIN
    TInt err = KErrNone;
    if ( !iNdefDiscovery )
        {
        TRAP(err, iNdefDiscovery = CNdefDiscovery::NewL( iServer ));
        if (err != KErrNone)
            {
            END
            return err;
            }
        err = iNdefDiscovery->AddNdefMessageListener( *this );
        if (err != KErrNone)
            {
            END
            return err;
            }

        }
    TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType));
    err = iNdefDiscovery->AddNdefSubscription( QTnf2CTnf(aTnf), type );
    END
    return err;
    }

/*!
    Unregister interested TNF NDEF message to NFC server.
*/
void CNearFieldManager::RemoveNdefSubscription( const QNdefRecord::TypeNameFormat aTnf,
                                          const QByteArray& aType )
    {
    BEGIN
    if ( iNdefDiscovery )
        {
        TPtrC8 type(QNFCNdefUtility::QByteArray2TPtrC8(aType));
        iNdefDiscovery->RemoveNdefSubscription( QTnf2CTnf(aTnf), type );
        }
    END
    }

/*!
    Callback function when the tag found by NFC symbain services.
*/
void CNearFieldManager::TagDetected( MNfcTag* aNfcTag )
    {
    BEGIN
    if (aNfcTag)
        {
        QNearFieldTarget* tag = TNearFieldTargetFactory::CreateTargetL(aNfcTag, iServer, &iCallback);
        TInt error = KErrNone;
        QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag));
        Q_UNUSED(error);//just skip the error
        }
    END
    }

/*!
    Callback function when the tag lost event found by NFC symbain services.
*/
void CNearFieldManager::TagLost()
    {
    BEGIN
    TInt error = KErrNone;
    QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected());//just skip the error
    Q_UNUSED(error);//just skip the error
    END
    }

/*!
    Callback function when the LLCP peer found by NFC symbain services.
*/
void CNearFieldManager::LlcpRemoteFound()
    {
    BEGIN
    TInt error = KErrNone;
    QNearFieldTarget* tag = NULL;
    TRAP(error, tag = TNearFieldTargetFactory::CreateTargetL(NULL, iServer, &iCallback));
    if (error == KErrNone)
        {
        QT_TRYCATCH_ERROR(error, iCallback.targetFound(tag) );
        Q_UNUSED(error);//just skip the error
        }
    END
    }

/*!
    Callback function when the LLCP peer lost event found by NFC symbain services.
*/
void CNearFieldManager::LlcpRemoteLost()
    {
    BEGIN
    TInt error = KErrNone;
    QT_TRYCATCH_ERROR(error, iCallback.targetDisconnected());
    Q_UNUSED(error);//just skip the error
    END
    }

/*!
    Callback function when the registerd NDEF message found by NFC symbain services.
*/
void CNearFieldManager::MessageDetected( CNdefMessage* aMessage )
    {
    BEGIN
    if ( aMessage )
        {
        TInt error = KErrNone;
        QNdefMessage msg;
        TRAP(error, msg = QNFCNdefUtility::CNdefMsg2QNdefMsgL( *aMessage));
        if (error == KErrNone)
            {
            QT_TRYCATCH_ERROR(error, iCallback.invokeTargetDetectedHandler(msg));
            Q_UNUSED(error);//just skip the error
            }
        delete aMessage;
        }
    END
    }

/*!
    New a CNearFieldManager instance.
*/
CNearFieldManager::CNearFieldManager( QtMobility::QNearFieldManagerPrivateImpl& aCallback)
    : iCallback(aCallback)
    {
    }

/*!
    Create a new instance of this class.
*/
CNearFieldManager* CNearFieldManager::NewL( QtMobility::QNearFieldManagerPrivateImpl& aCallback)
    {
    BEGIN
    CNearFieldManager* self = new (ELeave) CNearFieldManager(aCallback);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    END
    return self;
    }

/*!
    Destructor.
*/
CNearFieldManager::~CNearFieldManager()
    {
    BEGIN
    if ( iNfcTagDiscovery )
        {
        iNfcTagDiscovery->RemoveTagConnectionListener();
        iNfcTagDiscovery->RemoveTagSubscription();
        }

    delete iTagSubscription;
    delete iNfcTagDiscovery;

    if (iLlcpProvider)
        {
        iLlcpProvider->RemoveLlcpLinkListener();
        }
    delete iLlcpProvider;

    if (iNdefDiscovery)
        {
        iNdefDiscovery->RemoveAllNdefSubscription();
        }
    delete iNdefDiscovery;

    iServer.Close();
    END
    }
//EOF
<|endoftext|>