<commit_before>/**
 * Tests for CacheTagArray
 * @author Oleg Ladin, Denis Los
 */

#include <catch.hpp>

// Module
#include "../cache_tag_array.h"

#include <infra/types.h>

#include <fstream>
#include <map>
#include <vector>

TEST_CASE( "pass_wrong_arguments: Pass_Wrong_Arguments_To_CacheTagArraySizeCheck")
{
    // size_in_bytes = 128
    // ways = 0
    // line_size = 4
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 0, 4, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 0
    // ways = 16
    // line_size = 4
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 0, 16, 4, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 128
    // ways = 16
    // line_size = 0
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 16, 0, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 128
    // ways = 16
    // line_size = 4
    // addr_size_in_bits = 0
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 16, 4, 0), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 0
    // ways = 0
    // line_size = 0
    // addr_size_in_bits = 0
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 0, 0, 0, 0), CacheTagArrayInvalidSizeException);

    // size_in_bytes is power of 2,
    // but the number of ways is not
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 64, 9, 4, 32), CacheTagArrayInvalidSizeException);

    // the number of ways is power of 2,
    // but size_in_bytes is not
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 500, 16, 4, 32), CacheTagArrayInvalidSizeException);

    // line_size is not power of 2
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 512, 16, 12, 32), CacheTagArrayInvalidSizeException);

    // address is 48 bits
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 4, 4, 48), CacheTagArrayInvalidSizeException);

    // too small cache
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 8, 4, 4, 32), CacheTagArrayInvalidSizeException);
}

static const uint32 LINE_SIZE = 4; // why not 32?

struct CacheParameters {
    uint32 associativity;
    uint32 cache_size;
    bool operator<(const CacheParameters& rhs) const {
        if (associativity == rhs.associativity)
            return (cache_size < rhs.cache_size);

        return associativity < rhs.associativity;
    }
};

struct CacheResults {
    uint32 misses;
    uint32 hits;
};

static const std::map<CacheParameters, CacheResults> golden =
{
    // ways, size, misses, hits
    {{ 1, 1 * 1024},  {390614, 728471}},
    {{ 1, 2 * 1024},  {306137, 812948}},
    {{ 1, 4 * 1024},  {242688, 876397}},
    {{ 1, 8 * 1024},  {183876, 935209}},
    {{ 1, 16 * 1024}, {142662, 976423}},
    {{ 1, 32 * 1024}, {100330, 1018755}},
    {{ 1, 64 * 1024}, {68760, 1050325}},
    {{ 1, 128 * 1024},{43114, 1075971}},
    {{ 1, 256 * 1024},{38295, 1080790}},
    {{ 1, 512 * 1024},{31134, 1087951}},
    {{ 1, 1024 * 1024}, {31064, 1088021}},
    {{ 2, 1 * 1024},  {358489, 760596}},
    {{ 2, 2 * 1024},  {266913, 852172}},
    {{ 2, 4 * 1024},  {201319, 917766}},
    {{ 2, 8 * 1024},  {161085, 958000}},
    {{ 2, 16 * 1024}, {123902, 995183}},
    {{ 2, 32 * 1024}, {88968, 1030117}},
    {{ 2, 64 * 1024}, {53685, 1065400}},
    {{ 2, 128 * 1024},{37244, 1081841}},
    {{ 2, 256 * 1024},{30626, 1088459}},
    {{ 2, 512 * 1024},{30596, 1088489}},
    {{ 2, 1024 * 1024}, {30400, 1088685}},
    {{ 4, 1 * 1024},  {343381, 775704}},
    {{ 4, 2 * 1024},  {257323, 861762}},
    {{ 4, 4 * 1024},  {188436, 930649}},
    {{ 4, 8 * 1024},  {149047, 970038}},
    {{ 4, 16 * 1024}, {119688, 999397}},
    {{ 4, 32 * 1024}, {86607, 1032478}},
    {{ 4, 64 * 1024}, {48190, 1070895}},
    {{ 4, 128 * 1024},{32202, 1086883}},
    {{ 4, 256 * 1024},{30597, 1088488}},
    {{ 4, 512 * 1024},{30400, 1088685}},
    {{ 4, 1024 * 1024}, {30400, 1088685}},
    {{ 8, 1 * 1024},  {340031, 779054}},
    {{ 8, 2 * 1024},  {253850, 865235}},
    {{ 8, 4 * 1024},  {185989, 933096}},
    {{ 8, 8 * 1024},  {146187, 972898}},
    {{ 8, 16 * 1024}, {117343, 1001742}},
    {{ 8, 32 * 1024}, {85325, 1033760}},
    {{ 8, 64 * 1024}, {45835, 1073250}},
    {{ 8, 128 * 1024},{30601, 1088484}},
    {{ 8, 256 * 1024},{30400, 1088685}},
    {{ 8, 512 * 1024},{30400, 1088685}},
    {{ 8, 1024 * 1024}, {30400, 1088685}},
    {{ 16, 1 * 1024},  {338084, 781001}},
    {{ 16, 2 * 1024},  {252963, 866122}},
    {{ 16, 4 * 1024},  {185231, 933854}},
    {{ 16, 8 * 1024},  {145383, 973702}},
    {{ 16, 16 * 1024}, {116731, 1002354}},
    {{ 16, 32 * 1024}, {84471, 1034614}},
    {{ 16, 64 * 1024}, {44084, 1075001}},
    {{ 16, 128 * 1024},{30463, 1088622}},
    {{ 16, 256 * 1024},{30400, 1088685}},
    {{ 16, 512 * 1024},{30400, 1088685}},
    {{ 16, 1024 * 1024}, {30400, 1088685}},
    // Full associativity
    {{ (1 * 1024 / LINE_SIZE), 1 * 1024},     {337333, 781752}},
    {{ (2 * 1024 / LINE_SIZE), 2 * 1024},     {250920, 868165}},
    {{ (4 * 1024 / LINE_SIZE), 4 * 1024},     {184816, 934269}},
    {{ (8 * 1024 / LINE_SIZE), 8 * 1024},     {145443, 973642}},
    {{ (16 * 1024 / LINE_SIZE), 16 * 1024},   {116112, 1002973}},
    {{ (32 * 1024 / LINE_SIZE), 32 * 1024},   {82732, 1036353}},
    {{ (64 * 1024 / LINE_SIZE), 64 * 1024},   {41512, 1077573}},
    {{ (128 * 1024 / LINE_SIZE), 128 * 1024}, {30400, 1088685}},
    {{ (256 * 1024 / LINE_SIZE), 256 * 1024}, {30400, 1088685}},
    {{ (512 * 1024 / LINE_SIZE), 512 * 1024}, {30400, 1088685}},
    {{ (1024 * 1024 / LINE_SIZE), 1024 * 1024}, {30400, 1088685}},
};

static void test( const std::vector<Addr>& values, uint32 associativity, uint32 _size)
{
    CacheTagArray cta(_size, associativity, LINE_SIZE);

    std::size_t hits = 0;
    std::size_t misses = 0;

    for ( const auto& addr : values)
        if ( cta.read( addr).first)
        {
            hits++;
        }
        else
        {
            misses++;
            cta.write( addr); // load to the
        }

    // check whether sample hit and miss numbers
    // are equal to the evaluated ones
    CHECK( hits == golden.at({associativity, _size}).hits);
    CHECK( misses == golden.at({associativity, _size}).misses);
}

static std::vector<Addr> read_values()
{
    const std::string MEM_TRACE_FILENAME = TEST_DATA_PATH "mem_trace.txt";

    // open and check mem_trace file
    std::ifstream mem_trace_file;
    mem_trace_file.open( MEM_TRACE_FILENAME, std::ifstream::in);
    CHECK( mem_trace_file.is_open());

    Addr addr;
    std::vector<Addr> values;
    values.reserve(100000);
    while ( mem_trace_file >> std::hex >> addr)
        values.push_back(addr);

    mem_trace_file.close();

    return values;
}

TEST_CASE( "miss_rate_sim: Miss_Rate_Sim_Test")
{
    // Input data
    auto values = read_values();

    // test CacheTagArray on different parameters
    for ( uint32 cache_size : { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 })
        for ( uint32 associativity : { 1, 2, 4, 8, 16, int(cache_size * 1024 / LINE_SIZE) })
            test( values, associativity, cache_size * 1024);
}
<commit_msg>EOL of Miss Rate Sim as a CacheTagArray test (#980)<commit_after>/**
 * Tests for CacheTagArray
 * @author Oleg Ladin, Denis Los
 */

#include <catch.hpp>

// Module
#include "../cache_tag_array.h"

#include <infra/types.h>

#include <fstream>
#include <map>
#include <vector>

TEST_CASE( "pass_wrong_arguments: Pass_Wrong_Arguments_To_CacheTagArraySizeCheck")
{
    // size_in_bytes = 128
    // ways = 0
    // line_size = 4
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 0, 4, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 0
    // ways = 16
    // line_size = 4
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 0, 16, 4, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 128
    // ways = 16
    // line_size = 0
    // addr_size_in_bits = 32
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 16, 0, 32), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 128
    // ways = 16
    // line_size = 4
    // addr_size_in_bits = 0
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 16, 4, 0), CacheTagArrayInvalidSizeException);

    // size_in_bytes = 0
    // ways = 0
    // line_size = 0
    // addr_size_in_bits = 0
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 0, 0, 0, 0), CacheTagArrayInvalidSizeException);

    // size_in_bytes is power of 2,
    // but the number of ways is not
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 64, 9, 4, 32), CacheTagArrayInvalidSizeException);

    // the number of ways is power of 2,
    // but size_in_bytes is not
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 500, 16, 4, 32), CacheTagArrayInvalidSizeException);

    // line_size is not power of 2
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 512, 16, 12, 32), CacheTagArrayInvalidSizeException);

    // address is 48 bits
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 128, 4, 4, 48), CacheTagArrayInvalidSizeException);

    // too small cache
    CHECK_THROWS_AS( CacheTagArraySizeCheck( 8, 4, 4, 32), CacheTagArrayInvalidSizeException);
}

static const uint32 LINE_SIZE = 4; // why not 32?

<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//									     //
// This class provides access to ZDC digits in raw data.		     //
//									     //
// It loops over all ZDC digits in the raw data given by the AliRawReader.   //
// The Next method goes to the next digit. If there are no digits left	     //
// it returns kFALSE.							     //
// Getters provide information about the current digit. 		     //
//									     //
///////////////////////////////////////////////////////////////////////////////

#include "AliZDCRawStream.h"
#include "AliRawReader.h"
#include "AliLog.h"

ClassImp(AliZDCRawStream)

//_____________________________________________________________________________
AliZDCRawStream::AliZDCRawStream(AliRawReader* rawReader) :
  fRawReader(rawReader),
  fRawADC(0),
  fADCModule(0),
  fADCValue(-1),
  fADCGain(0),
  fIsADCDataWord(kFALSE)
{
  // Create an object to read ZDC raw digits

  fRawReader->Select("ZDC");
}

//_____________________________________________________________________________
AliZDCRawStream::AliZDCRawStream(const AliZDCRawStream& stream) :
  TObject(stream)
{
  // Copy constructor
  fRawADC = stream.GetADCRaw();
  for(Int_t j=0; j<2; j++) fSector[j] = stream.GetSector(j);
  fADCModule = stream.GetADCModule();
  fADCValue = stream.GetADCValue();
  fADCGain = stream.GetADCGain();
  fIsADCDataWord = stream.IsADCDataWord();

}

//_____________________________________________________________________________
AliZDCRawStream& AliZDCRawStream::operator = (const AliZDCRawStream&
					      /* stream */)
{
  // Assignment operator
  Fatal("operator =", "assignment operator not implemented");
  return *this;
}

//_____________________________________________________________________________
AliZDCRawStream::~AliZDCRawStream()
{
// Destructor

}

//_____________________________________________________________________________
Bool_t AliZDCRawStream::Next()
{
  // Read the next raw digit
  // Returns kFALSE if there is no digit left

  if(!fRawReader->ReadNextInt((UInt_t&) fRawADC)) return kFALSE;
  fIsADCDataWord = kFALSE;

  printf("fRawADC %x",fRawADC);
  //
  if((fRawADC == 0xe52b6300) || (fRawADC == 0xdeadface) || (fRawADC == 0xffffffff) || (fRawADC == 0xdeadbeef)){
    printf("    This is a DARC header!!!\n");
  }
  else if(fRawADC == 0xcafefade) printf("    End of data!\n");
  else{
    if((fRawADC & 0x6000000) == 0x6000000){//Not valid datum
      printf("    AliZDCRawStream -> Not valid datum in ADC module!!! %d\n",fADCModule);
    }
    else if((fRawADC & 0x4000000) == 0x4000000){//ADC EOB
      printf("    AliZDCRawStream -> ADC %d End Of Block - Event no. %d\n\n",fADCModule, (fRawADC & 0xffffff));
      fSector[0] = fSector[1] = 99;
    }
    else if((fRawADC & 0x2000000) == 0x2000000){//ADC Header
      fADCModule++;
      printf("    AliZDCRawStream -> Header ADC %d - ADC datum contains %d data words \n",fADCModule,((fRawADC & 0x3f00) >> 8));
    }
    else{//ADC data word
      fIsADCDataWord = kTRUE;
      printf(" \t \t ADC Data Word");
      if(!(fRawADC & 0x1000) && !(fRawADC & 0x2000)){ // Valid ADC data
        fADCGain = (fRawADC & 0x10000) >> 16;
        fADCValue = (fRawADC & 0xfff);
        //
        Int_t vADCChannel = (fRawADC & 0x1e0000) >> 17;
        if(fADCModule==1 || fADCModule==3){  //1st & 3rd ADC modules
          if(vADCChannel >= 0 && vADCChannel <= 4){
            fSector[0] = 1; // ZN1
            fSector[1] = vADCChannel;
          }
          else if(vADCChannel >= 8 && vADCChannel <= 12){
            fSector[0] = 2; // ZP1
            fSector[1] = vADCChannel-8;
          }
          else if(vADCChannel == 5 || vADCChannel == 13){
            fSector[0] = 3; // ZEM 1,2
            fSector[1] = ((vADCChannel-5)/8)+1;
          }
        }
        else if(fADCModule==2 || fADCModule==4){  //2nd & 4rth ADC modules
          if(vADCChannel >= 0 && vADCChannel <= 4){
            fSector[0] = 4; // ZN2
          fSector[1] = vADCChannel;
          }
          else if(vADCChannel >= 8 && vADCChannel <= 12){
            fSector[0] = 5; // ZP2
            fSector[1] = vADCChannel-8;
          }
          else if(vADCChannel == 5 || vADCChannel == 13){
            fSector[0] = (vADCChannel-5)*3/8+1; // PM Ref 1,2
            fSector[1] = 5;
          }
        }
        else{
          AliWarning("    AliZDCRawStream -> No valid ADC module!!!");
          printf(" ADCmod = %d\n", fADCModule);
          fRawReader->AddMajorErrorLog(kInvalidADCModule);
        }
        printf("  ADC %d ch %d range %d -> det %d quad %d value %x\n",
           fADCModule, vADCChannel, fADCGain, fSector[0], fSector[1], fADCValue);//Chiara debugging

      }
      else if(fRawADC & 0x1000)
        printf("  ADC %d ch %d range %d  overflow\n",fADCModule, (fRawADC & 0x1e0000) >> 17, fADCGain); // Overflow
      else if(fRawADC & 0x2000)
        printf("  ADC %d ch %d range %d  underflow\n",fADCModule, (fRawADC & 0x1e0000) >> 17, fADCGain); // Underflow
    }
  }//Not DARC Header

  return kTRUE;
}
<commit_msg>AliZDCRawStream class updated<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//									     //
// This class provides access to ZDC digits in raw data.		     //
//									     //
// It loops over all ZDC digits in the raw data given by the AliRawReader.   //
// The Next method goes to the next digit. If there are no digits left	     //
// it returns kFALSE.							     //
// Getters provide information about the current digit. 		     //
//									     //
///////////////////////////////////////////////////////////////////////////////

#include "AliZDCRawStream.h"
#include "AliRawReader.h"
#include "AliLog.h"

ClassImp(AliZDCRawStream)

//_____________________________________________________________________________
AliZDCRawStream::AliZDCRawStream(AliRawReader* rawReader) :
  fRawReader(rawReader),
  fRawADC(0),
  fADCModule(0),
  fADCValue(-1),
  fADCGain(0),
  fIsADCDataWord(kFALSE)
{
  // Create an object to read ZDC raw digits

  fRawReader->Select("ZDC");
}

//_____________________________________________________________________________
AliZDCRawStream::AliZDCRawStream(const AliZDCRawStream& stream) :
  TObject(stream)
{
  // Copy constructor
  fRawADC = stream.GetADCRaw();
  for(Int_t j=0; j<2; j++) fSector[j] = stream.GetSector(j);
  fADCModule = stream.GetADCModule();
  fADCValue = stream.GetADCValue();
  fADCGain = stream.GetADCGain();
  fIsADCDataWord = stream.IsADCDataWord();

}

//_____________________________________________________________________________
AliZDCRawStream& AliZDCRawStream::operator = (const AliZDCRawStream&
					      /* stream */)
{
  // Assignment operator
  Fatal("operator =", "assignment operator not implemented");
  return *this;
}

//_____________________________________________________________________________
AliZDCRawStream::~AliZDCRawStream()
{
// Destructor

}

//_____________________________________________________________________________
Bool_t AliZDCRawStream::Next()
{
  // Read the next raw digit
  // Returns kFALSE if there is no digit left

  if(!fRawReader->ReadNextInt((UInt_t&) fRawADC)) return kFALSE;
  fIsADCDataWord = kFALSE;

  //
  // --- DARC header
  if((fRawADC == 0xe52b6300) || (fRawADC == 0xe52c0300) ||  (fRawADC == 0xffffffff) ||
     (fRawADC == 0xdeadface) || (fRawADC == 0xdeadbeef)){
    //printf("    This is a DARC header!!!\n");
  }
  // --- End of data
  else if(fRawADC == 0xcafefade){
    //printf("    End of data!\n");
  }
  // --- ADC buffer
  else{
    if((fRawADC & 0x6000000) == 0x6000000){ // Not valid datum
      //printf("    AliZDCRawStream -> Not valid datum in ADC module!!! %d\n",fADCModule);
    }
    else if((fRawADC & 0x4000000) == 0x4000000){ // ADC EOB
      //printf("    AliZDCRawStream -> ADC %d End Of Block - Event no. %d\n\n",fADCModule, (fRawADC & 0xffffff));
      fSector[0] = fSector[1] = 99;
    }
    else if((fRawADC & 0x2000000) == 0x2000000){ // ADC Header
      printf("  fRawADC %x\n",fRawADC);
      // Reading the GEO address to determine ADC module
      fADCModule = (fRawADC & 0xf8000000) >> 27;
      fADCModule ++;
      //printf("    AliZDCRawStream -> HEADER: ADC mod. %d contains %d data words \n",fADCModule,((fRawADC & 0x3f00) >> 8));
    }
    else{ // ADC data word
      fIsADCDataWord = kTRUE;
      //printf(" \t \t ADC Data Word");
      //
      if(!(fRawADC & 0x1000) && !(fRawADC & 0x2000)){ // Valid ADC data
        fADCGain = (fRawADC & 0x10000) >> 16;
        fADCValue = (fRawADC & 0xfff);
        //
        Int_t vADCChannel = (fRawADC & 0x1e0000) >> 17;
        if(fADCModule==1 || fADCModule==3){  //1st & 3rd ADC modules
          if(vADCChannel >= 0 && vADCChannel <= 4){
            fSector[0] = 1; // ZN1
            fSector[1] = vADCChannel;
          }
          else if(vADCChannel >= 8 && vADCChannel <= 12){
            fSector[0] = 2; // ZP1
            fSector[1] = vADCChannel-8;
          }
          else if(vADCChannel == 5 || vADCChannel == 13){
            fSector[0] = 3; // ZEM 1,2
            fSector[1] = ((vADCChannel-5)/8)+1;
          }
        }
        else if(fADCModule==2 || fADCModule==4){  //2nd & 4rth ADC modules
          if(vADCChannel >= 0 && vADCChannel <= 4){
            fSector[0] = 4; // ZN2
          fSector[1] = vADCChannel;
          }
          else if(vADCChannel >= 8 && vADCChannel <= 12){
            fSector[0] = 5; // ZP2
            fSector[1] = vADCChannel-8;
          }
          else if(vADCChannel == 5 || vADCChannel == 13){
            fSector[0] = (vADCChannel-5)*3/8+1; // PM Ref 1,2
            fSector[1] = 5;
          }
        }
        else{
          AliWarning("    AliZDCRawStream -> No valid ADC module\n");
          fRawReader->AddMajorErrorLog(kInvalidADCModule);
        }
        //printf("  ADC %d ch %d range %d -> det %d quad %d value %x\n",
        //   fADCModule, vADCChannel, fADCGain, fSector[0], fSector[1], fADCValue);//Chiara debugging

      }// Valid ADC data
      else if(fRawADC & 0x1000){
        //printf("  ADC %d ch %d range %d  overflow\n",fADCModule, (fRawADC & 0x1e0000) >> 17, fADCGain); // Overflow
      }
      else if(fRawADC & 0x2000){
        //printf("  ADC %d ch %d range %d  underflow\n",fADCModule, (fRawADC & 0x1e0000) >> 17, fADCGain); // Underflow
      }
    }// ADC word
  }//Not DARC Header

  return kTRUE;
}
<|endoftext|>


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

#include <pcl/point_types.h>
#include <pcl/impl/instantiate.hpp>
#include <pcl/segmentation/supervoxels.h>
#include <pcl/segmentation/impl/supervoxels.hpp>
//These are needed to link with our local PointSuperVoxel
#include <pcl/features/impl/normal_3d_omp.hpp>
#include <pcl/features/impl/normal_3d.hpp>
#include <pcl/search/impl/organized.hpp>
#include <pcl/kdtree/impl/kdtree_flann.hpp>

// Instantiations of specific point types
template class pcl::SuperVoxels<pcl::PointXYZRGBA>;
template class pcl::SuperVoxels<pcl::PointXYZRGB>;
template class pcl::NormalEstimationOMP<pcl::PointSuperVoxel,pcl::PointSuperVoxel>;
template class pcl::NormalEstimation<pcl::PointSuperVoxel,pcl::PointSuperVoxel>;
template class pcl::KdTreeFLANN<pcl::PointSuperVoxel>;
template class pcl::search::OrganizedNeighbor<pcl::PointSuperVoxel>;
<commit_msg>nm<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author : jpapon@gmail.com
 * Email  : jpapon@gmail.com
 *
 */

#include <pcl/point_types.h>
#include <pcl/impl/instantiate.hpp>
#include <pcl/segmentation/supervoxels.h>
#include <pcl/segmentation/impl/supervoxels.hpp>
//These are needed to link with our local PointSuperVoxel
#include <pcl/features/impl/normal_3d_omp.hpp>
#include <pcl/features/impl/normal_3d.hpp>
#include <pcl/search/impl/organized.hpp>
#include <pcl/kdtree/impl/kdtree_flann.hpp>
#include <pcl/impl/pcl_base.hpp>
#include <pcl/search/impl/kdtree.hpp>
#include <pcl/search/impl/search.hpp>

// Instantiations of specific point types
template class pcl::PCLBase<pcl::PointSuperVoxel>;
template class pcl::search::Search<pcl::PointSuperVoxel>;
template class pcl::search::KdTree<pcl::PointSuperVoxel>;
template class pcl::SuperVoxels<pcl::PointXYZRGBA>;
template class pcl::SuperVoxels<pcl::PointXYZRGB>;
template class pcl::NormalEstimationOMP<pcl::PointSuperVoxel,pcl::PointSuperVoxel>;
template class pcl::NormalEstimation<pcl::PointSuperVoxel,pcl::PointSuperVoxel>;
template class pcl::KdTreeFLANN<pcl::PointSuperVoxel>;
template class pcl::search::OrganizedNeighbor<pcl::PointSuperVoxel>;
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_SIGNALMATH_HH__
#define __BSE_SIGNALMATH_HH__

#include <bse/bseieee754.hh>

namespace Bse {

/// Round float to int, using round-to-nearest
/// Fast version of `f < 0 ? int (f - 0.5) : int (f + 0.5)`.
extern inline G_GNUC_CONST int irintf (float f) { return __builtin_rintf (f); }

/// Force number into double precision floating point format, even with `-ffast-math`.
extern inline double force_double (double d)   { volatile double v = d; return v; }

/// Force number into single precision floating point format, even with `-ffast-math`.
extern inline float  force_float  (float  f)   { volatile float v = f; return v; }

/**
 * @param ex	exponent within [-127..+127]
 * @return	fast approximation of `2^x`
 *
 * Fast approximation of 2 raised to the power of `x`.
 * Within -1..+1, the error stays below 4e-7 which corresponds to a sample
 * precision of 21 bit. For integer values of `x` (i.e. `x - floor (x) -> 0`),
 * the error approaches zero. With FMA instructions and -ffast-math enabled,
 * execution times should be below 10ns on 3GHz machines.
 */
extern inline float fast_exp2   (float x)       G_GNUC_CONST;

/**
 * @param ex	exponent within [1.1e-38..2^127]
 * @return	fast approximation of `log2(x)`
 *
 * Fast approximation of logarithm to base 2.
 * Within 1e-7..+1, the error stays below 3.8e-6 which corresponds to a sample
 * precision of 18 bit. When `x` is an exact power of 2, the error approaches
 * zero. With FMA instructions and -ffast-math enabled, execution times should
 * be below 10ns on 3GHz machines.
 */
extern inline float fast_log2   (float x)       G_GNUC_CONST;

// == Implementations ==
extern inline G_GNUC_CONST float
fast_exp2 (float ex)
{
  BseFloatIEEE754 fp = { 0, };
  // const int i = ex < 0 ? int (ex - 0.5) : int (ex + 0.5);
  const int i = irintf (ex);
  fp.mpn.biased_exponent = BSE_FLOAT_BIAS + i;
  const float x = ex - i;
  float r;

  // f=2^x; remez(1, 5, [-.5;.5], 1/f, 1e-16); // minimized relative error
  r = x *  0.0013276471992255f;
  r = x * (0.0096755413344448f + r);
  r = x * (0.0555071327349880f + r);
  r = x * (0.2402211972384019f + r);
  r = x * (0.6931469670647601f + r);
  r = fp.v_float * (1.0f + r);
  return r;
}

extern inline G_GNUC_CONST float
fast_log2 (float value)
{
  static_assert (127 == BSE_FLOAT_BIAS);

  // log2 (i*x) = log2 (i) + log2 (x)
  BseFloatIEEE754 u { value };                  // v_float = 2^(biased_exponent-127) * mantissa
  const int i = u.mpn.biased_exponent - 127;    // extract exponent without bias
  u.mpn.biased_exponent = 127;                  // reset to 2^0 so v_float is mantissa in [1..2]
  float r, x = u.v_float - 1.0f;                // x=[0..1]; r = log2 (x + 1);

  // h=0.0113916; // offset to reduce error at origin
  // f=(1/log(2)) * log(x+1); dom=[0-h;1+h]; p=remez(f, 6, dom, 1);
  // p = p - p(0); // discard non-0 offset
  // err=p-f; plot(err,[0;1]); plot(f,p,dom); // result in sollya
  r = x *  -0.0259366993544709205147977455165000143561553284592936f;
  r = x * (+0.122047857676447181074792747820717519424533931189428f + r);
  r = x * (-0.27814297685064327713977752916286528359628147166014f + r);
  r = x * (+0.45764712300320092992105460899527194244236573556309f + r);
  r = x * (-0.71816105664624015087225994551041120290062342459945f + r);
  r = x * (+1.44254540258782520489769598315182363877204824648687f + r);
  return i + r; // log2 (i) + log2 (x)
}

} // Bse

#endif // __BSE_SIGNALMATH_HH__
<commit_msg>BSE: signalmath.hh: add Logscale to scale and invert logarithmic mappings<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_SIGNALMATH_HH__
#define __BSE_SIGNALMATH_HH__

#include <bse/bseieee754.hh>

namespace Bse {

/// Round float to int, using round-to-nearest
/// Fast version of `f < 0 ? int (f - 0.5) : int (f + 0.5)`.
extern inline G_GNUC_CONST int irintf (float f) { return __builtin_rintf (f); }

/// Force number into double precision floating point format, even with `-ffast-math`.
extern inline double force_double (double d)   { volatile double v = d; return v; }

/// Force number into single precision floating point format, even with `-ffast-math`.
extern inline float  force_float  (float  f)   { volatile float v = f; return v; }

/**
 * @param ex	exponent within [-127..+127]
 * @return	fast approximation of `2^x`
 *
 * Fast approximation of 2 raised to the power of `x`.
 * Within -1..+1, the error stays below 4e-7 which corresponds to a sample
 * precision of 21 bit. For integer values of `x` (i.e. `x - floor (x) -> 0`),
 * the error approaches zero. With FMA instructions and -ffast-math enabled,
 * execution times should be below 10ns on 3GHz machines.
 */
extern inline float fast_exp2   (float x)       G_GNUC_CONST;

/**
 * @param ex	exponent within [1.1e-38..2^127]
 * @return	fast approximation of `log2(x)`
 *
 * Fast approximation of logarithm to base 2.
 * Within 1e-7..+1, the error stays below 3.8e-6 which corresponds to a sample
 * precision of 18 bit. When `x` is an exact power of 2, the error approaches
 * zero. With FMA instructions and -ffast-math enabled, execution times should
 * be below 10ns on 3GHz machines.
 */
extern inline float fast_log2   (float x)       G_GNUC_CONST;

// == Implementations ==
extern inline G_GNUC_CONST float
fast_exp2 (float ex)
{
  BseFloatIEEE754 fp = { 0, };
  // const int i = ex < 0 ? int (ex - 0.5) : int (ex + 0.5);
  const int i = irintf (ex);
  fp.mpn.biased_exponent = BSE_FLOAT_BIAS + i;
  const float x = ex - i;
  float r;

  // f=2^x; remez(1, 5, [-.5;.5], 1/f, 1e-16); // minimized relative error
  r = x *  0.0013276471992255f;
  r = x * (0.0096755413344448f + r);
  r = x * (0.0555071327349880f + r);
  r = x * (0.2402211972384019f + r);
  r = x * (0.6931469670647601f + r);
  r = fp.v_float * (1.0f + r);
  return r;
}

extern inline G_GNUC_CONST float
fast_log2 (float value)
{
  static_assert (127 == BSE_FLOAT_BIAS);

  // log2 (i*x) = log2 (i) + log2 (x)
  BseFloatIEEE754 u { value };                  // v_float = 2^(biased_exponent-127) * mantissa
  const int i = u.mpn.biased_exponent - 127;    // extract exponent without bias
  u.mpn.biased_exponent = 127;                  // reset to 2^0 so v_float is mantissa in [1..2]
  float r, x = u.v_float - 1.0f;                // x=[0..1]; r = log2 (x + 1);

  // h=0.0113916; // offset to reduce error at origin
  // f=(1/log(2)) * log(x+1); dom=[0-h;1+h]; p=remez(f, 6, dom, 1);
  // p = p - p(0); // discard non-0 offset
  // err=p-f; plot(err,[0;1]); plot(f,p,dom); // result in sollya
  r = x *  -0.0259366993544709205147977455165000143561553284592936f;
  r = x * (+0.122047857676447181074792747820717519424533931189428f + r);
  r = x * (-0.27814297685064327713977752916286528359628147166014f + r);
  r = x * (+0.45764712300320092992105460899527194244236573556309f + r);
  r = x * (-0.71816105664624015087225994551041120290062342459945f + r);
  r = x * (+1.44254540258782520489769598315182363877204824648687f + r);
  return i + r; // log2 (i) + log2 (x)
}

/// Logarithmically map (and invert) a range onto 0…+1.
struct Logscale {
  double b2 = 0;         // log2 (begin)
  double r2 = 1, ir = 1; // range
  /// Provide minimum and maximum values to be mapped.
  void
  setup (double min, double max)
  {
    b2 = ::log2l (min);
    auto range = ::log2l (max) - b2;
    ir = 1.0 / range;
    r2 = range;
  }
  /// Calculate scale value within `[min … max]` from normalized `x`.
  double
  scale (double normalized) const
  {
    return ::exp2 (b2 + normalized * r2);
  }
  /// Calculate `normalized` from a `scale()` result within `[min … max]`.
  double
  iscale (double mmvalue) const
  {
    return (::log2 (mmvalue) - b2) * ir;
  }
};

} // Bse

#endif // __BSE_SIGNALMATH_HH__
<|endoftext|>


<commit_before>/**
 * \file hmc-tessellate.hpp
 *
 * \author 2015-2016 Sandia Clinic Team
 *
 * \brief
 *   Contains interface classes for the hmc-tessellate
 *   Voronoi tessellation package.
 */

#pragma once

#include <iostream>
#include <vector>
#include <limits>

#include "vectormath.hpp"
#include "polyhedron.hpp"
#include "verification.hpp"
#include "sds.hpp"

namespace hmc {
    using SizeType = std::size_t;
    using SDS = CellArray<SizeType>;

    class Diagram;
    class Cell;

	/// Value used to signify that no search radius is known for building a Cell.
    constexpr double NO_RADIUS = -1;

	/**
	 * \struct Particle
	 *
	 * \brief
	 *   A struct representing a single 3-D particle.
	 */
    struct Particle {
		/// An identifier for the particle.
        int id;

		/// A 3-D vector representing the position of the particle.
        Vector3 position;

		/// Constructor
        Particle(int id, double x, double y, double z)
            : id(id), position(x, y, z)
        { /* Done */ }

		/// Print information about the particle.
        friend std::ostream& operator<<(std::ostream& out, const Particle& p)
        {
            return out << "{id = " << p.id << ", pos = " << p.position << "}";
        }
    };

	/**
	 * \struct CellInfo
	 *
	 * \brief
	 *   Contains all the information for constructing a Cell in a Diagram.
	 */
    struct CellInfo {
		/// A pointer to the Diagram that contains the Cell.
        const Diagram* diagram;

		/// The index of the point in this Cell in the Diagram.
        SizeType index;

		/// The position of the point in this Cell.
        Vector3 position;

		/// The search radius for neighbors of the particle in the Cell. If no radius is known, set to NO_RADIUS.
        double searchRadius;

		/// Constructor
        CellInfo(const Diagram& diagram, SizeType index, Vector3 position, double searchRadius = NO_RADIUS)
            : diagram(&diagram), index(index), position(position), searchRadius(searchRadius)
        { /* Done */ }
    };

	/**
	 * \class Cell
	 *
	 * \brief
	 *   A Voronoi cell. Used to retrieve various parameters.
	 *
	 * /remarks
	 *   Each cell is only computed once, and the information is cached if it is needed later.
	 */
    class Cell {
        friend class Diagram;

    public:
		/// A pointer to the Diagram that contains this Cell.
        const Diagram* diagram_;

		/// The index of the point in this Cell in the Diagram.
        SizeType index_;

		/// The position of the point in this Cell.
        Vector3 position_;

		/// The Polyhedron representing the Voronoi cell.
        Polyhedron poly_;

		/// A flag that tells whether the Polyhedron has been computed.
        bool polyComputed_;

		/// The search radius for neighbors of the particle in the Cell. If no radius is known, set to NO_RADIUS.
        double searchRadius_;

		/// The ExpandingSearch object used to search for neighbors of the point in this Cell.
        SDS::ExpandingSearch search_;

    public:
		/// Default constructor
        Cell() : diagram_(nullptr), polyComputed_(false) {}

		/**
		 * \brief Constructor
		 *
		 * \param  diagram       A reference to the Diagram that contains this Cell.
		 * \param  index         The index of the point in this Cell in the Diagram.
		 * \param  position      The position of the point in this Cell.
		 * \param  searchRadius  The search radius for neighbors of the particle in the Cell. Optional.
		 *
		 * \remarks
		 *   If no search radius is given, neighbors will be found using an ExpaningSearch.
		 */
        Cell(const Diagram& diagram, SizeType index, Vector3 position, double searchRadius = NO_RADIUS)
            : diagram_(&diagram), index_(index),
              position_(position), polyComputed_(false), searchRadius_(searchRadius)
        { /* Done */ }

		/// Assignment operator
        Cell& operator=(const CellInfo& info)
        {
            clear();
            diagram_ = info.diagram;
            index_ = info.index;
            position_ = info.position;
            searchRadius_ = info.searchRadius;
            return *this;
        }

		/// Clear the Cell
        void clear()
        {
            // diagram_ = nullptr;
            poly_.clear();
            polyComputed_ = false;
        }

        const Particle& getParticle() const;

		/// Compute the volume of the Voronoi cell.
        double computeVolume()
        {
            ensurePolyComputed();
            return poly_.computeVolume();
        }

		/// Find the neighbors of the point in the Voronoi cell.
        template <typename Collection>
        void computeNeighbors(Collection& result)
        {
            ensurePolyComputed();
            poly_.computeNeighbors(result);
        }

		/**
		 * \brief
		 *   Checks whether the Polyhedron representing the Voronoi cell has been computed.
		 *   If it has not, performs the computation.
		 */
        void ensurePolyComputed()
        {
            VERIFY_EXIT(polyComputed_);

            if (!polyComputed_) {
                computeVoronoiCell();
                polyComputed_ = true;
            }
        }

    protected:
        void computeVoronoiCell();
    };

	/**
	 * \class Diagram
	 *
	 * \brief
	 *   A class that represents a Voronoi diagram.
	 *
	 * \details
	 *   Contains a vector of Particle objects, a spatial data structure, and a Polyhedron
	 *   representing the container.
	 */
    class Diagram {
        friend class Cell;

        // using SDS = TrivialSDS<SizeType>;
        // using SDS = ShellArray<SizeType>;

    protected:
		/// The Polyhedron that represents the container of the points.
        Polyhedron containerShape_;

		/// The vector of Particle objects in the Diagram.
        std::vector<Particle> particles_;

		/// The spatial data structure used to determine spatial relationships between points.
        SDS spatialStructure_;

		/// Default constructor
        Diagram() = default;

    public:
		/**
		 * \brief Constructor
		 *
		 * \param  containerShape  A Polyhedron represeting the shape of the container of points.
		 */
        Diagram(Polyhedron containerShape)
            : containerShape_(containerShape)
        { /* Done */ }

		/// Makes a Diagram in the shape of a cube.
        static Diagram cube(double xmin, double xMAX,
                            double ymin, double yMAX,
                            double zmin, double zMAX)
        {
            Diagram diagram;
            diagram.containerShape_.buildCube(xmin, xMAX, ymin, yMAX, zmin, zMAX);
            return diagram;
        }

		/// The number of Particle objects in the Diagram.
        SizeType size() const
        {
            return particles_.size();
        }

		/**
		 * \brief
		 *   Add a Particle to the Diagram.
		 *
		 * \param  id  An identifier for the Particle
		 * \param  x   The x-coordinate of the Particle
		 * \param  y   The y-coordinate of the Particle
		 * \param  z   The z-coordinate of the Particle
		 *
		 * \remarks
		 *   Should only be used before the initialize function is called.
		 */
        void addParticle(int id, double x, double y, double z)
        {
            particles_.emplace_back(id, x, y, z);
        }

		/**
		 * \brief
		 *   Initialize the Diagram.
		 *
		 * \remarks
		 *   Should only be called after all Particles have been added to the Diagram.
		 */
        void initialize()
        {
            spatialStructure_.initialize(0, particles_.size(),
                [this](SizeType index) -> Vector3 {
                    return particles_[index].position;
                }
            );
        }

		/**
		 * \brief
		 *   Initialize the Diagram.
		 *
		 * \param  fill  A lambda function that fills the Diagram with Particle objects
		 *
		 * \remarks
		 *   Should only be called after all Particles (other than those to be added by fill)
		 *   have been added to the Diagram.
		 */
        template <typename FillDiagramWithParticles>
        void initialize(FillDiagramWithParticles fill)
        {
            fill();
            initialize();
        }

		/**
		 * \brief
		 *   Get the CellInfo for a Particle.
		 *
		 * \param  index  The index of the Particle
		 */
        CellInfo getCell(SizeType index) const
        {
            VERIFY(index < particles_.size());
            return CellInfo(*this, index, particles_[index].position);
        }

		/**
		 * \brief
		 *   Get the CellInfo for a Particle using a specfic search radius.
		 *
		 * \param  index         The index of the Particle
		 * \param  searchRadius  The search radius to use for finding neighbors of the Particle
		 */
        CellInfo getCell(SizeType index, double searchRadius) const
        {
            VERIFY(index < particles_.size());
            VERIFY(searchRadius > 0);
            return CellInfo(*this, index, particles_[index].position, searchRadius);
        }

		/**
		 * \brief
		 *   Compute the Voronoi cell for a Particle.
		 *
		 * \param  particleIndex  The index of the Particle
		 * \param  position       The position of the Particle
		 * \param  poly           A reference to the Polyhedron to be cut to compute the cell
		 * \param  search         A reference to an ExpandingSearch for the Particle
		 * \param  searchRadius   The search radius to look for neighbors of the particle. Optional.
		 *
		 * \remarks
		 *   Uses the efficient expanding search strategy to find neighbors if searchRadius is not specified.
		 */
        void computeVoronoiCell(SizeType particleIndex, Vector3 position, Polyhedron& poly,
                                SDS::ExpandingSearch& search, double searchRadius = NO_RADIUS) const
        {
            VERIFY(poly.isClear());
            poly = containerShape_;
            poly.translate(-position);

            // Use expanding search if no radius is given
            if (searchRadius == NO_RADIUS) {
    			searchRadius = std::numeric_limits<double>::max();
                for (search.startSearch(spatialStructure_, position);
                        !search.done();
    				    search.expandSearch(searchRadius = poly.maximumNeighborDistance()))
                {
                    for (SizeType index : search) {
                        Vector3 shiftedPosition = particles_[index].position - position;
                        if (index != particleIndex
                            && mag2(shiftedPosition) <= searchRadius)
                        {
                            poly.cutWithPlane(
                                index,
                                Plane::halfwayFromOriginTo(shiftedPosition)
                            );
                        }
                    }
                }
            }

            // Otherwise (given radius), do a basic search
            else {
                for (SizeType index : spatialStructure_.search(position, searchRadius)) {
                    if (index != particleIndex) {
                        poly.cutWithPlane(
                            index,
                            Plane::halfwayFromOriginTo(particles_[index].position - position)
                        );
                    }
                }
            }
        }
    };

	/// A wrapper function for calling Diagram::ComputeVoronoiCell.
    void Cell::computeVoronoiCell()
    {
        diagram_->computeVoronoiCell(index_, position_, poly_, search_, searchRadius_);
    }

	/// A wrapper function for finding the Particle at an index of a Diagram.
    const Particle& Cell::getParticle() const
    {
        return diagram_->particles_[index_];
    }

}
<commit_msg>Added and documented group functionality in hmc-tessellate.<commit_after>/**
 * \file hmc-tessellate.hpp
 *
 * \author 2015-2016 Sandia Clinic Team
 *
 * \brief
 *   Contains interface classes for the hmc-tessellate
 *   Voronoi tessellation package.
 */

#pragma once

#include <iostream>
#include <vector>
#include <limits>

#include "vectormath.hpp"
#include "polyhedron.hpp"
#include "verification.hpp"
#include "sds.hpp"

namespace hmc {
    using SizeType = std::size_t;
    using SDS = CellArray<SizeType>;

	using TargetGroup = std::unordered_set<int>;
	using SourceGroup = std::vector<int>;

    class Diagram;
    class Cell;

	/// Value used to signify that no group has been specified.
	constexpr int DEFAULT_GROUP = -1;

	/// Value used to signify that no search radius is known for building a Cell.
    constexpr double NO_RADIUS = -1;

	/**
	 * \struct Particle
	 *
	 * \brief
	 *   A struct representing a single 3-D particle.
	 */
    struct Particle {
		/// An identifier for the particle.
        int id;

		/// A 3-D vector representing the position of the particle.
        Vector3 position;

		/// Constructor
        Particle(int id, double x, double y, double z)
            : id(id), position(x, y, z)
        { /* Done */ }

		/// Print information about the particle.
        friend std::ostream& operator<<(std::ostream& out, const Particle& p)
        {
            return out << "{id = " << p.id << ", pos = " << p.position << "}";
        }
    };

	/**
	 * \struct CellInfo
	 *
	 * \brief
	 *   Contains all the information for constructing a Cell in a Diagram.
	 */
    struct CellInfo {
		/// A pointer to the Diagram that contains the Cell.
        const Diagram* diagram;

		/// The index of the point in this Cell in the Diagram.
        SizeType index;

		/// The position of the point in this Cell.
        Vector3 position;

		/// The search radius for neighbors of the particle in the Cell. If no radius is known, set to NO_RADIUS.
        double searchRadius;

		/// The target group of the Cell.
		TargetGroup targetGroup;

		/// Constructor
        CellInfo(const Diagram& diagram, SizeType index, Vector3 position, double searchRadius = NO_RADIUS)
            : diagram(&diagram), index(index), position(position), searchRadius(searchRadius)
        { /* Done */ }

		/// Constructor
        CellInfo(const Diagram& diagram, SizeType index, Vector3 position, TargetGroup targetGroup, double searchRadius = NO_RADIUS)
            : diagram(&diagram), index(index), position(position), targetGroup(targetGroup), searchRadius(searchRadius)
        { /* Done */ }
    };

	/**
	 * \class Cell
	 *
	 * \brief
	 *   A Voronoi cell. Used to retrieve various parameters.
	 *
	 * /remarks
	 *   Each cell is only computed once, and the information is cached if it is needed later.
	 */
    class Cell {
        friend class Diagram;

    public:
		/// A pointer to the Diagram that contains this Cell.
        const Diagram* diagram_;

		/// The index of the point in this Cell in the Diagram.
        SizeType index_;

		/// The position of the point in this Cell.
        Vector3 position_;

		/// The Polyhedron representing the Voronoi cell.
        Polyhedron poly_;

		// The target group of the Cell.
		TargetGroup target_group_;

		/// A flag that tells whether the Polyhedron has been computed.
        bool polyComputed_;

		/// The search radius for neighbors of the particle in the Cell. If no radius is known, set to NO_RADIUS.
        double searchRadius_;

		/// The ExpandingSearch object used to search for neighbors of the point in this Cell.
        SDS::ExpandingSearch search_;

    public:
		/// Default constructor
        Cell() : diagram_(nullptr), polyComputed_(false) {}

		/**
		 * \brief Constructor
		 *
		 * \param  diagram       A reference to the Diagram that contains this Cell.
		 * \param  index         The index of the point in this Cell in the Diagram.
		 * \param  position      The position of the point in this Cell.
		 * \param  searchRadius  The search radius for neighbors of the particle in the Cell. Optional.
		 *
		 * \remarks
		 *   If no search radius is given, neighbors will be found using an ExpaningSearch.
		 */
        Cell(const Diagram& diagram, SizeType index, Vector3 position, double searchRadius = NO_RADIUS)
            : diagram_(&diagram), index_(index),
              position_(position), polyComputed_(false), searchRadius_(searchRadius)
        { /* Done */ }

		/**
		 * \brief Constructor
		 *
		 * \param  diagram       A reference to the Diagram that contains this Cell.
		 * \param  index         The index of the point in this Cell in the Diagram.
		 * \param  position      The position of the point in this Cell.
		 * \param  searchRadius  The search radius for neighbors of the particle in the Cell. Optional.
		 * \param  targetGroup   The target group of the Cell.
		 *
		 * \remarks
		 *   If no search radius is given, neighbors will be found using an ExpaningSearch.
		 */
        Cell(const Diagram& diagram, SizeType index, Vector3 position, TargetGroup targetGroup, double searchRadius = NO_RADIUS)
            : diagram_(&diagram), index_(index),
              position_(position), polyComputed_(false), searchRadius_(searchRadius),
			  target_group_(targetGroup)
        { /* Done */ }

		/// Assignment operator
        Cell& operator=(const CellInfo& info)
        {
            clear();
            diagram_ = info.diagram;
            index_ = info.index;
            position_ = info.position;
			target_group_ = info.targetGroup;
            searchRadius_ = info.searchRadius;
            return *this;
        }

		/// Clear the Cell
        void clear()
        {
            // diagram_ = nullptr;
            poly_.clear();
            polyComputed_ = false;
			target_group_.clear();
        }

        const Particle& getParticle() const;

		/// Compute the volume of the Voronoi cell.
        double computeVolume()
        {
            ensurePolyComputed();
            return poly_.computeVolume();
        }

		/// Find the neighbors of the point in the Voronoi cell.
        template <typename Collection>
        void computeNeighbors(Collection& result)
        {
            ensurePolyComputed();
            poly_.computeNeighbors(result);
        }

		/**
		 * \brief
		 *   Checks whether the Polyhedron representing the Voronoi cell has been computed.
		 *   If it has not, performs the computation.
		 */
        void ensurePolyComputed()
        {
            VERIFY_EXIT(polyComputed_);

            if (!polyComputed_) {
				computeVoronoiCell();
                polyComputed_ = true;
            }
        }

    protected:
        void computeVoronoiCell();
    };

	/**
	 * \class Diagram
	 *
	 * \brief
	 *   A class that represents a Voronoi diagram.
	 *
	 * \details
	 *   Contains a vector of Particle objects, a spatial data structure, and a Polyhedron
	 *   representing the container.
	 */
    class Diagram {
        friend class Cell;

        // using SDS = TrivialSDS<SizeType>;
        // using SDS = ShellArray<SizeType>;

    protected:
		/// The Polyhedron that represents the container of the points.
        Polyhedron containerShape_;

		/// The vector of Particle objects in the Diagram.
        std::vector<Particle> particles_;

		/// The vector of groups that contain each particle. The group at an index corresponds
		/// to the particle at that index.
		std::vector<int> groups_;

		/// The spatial data structure used to determine spatial relationships between points.
        SDS spatialStructure_;

		/// Default constructor
        Diagram() = default;

    public:
		/**
		 * \brief Constructor
		 *
		 * \param  containerShape  A Polyhedron represeting the shape of the container of points.
		 */
        Diagram(Polyhedron containerShape)
            : containerShape_(containerShape)
        { /* Done */ }

		/// Makes a Diagram in the shape of a cube.
        static Diagram cube(double xmin, double xMAX,
                            double ymin, double yMAX,
                            double zmin, double zMAX)
        {
            Diagram diagram;
            diagram.containerShape_.buildCube(xmin, xMAX, ymin, yMAX, zmin, zMAX);
            return diagram;
        }

		/// The number of Particle objects in the Diagram.
        SizeType size() const
        {
            return particles_.size();
        }

		/**
		 * \brief
		 *   Add a Particle to the Diagram.
		 *
		 * \param  id     An identifier for the Particle
		 * \param  x      The x-coordinate of the Particle
		 * \param  y      The y-coordinate of the Particle
		 * \param  z      The z-coordinate of the Particle
		 * \param  group  The group containing the Particle. Optional.
		 *
		 * \remarks
		 *   Should only be used before the initialize function is called.
		 */
        void addParticle(int id, double x, double y, double z, int group = DEFAULT_GROUP)
        {
            particles_.emplace_back(id, x, y, z);
			groups_.push_back(group);
        }

		/**
		 * \brief
		 *   Initialize the Diagram.
		 *
		 * \remarks
		 *   Should only be called after all Particles have been added to the Diagram.
		 */
        void initialize()
        {
            spatialStructure_.initialize(0, particles_.size(),
                [this](SizeType index) -> Vector3 {
                    return particles_[index].position;
                }
            );
        }

		/**
		 * \brief
		 *   Initialize the Diagram.
		 *
		 * \param  fill  A lambda function that fills the Diagram with Particle objects
		 *
		 * \remarks
		 *   Should only be called after all Particles (other than those to be added by fill)
		 *   have been added to the Diagram.
		 */
        template <typename FillDiagramWithParticles>
        void initialize(FillDiagramWithParticles fill)
        {
            fill();
            initialize();
        }

		/**
		 * \brief
		 *   Get the CellInfo for a Particle.
		 *
		 * \param  index  The index of the Particle
		 */
        CellInfo getCell(SizeType index) const
        {
            VERIFY(index < particles_.size());
            return CellInfo(*this, index, particles_[index].position);
        }

		/**
		 * \brief
		 *   Get the CellInfo for a Particle using a specfic search radius.
		 *
		 * \param  index         The index of the Particle
		 * \param  searchRadius  The search radius to use for finding neighbors of the Particle
		 */
        CellInfo getCell(SizeType index, double searchRadius) const
        {
            VERIFY(index < particles_.size());
            VERIFY(searchRadius > 0);
            return CellInfo(*this, index, particles_[index].position, searchRadius);
        }

		/**
		 * \brief
		 *   Create a TargetGroup containing the specified groups.
		 *
		 * \param  groups  The groups to include in the TargetGroup.
		 */
		template <typename... Groups>
		TargetGroup targetGroups(Groups... groups)
		{
			return TargetGroup {groups...};
		}

		// dani hacky constructor thing
		TargetGroup targetGroups(std::vector<int> groups)
		{
			TargetGroup targets = TargetGroup();
			for (int i = 0; i < groups.size(); ++i) {
				targets.insert(groups[i]);
			}
			return targets;
		}

		/**
		 * \brief
		 *   Create a SourceGroup containing particles from the specified groups. The SourceGroup
		 *   can be treated like a vector of indices of Particles in the Diagram.
		 *
		 * \param  groups  The groups to be included.
		 *
		 * \remark
		 *   The SourceGroup does not actually contain any group information once created, and
		 *   is simply included for convenience.
		 */
		template <typename... Groups>
		SourceGroup sourceGroups(Groups... groups)
		{
			std::unordered_set<int> sources = std::unordered_set<int> {groups...};
			SourceGroup src;

			int end = particles_.size();
			for (int i = 0; i < end; ++i) {
				if (sources.count(groups_[i])) {
					src.push_back(i);
				}
			}

			return src;
		}

		/**
		 * \brief
		 *   Compute the Voronoi cell for a Particle.
		 *
		 * \param  particleIndex  The index of the Particle
		 * \param  position       The position of the Particle
		 * \param  poly           A reference to the Polyhedron to be cut to compute the cell
		 * \param  search         A reference to an ExpandingSearch for the Particle
		 * \param  targetGroup    If not empty, only cut the particle with the specified groups.
		 * \param  searchRadius   The search radius to look for neighbors of the particle. Optional.
		 *
		 * \remarks
		 *   Uses the efficient expanding search strategy to find neighbors if searchRadius is not specified.
		 */
        void computeVoronoiCell(SizeType particleIndex, Vector3 position, Polyhedron& poly,
                                SDS::ExpandingSearch& search, TargetGroup& targetGroup,
								double searchRadius = NO_RADIUS) const
        {
            VERIFY(poly.isClear());
            poly = containerShape_;
            poly.translate(-position);

            // Use expanding search if no radius is given
            if (searchRadius == NO_RADIUS) {
    			searchRadius = std::numeric_limits<double>::max();
                for (search.startSearch(spatialStructure_, position);
                        !search.done();
    				    search.expandSearch(searchRadius = poly.maximumNeighborDistance()))
                {
					if (targetGroup.empty()) {
						for (SizeType index : search) {
							Vector3 shiftedPosition = particles_[index].position - position;
							if (index != particleIndex
								&& mag2(shiftedPosition) <= searchRadius)
							{
								poly.cutWithPlane(
									index,
									Plane::halfwayFromOriginTo(shiftedPosition)
									);
							}
						}
					}

					else {
						for (SizeType index : search) {
							Vector3 shiftedPosition = particles_[index].position - position;
							if (index != particleIndex
								&& mag2(shiftedPosition) <= searchRadius
								&& targetGroup.count(groups_[index]) != 0)
							{
								poly.cutWithPlane(
									index,
									Plane::halfwayFromOriginTo(shiftedPosition)
									);
							}
						}
					}
                }
            }

            // Otherwise (given radius), do a basic search
            else {
				if (targetGroup.empty()) {
					for (SizeType index : spatialStructure_.search(position, searchRadius)) {
						if (index != particleIndex) {
							poly.cutWithPlane(
								index,
								Plane::halfwayFromOriginTo(particles_[index].position - position)
								);
						}
					}
				}

				else {
					for (SizeType index : spatialStructure_.search(position, searchRadius)) {
						if (index != particleIndex && targetGroup.count(groups_[index]) != 0) {
							poly.cutWithPlane(
								index,
								Plane::halfwayFromOriginTo(particles_[index].position - position)
								);
						}
					}
				}
            }
        }
    };

	/// A wrapper function for calling Diagram::ComputeVoronoiCell.
    void Cell::computeVoronoiCell()
    {
        diagram_->computeVoronoiCell(index_, position_, poly_, search_, target_group_, searchRadius_);
    }

	/// A wrapper function for finding the Particle at an index of a Diagram.
    const Particle& Cell::getParticle() const
    {
        return diagram_->particles_[index_];
    }

}
<|endoftext|>


<commit_before>#include "Arglist.h"

void addArg(cmdComponent* a) // appends argument  “a” to ArgList
{
    ArgVec.push_back(a);
}

void deleteArg()			      // removes arg at last index
{
    ArgVec.pop_back();
}

cmdComponent* at(int i) // returns “argument” at index “i”
{
    return ArgVec.at(i);
}<commit_msg>Delete ArgList.cpp<commit_after><|endoftext|>


<commit_before>#ifndef NONBLOCKING_BCI_HPP
#define NONBLOCKING_BCI_HPP

#include <boost/lockfree/spsc_queue.hpp>
#include <boost/thread.hpp>
#include <boost/atomic.hpp>

#include "bci.hpp"
#include "sample.hpp"

static const size_t SAMPLE_BUFFER_SIZE=8192;

class NonblockingBCI : public BCI {
public:
	NonblockingBCI(BCI*);
	virtual ~NonblockingBCI();
	virtual bool open(uint8_t[]);
	virtual bool init(size_t);
	virtual bool start();
	virtual size_t acquire();
	virtual void getdata(uint32_t* data, size_t n);
	virtual uint64_t timestamp();
	virtual bool stop();
	virtual bool close();
private:
    BCI* mpBCI;
    Sample<uint32_t>* mpSamples;
    boost::lockfree::spsc_queue<Sample<uint32_t>*, boost::lockfree::capacity<(SAMPLE_BUFFER_SIZE-1)> > mQueue;
    boost::thread mAsyncSampleCollector;
    boost::atomic<bool> mDone;

};

#endif
<commit_msg>Applied Emacs' default c++-mode formatting<commit_after>#ifndef NONBLOCKING_BCI_HPP
#define NONBLOCKING_BCI_HPP

#include <boost/lockfree/spsc_queue.hpp>
#include <boost/thread.hpp>
#include <boost/atomic.hpp>

#include "bci.hpp"
#include "sample.hpp"

static const size_t SAMPLE_BUFFER_SIZE=8192;

class NonblockingBCI : public BCI {
public:
  NonblockingBCI(BCI*);
  virtual ~NonblockingBCI();
  virtual bool open(uint8_t[]);
  virtual bool init(size_t);
  virtual bool start();
  virtual size_t acquire();
  virtual void getdata(uint32_t* data, size_t n);
  virtual uint64_t timestamp();
  virtual bool stop();
  virtual bool close();
private:
  BCI* mpBCI;
  Sample<uint32_t> mSamples[SAMPLE_BUFFER_SIZE];
  boost::lockfree::spsc_queue<Sample<uint32_t>*, boost::lockfree::capacity<(SAMPLE_BUFFER_SIZE-1)> > mQueue;
  boost::thread mAsyncSampleCollector;
  boost::atomic<bool> mDone;

};

#endif
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include "pysignal.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <qitype/signal.hpp>
#include <qitype/anyobject.hpp>
#include "gil.hpp"
#include "error.hpp"
#include "pyfuture.hpp"
#include "pythreadsafeobject.hpp"

qiLogCategory("py.signal");

namespace qi { namespace py {

    static qi::AnyReference pysignalCb(const std::vector<qi::AnyReference>& cargs, const PyThreadSafeObject& callable) {
      GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::AnyReference>::const_iterator it;
      for (it = cargs.begin(); it != cargs.end(); ++it) {
        args.append(it->to<boost::python::object>());
      }
      PY_CATCH_ERROR(ret = callable.object()(*boost::python::tuple(args)));
      return qi::AnyReference(ret).clone();
    }

    class PySignal {
    public:
      PySignal(const qi::Signature &signature = "m")
        : _sig(new qi::SignalBase(signature))
      {
      }

      PySignal(const PySignal& rhs)
        : _sig(new qi::SignalBase(qi::Signature("m")))
      {

        *_sig = *rhs._sig;
      }

      PySignal &operator=(const PySignal& rhs) {
        *_sig = *rhs._sig;
        return *this;
      }

      ~PySignal() {
        //the dtor can lock waiting for callback ends
        GILScopedUnlock _unlock;
        delete _sig;
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::uint64_t r;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          r = _sig->connect(qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<qi::uint64_t>(r)));
        }
        return boost::python::object(r);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnect(id);
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }

        return boost::python::object(r);
      }

      boost::python::object disconnectAll(bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnectAll();
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }
        return boost::python::object(r);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _sig->trigger(qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    public:
      qi::SignalBase *_sig;
    };

    class PyProxySignal {
    public:
      PyProxySignal(qi::AnyObject obj, const qi::MetaSignal &signal)
        : _obj(obj)
        , _sigid(signal.uid()){
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::Future<SignalLink> f;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          f = _obj.connect(_sigid, qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        return toPyFutureAsync(f, _async);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        qi::Future<void> f;
        {
          GILScopedUnlock _unlock;
          f = _obj.disconnect(id);
        }
        return toPyFutureAsync(f, _async);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _obj.metaPost(_sigid, qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    private:
      qi::AnyObject _obj;
      unsigned int  _sigid;
    };

    qi::SignalBase *getSignal(boost::python::object obj) {
      PySignal* sig = boost::python::extract<PySignal*>(obj);
      if (!sig)
        return 0;
      return sig->_sig;
    }

    boost::python::object makePySignal(const std::string &signature) {
      GILScopedLock _lock;
      return boost::python::object(PySignal(signature));
    }

    boost::python::object makePyProxySignal(const qi::AnyObject &obj, const qi::MetaSignal &signal) {
      return boost::python::object(PyProxySignal(obj, signal));
    }

    template <typename T>
    static boost::python::object signal_param_shrinker(boost::python::tuple args, boost::python::dict kwargs) {
      T& pys = boost::python::extract<T&>(args[0]);
      boost::python::list l;
      for (unsigned i = 1; i < boost::python::len(args); ++i)
        l.append(args[i]);
      pys.trig(boost::python::tuple(l), kwargs);
      return boost::python::object();
    }

    void export_pysignal() {
      boost::python::class_<PySignal>("Signal", boost::python::init<>())
          .def(boost::python::init<const std::string &>())
          .def("connect", &PySignal::connect, (boost::python::arg("callback"), boost::python::arg("_async") = false),
               "connect(callback) -> int\n"
               ":param callback: the callback that will be called when the signal is triggered\n"
               ":return: the connection id of the registered callback.\n"
               "\n"
               "Connect the signal to a callback, the callback will be called each time the signal is triggered. "
               "Use the id returned to unregister the callback")

          .def("disconnect", &PySignal::disconnect, (boost::python::arg("id"), boost::python::arg("_async") = false),
               "disconnect(id) -> bool\n"
               ":param id: the connection id returned by connect\n"
               ":return: true on success\n"
               "\n"
               "Disconnect the callback associated to id.")

          .def("disconnectAll", &PySignal::disconnectAll, (boost::python::arg("_async") = false),
               "disconnectAll() -> bool\n"
               ":return: true on success\n"
               "\n"
               "disconnect all callback associated to the signal. This function should be used very carefully. It's extremely rare that it is needed.")

          .def("__call__", boost::python::raw_function(&signal_param_shrinker<PySignal>),
               "__call__(*args) -> None\n"
               "Trigger the signal");

      boost::python::class_<PyProxySignal>("_ProxySignal", boost::python::no_init)
          .def("connect", &PyProxySignal::connect, (boost::python::arg("callback"), boost::python::arg("_async") = false))
          .def("disconnect", &PyProxySignal::disconnect, (boost::python::arg("id"), boost::python::arg("_async") = false))
          .def("__call__", boost::python::raw_function(&signal_param_shrinker<PyProxySignal>));
    }

  }
}
<commit_msg>python: signal: throw in connect if the callback is not callable<commit_after>/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include "pysignal.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <qitype/signal.hpp>
#include <qitype/anyobject.hpp>
#include "gil.hpp"
#include "error.hpp"
#include "pyfuture.hpp"
#include "pythreadsafeobject.hpp"

qiLogCategory("py.signal");

namespace qi { namespace py {

    static qi::AnyReference pysignalCb(const std::vector<qi::AnyReference>& cargs, const PyThreadSafeObject& callable) {
      GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::AnyReference>::const_iterator it;
      for (it = cargs.begin(); it != cargs.end(); ++it) {
        args.append(it->to<boost::python::object>());
      }
      PY_CATCH_ERROR(ret = callable.object()(*boost::python::tuple(args)));
      return qi::AnyReference(ret).clone();
    }

    class PySignal {
    public:
      PySignal(const qi::Signature &signature = "m")
        : _sig(new qi::SignalBase(signature))
      {
      }

      PySignal(const PySignal& rhs)
        : _sig(new qi::SignalBase(qi::Signature("m")))
      {

        *_sig = *rhs._sig;
      }

      PySignal &operator=(const PySignal& rhs) {
        *_sig = *rhs._sig;
        return *this;
      }

      ~PySignal() {
        //the dtor can lock waiting for callback ends
        GILScopedUnlock _unlock;
        delete _sig;
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);

        if (!PyCallable_Check(callable.ptr()))
          throw std::runtime_error("Not a callable");
        qi::uint64_t r;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          r = _sig->connect(qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<qi::uint64_t>(r)));
        }
        return boost::python::object(r);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnect(id);
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }

        return boost::python::object(r);
      }

      boost::python::object disconnectAll(bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnectAll();
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }
        return boost::python::object(r);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _sig->trigger(qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    public:
      qi::SignalBase *_sig;
    };

    class PyProxySignal {
    public:
      PyProxySignal(qi::AnyObject obj, const qi::MetaSignal &signal)
        : _obj(obj)
        , _sigid(signal.uid()){
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        if (!PyCallable_Check(callable.ptr()))
          throw std::runtime_error("Not a callable");
        qi::Future<SignalLink> f;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          f = _obj.connect(_sigid, qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        return toPyFutureAsync(f, _async);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        qi::Future<void> f;
        {
          GILScopedUnlock _unlock;
          f = _obj.disconnect(id);
        }
        return toPyFutureAsync(f, _async);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _obj.metaPost(_sigid, qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    private:
      qi::AnyObject _obj;
      unsigned int  _sigid;
    };

    qi::SignalBase *getSignal(boost::python::object obj) {
      PySignal* sig = boost::python::extract<PySignal*>(obj);
      if (!sig)
        return 0;
      return sig->_sig;
    }

    boost::python::object makePySignal(const std::string &signature) {
      GILScopedLock _lock;
      return boost::python::object(PySignal(signature));
    }

    boost::python::object makePyProxySignal(const qi::AnyObject &obj, const qi::MetaSignal &signal) {
      return boost::python::object(PyProxySignal(obj, signal));
    }

    template <typename T>
    static boost::python::object signal_param_shrinker(boost::python::tuple args, boost::python::dict kwargs) {
      T& pys = boost::python::extract<T&>(args[0]);
      boost::python::list l;
      for (unsigned i = 1; i < boost::python::len(args); ++i)
        l.append(args[i]);
      pys.trig(boost::python::tuple(l), kwargs);
      return boost::python::object();
    }

    void export_pysignal() {
      boost::python::class_<PySignal>("Signal", boost::python::init<>())
          .def(boost::python::init<const std::string &>())
          .def("connect", &PySignal::connect, (boost::python::arg("callback"), boost::python::arg("_async") = false),
               "connect(callback) -> int\n"
               ":param callback: the callback that will be called when the signal is triggered\n"
               ":return: the connection id of the registered callback.\n"
               "\n"
               "Connect the signal to a callback, the callback will be called each time the signal is triggered. "
               "Use the id returned to unregister the callback")

          .def("disconnect", &PySignal::disconnect, (boost::python::arg("id"), boost::python::arg("_async") = false),
               "disconnect(id) -> bool\n"
               ":param id: the connection id returned by connect\n"
               ":return: true on success\n"
               "\n"
               "Disconnect the callback associated to id.")

          .def("disconnectAll", &PySignal::disconnectAll, (boost::python::arg("_async") = false),
               "disconnectAll() -> bool\n"
               ":return: true on success\n"
               "\n"
               "disconnect all callback associated to the signal. This function should be used very carefully. It's extremely rare that it is needed.")

          .def("__call__", boost::python::raw_function(&signal_param_shrinker<PySignal>),
               "__call__(*args) -> None\n"
               "Trigger the signal");

      boost::python::class_<PyProxySignal>("_ProxySignal", boost::python::no_init)
          .def("connect", &PyProxySignal::connect, (boost::python::arg("callback"), boost::python::arg("_async") = false))
          .def("disconnect", &PyProxySignal::disconnect, (boost::python::arg("id"), boost::python::arg("_async") = false))
          .def("__call__", boost::python::raw_function(&signal_param_shrinker<PyProxySignal>));
    }

  }
}
<|endoftext|>