<commit_before>//
// Copyright (C) 2005-2008 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2008 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <stdlib.h>

// APPLICATION INCLUDES
#include <os/OsConfigDb.h>
#include "sipXmediaFactoryImpl.h"
#include "CpPhoneMediaInterface.h"
#include <sdp/SdpCodec.h>
#include <mp/MpMediaTask.h>
#include <mp/MpMisc.h>
#include <mp/MpCodec.h>
#include <mp/MpCallFlowGraph.h>
#include <mp/dmaTask.h>
#include <mp/MpCodecFactory.h>
#include <sdp/SdpCodecList.h>
#include "mi/CpMediaInterfaceFactoryFactory.h"

#ifdef INCLUDE_RTCP /* [ */
#include <rtcp/RTCManager.h>
#endif /* INCLUDE_RTCP ] */

#ifdef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
#include <mp/NetInTask.h>
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// GLOBAL FUNCTION

#define MAX_MANAGED_FLOW_GRAPHS 16

// STATIC VARIABLE INITIALIZATIONS
int sipXmediaFactoryImpl::miInstanceCount=0;

CpMediaInterfaceFactory* spFactory = NULL;
int siInstanceCount=0;

#ifndef DISABLE_DEFAULT_PHONE_MEDIA_INTERFACE_FACTORY
extern "C" CpMediaInterfaceFactory* cpDefaultMediaFactoryFactory(OsConfigDb* pConfigDb,
                                                                 uint32_t maxSamplesPerFrame,
                                                                 uint32_t maxSamplesPerSec)
{
   // TODO: Add locking

   if (spFactory == NULL)
   {
      spFactory = new CpMediaInterfaceFactory();
      spFactory->setFactoryImplementation(new sipXmediaFactoryImpl(pConfigDb,
                                                                   maxSamplesPerFrame,
                                                                   maxSamplesPerSec));
   }
   siInstanceCount++;

   // Assert some sane value
   assert(siInstanceCount < 11);
   return spFactory;
}

extern "C" CpMediaInterfaceFactory* sipXmediaFactoryFactory(OsConfigDb* pConfigDb,
                                                            uint32_t maxSamplesPerFrame,
                                                            uint32_t maxSamplesPerSec)
{
   return(cpDefaultMediaFactoryFactory(pConfigDb, maxSamplesPerFrame, maxSamplesPerSec));
}
#endif

extern "C" void sipxDestroyMediaFactoryFactory()
{
   // TODO: Add locking

   if (siInstanceCount > 0)
   {
      siInstanceCount--;
      if (siInstanceCount == 0)
      {
         if (spFactory)
         {
            delete spFactory;
            spFactory = NULL;
         }
      }
   }
}

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
sipXmediaFactoryImpl::sipXmediaFactoryImpl(OsConfigDb* pConfigDb,
                                           uint32_t maxSamplesPerFrame,
                                           uint32_t maxSamplesPerSec)
{
   // See doxyegen comments for this constructor for information on the impact
   // of the values of maxSamplesPerFrame and maxSamplesPerSec.
   mMaxSamplesPerFrame = (maxSamplesPerFrame == 0) ? 16000 : maxSamplesPerFrame;
   mMaxSamplesPerSec = (maxSamplesPerSec == 0) ? 160 : maxSamplesPerSec;

   int maxFlowGraph = -1;
   UtlString strInBandDTMF;
   if (pConfigDb)
   {
      pConfigDb->get("PHONESET_MAX_ACTIVE_CALLS_ALLOWED", maxFlowGraph);
      pConfigDb->get("PHONESET_SEND_INBAND_DTMF", strInBandDTMF);
      strInBandDTMF.toUpper();

      OsSysLog::add(FAC_MP, PRI_DEBUG,
                    "sipXmediaFactoryImpl::sipXmediaFactoryImpl"
                    " maxFlowGraph = %d",
                    maxFlowGraph);
   }

   // Max Flow graphs
   if (maxFlowGraph <=0 )
   {
      maxFlowGraph = MAX_MANAGED_FLOW_GRAPHS;
   }

   // Start audio subsystem if still not started.
   if (miInstanceCount == 0)
   {
      mpStartUp(mMaxSamplesPerSec, mMaxSamplesPerFrame, 16*maxFlowGraph, pConfigDb,
                mnCodecPaths, mpCodecPaths);
   }

   // Should we send inband DTMF by default?
   if (strInBandDTMF.compareTo("DISABLE") == 0)
   {
      MpCallFlowGraph::setInbandDTMF(false);
   }
   else
   {
      MpCallFlowGraph::setInbandDTMF(true);
   }

   // init the media processing task
   mpMediaTask = MpMediaTask::getMediaTask(maxFlowGraph);

#ifdef INCLUDE_RTCP /* [ */
   mpiRTCPControl = CRTCManager::getRTCPControl();
#endif /* INCLUDE_RTCP ] */

   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStartTasks();
#else
      if (OS_SUCCESS != startNetInTask())
      {
         OsSysLog::add(FAC_MP, PRI_ERR, "Could not start NetInTask!!");
      }
#endif
   }

   miGain = 7;
   ++miInstanceCount;

   // We are missing synchronization -- give the tasks time to start
   OsTask::delay(100);
}

// Destructor
sipXmediaFactoryImpl::~sipXmediaFactoryImpl()
{
   // TODO: Shutdown
   --miInstanceCount;
   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStopTasks();
#else
      shutdownNetInTask();
#endif
      mpShutdown();
   }
}

/* ============================ MANIPULATORS ============================== */

CpMediaInterface* sipXmediaFactoryImpl::createMediaInterface(const char* publicAddress,
                                                             const char* localAddress,
                                                             int numCodecs,
                                                             SdpCodec* sdpCodecArray[],
                                                             const char* locale,
                                                             int expeditedIpTos,
                                                             const char* szStunServer,
                                                             int iStunPort,
                                                             int iStunKeepAliveSecs,
                                                             const char* szTurnServer,
                                                             int iTurnPort,
                                                             const char* szTurnUsername,
                                                             const char* szTurnPassword,
                                                             int iTurnKeepAlivePeriodSecs,
                                                             UtlBoolean bEnableICE,
                                                             uint32_t samplesPerFrame,
                                                             uint32_t samplesPerSec)
{
   return new CpPhoneMediaInterface(this, publicAddress, localAddress,
      numCodecs, sdpCodecArray, locale, expeditedIpTos, szStunServer,
      iStunPort, iStunKeepAliveSecs, szTurnServer, iTurnPort,
      szTurnUsername, szTurnPassword, iTurnKeepAlivePeriodSecs,
      bEnableICE, samplesPerFrame, samplesPerSec);
}

OsStatus sipXmediaFactoryImpl::setSpeakerVolume(int iVolume)
{
   OsStatus rc = OS_SUCCESS;
   MpCodec_setVolume(iVolume);

   return rc;
}

OsStatus sipXmediaFactoryImpl::setSpeakerDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setCallDevice(device.data());
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneGain(int iGain)
{
   OsStatus rc;

   miGain = iGain;
   rc = MpCodec_setGain(miGain);
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setInputDevice(device.data());
#ifdef WIN32
   dmaSignalMicDeviceChange();
#endif
   return rc;
}

OsStatus sipXmediaFactoryImpl::muteMicrophone(UtlBoolean bMute)
{
   if (bMute)
   {
      MpCodec_setGain(0);
   }
   else
   {
      MpCodec_setGain(miGain);
   }
   return OS_SUCCESS;
}

OsStatus sipXmediaFactoryImpl::setAudioAECMode(const MEDIA_AEC_MODE mode)
{
   if (MpCallFlowGraph::setAECMode((FLOWGRAPH_AEC_MODE)mode))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::enableAGC(UtlBoolean bEnable)
{
   if (MpCallFlowGraph::setAGC(bEnable))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::setAudioNoiseReductionMode(const MEDIA_NOISE_REDUCTION_MODE mode)
{
   if (mode == MEDIA_NOISE_REDUCTION_DISABLED)
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(FALSE))
      {
         return OS_SUCCESS;
      }
   }
   else
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(TRUE))
      {
         return OS_SUCCESS;
      }
   }
   return OS_NOT_SUPPORTED;
}

OsStatus sipXmediaFactoryImpl::buildCodecFactory(SdpCodecList* pFactory,
                                                 const UtlString& sAudioPreferences,
                                                 const UtlString& sVideoPreferences,
                                                 int videoFormat,
                                                 int* iRejected)
{
   OsStatus rc = OS_FAILED;

   *iRejected = 0;

   if (pFactory)
   {
      pFactory->clearCodecs();

      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sAudioPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sAudioPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sAudioPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
         pCodecFactory->addCodecsToList(*pFactory);

         *iRejected = 0;
         rc = OS_SUCCESS;
      }

#ifdef VIDEO // [
      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sVideoPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sVideoPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sVideoPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         SdpCodec::SdpCodecTypes videoCodecs[] = {};
         const int numVideoCodecs = sizeof(videoCodecs)/sizeof(SdpCodec::SdpCodecTypes);

         *iRejected = pFactory->addCodecs(numVideoCodecs, videoCodecs);
         rc = OS_SUCCESS;
      }
#endif // VIDEO ]
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::updateVideoPreviewWindow(void* displayContext)
{
   return OS_NOT_SUPPORTED;
}

/* ============================ ACCESSORS ================================= */

OsStatus sipXmediaFactoryImpl::getSpeakerVolume(int& iVolume) const
{
   OsStatus rc = OS_SUCCESS;

   iVolume = MpCodec_getVolume();
   if (iVolume==-1)
   {
      rc = OS_FAILED;
      iVolume = 0;
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::getSpeakerDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getCallDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneGain(int& iGain) const
{
   OsStatus rc = OS_SUCCESS;
   iGain = MpCodec_getGain();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getMicDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::setVideoPreviewDisplay(void* pDisplay)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoQuality(int quality)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoParameters(int bitRate, int frameRate)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoQuality(int& quality) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoBitRate(int& bitRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoFrameRate(int& frameRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getLocalAudioConnectionId(int& connectionId) const
{
   connectionId = -1;
   return OS_NOT_SUPPORTED;

}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ FUNCTIONS ================================= */
<commit_msg>Fix bug in sipXmediaFactoryImpl constructor - number of samples per second and per frame were messed. Also change default to 80/8000. Let users to explicitely request WB support.<commit_after>//
// Copyright (C) 2005-2008 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2008 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <stdlib.h>

// APPLICATION INCLUDES
#include <os/OsConfigDb.h>
#include "sipXmediaFactoryImpl.h"
#include "CpPhoneMediaInterface.h"
#include <sdp/SdpCodec.h>
#include <mp/MpMediaTask.h>
#include <mp/MpMisc.h>
#include <mp/MpCodec.h>
#include <mp/MpCallFlowGraph.h>
#include <mp/dmaTask.h>
#include <mp/MpCodecFactory.h>
#include <sdp/SdpCodecList.h>
#include "mi/CpMediaInterfaceFactoryFactory.h"

#ifdef INCLUDE_RTCP /* [ */
#include <rtcp/RTCManager.h>
#endif /* INCLUDE_RTCP ] */

#ifdef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
#include <mp/NetInTask.h>
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// GLOBAL FUNCTION

#define MAX_MANAGED_FLOW_GRAPHS 16

// STATIC VARIABLE INITIALIZATIONS
int sipXmediaFactoryImpl::miInstanceCount=0;

CpMediaInterfaceFactory* spFactory = NULL;
int siInstanceCount=0;

#ifndef DISABLE_DEFAULT_PHONE_MEDIA_INTERFACE_FACTORY
extern "C" CpMediaInterfaceFactory* cpDefaultMediaFactoryFactory(OsConfigDb* pConfigDb,
                                                                 uint32_t maxSamplesPerFrame,
                                                                 uint32_t maxSamplesPerSec)
{
   // TODO: Add locking

   if (spFactory == NULL)
   {
      spFactory = new CpMediaInterfaceFactory();
      spFactory->setFactoryImplementation(new sipXmediaFactoryImpl(pConfigDb,
                                                                   maxSamplesPerFrame,
                                                                   maxSamplesPerSec));
   }
   siInstanceCount++;

   // Assert some sane value
   assert(siInstanceCount < 11);
   return spFactory;
}

extern "C" CpMediaInterfaceFactory* sipXmediaFactoryFactory(OsConfigDb* pConfigDb,
                                                            uint32_t maxSamplesPerFrame,
                                                            uint32_t maxSamplesPerSec)
{
   return(cpDefaultMediaFactoryFactory(pConfigDb, maxSamplesPerFrame, maxSamplesPerSec));
}
#endif

extern "C" void sipxDestroyMediaFactoryFactory()
{
   // TODO: Add locking

   if (siInstanceCount > 0)
   {
      siInstanceCount--;
      if (siInstanceCount == 0)
      {
         if (spFactory)
         {
            delete spFactory;
            spFactory = NULL;
         }
      }
   }
}

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
sipXmediaFactoryImpl::sipXmediaFactoryImpl(OsConfigDb* pConfigDb,
                                           uint32_t maxSamplesPerFrame,
                                           uint32_t maxSamplesPerSec)
{
   // See Doxygen comments for this constructor for information on the impact
   // of the values of maxSamplesPerFrame and maxSamplesPerSec.
   mMaxSamplesPerFrame = (maxSamplesPerFrame == 0) ? 80 : maxSamplesPerFrame;
   mMaxSamplesPerSec = (maxSamplesPerSec == 0) ? 8000 : maxSamplesPerSec;

   int maxFlowGraph = -1;
   UtlString strInBandDTMF;
   if (pConfigDb)
   {
      pConfigDb->get("PHONESET_MAX_ACTIVE_CALLS_ALLOWED", maxFlowGraph);
      pConfigDb->get("PHONESET_SEND_INBAND_DTMF", strInBandDTMF);
      strInBandDTMF.toUpper();

      OsSysLog::add(FAC_MP, PRI_DEBUG,
                    "sipXmediaFactoryImpl::sipXmediaFactoryImpl"
                    " maxFlowGraph = %d",
                    maxFlowGraph);
   }

   // Max Flow graphs
   if (maxFlowGraph <=0 )
   {
      maxFlowGraph = MAX_MANAGED_FLOW_GRAPHS;
   }

   // Start audio subsystem if still not started.
   if (miInstanceCount == 0)
   {
      mpStartUp(mMaxSamplesPerSec, mMaxSamplesPerFrame, 16*maxFlowGraph, pConfigDb,
                mnCodecPaths, mpCodecPaths);
   }

   // Should we send inband DTMF by default?
   if (strInBandDTMF.compareTo("DISABLE") == 0)
   {
      MpCallFlowGraph::setInbandDTMF(false);
   }
   else
   {
      MpCallFlowGraph::setInbandDTMF(true);
   }

   // init the media processing task
   mpMediaTask = MpMediaTask::getMediaTask(maxFlowGraph);

#ifdef INCLUDE_RTCP /* [ */
   mpiRTCPControl = CRTCManager::getRTCPControl();
#endif /* INCLUDE_RTCP ] */

   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStartTasks();
#else
      if (OS_SUCCESS != startNetInTask())
      {
         OsSysLog::add(FAC_MP, PRI_ERR, "Could not start NetInTask!!");
      }
#endif
   }

   miGain = 7;
   ++miInstanceCount;

   // We are missing synchronization -- give the tasks time to start
   OsTask::delay(100);
}

// Destructor
sipXmediaFactoryImpl::~sipXmediaFactoryImpl()
{
   // TODO: Shutdown
   --miInstanceCount;
   if (miInstanceCount == 0)
   {
#ifndef ENABLE_TOPOLOGY_FLOWGRAPH_INTERFACE_FACTORY
      mpStopTasks();
#else
      shutdownNetInTask();
#endif
      mpShutdown();
   }
}

/* ============================ MANIPULATORS ============================== */

CpMediaInterface* sipXmediaFactoryImpl::createMediaInterface(const char* publicAddress,
                                                             const char* localAddress,
                                                             int numCodecs,
                                                             SdpCodec* sdpCodecArray[],
                                                             const char* locale,
                                                             int expeditedIpTos,
                                                             const char* szStunServer,
                                                             int iStunPort,
                                                             int iStunKeepAliveSecs,
                                                             const char* szTurnServer,
                                                             int iTurnPort,
                                                             const char* szTurnUsername,
                                                             const char* szTurnPassword,
                                                             int iTurnKeepAlivePeriodSecs,
                                                             UtlBoolean bEnableICE,
                                                             uint32_t samplesPerFrame,
                                                             uint32_t samplesPerSec)
{
   return new CpPhoneMediaInterface(this, publicAddress, localAddress,
      numCodecs, sdpCodecArray, locale, expeditedIpTos, szStunServer,
      iStunPort, iStunKeepAliveSecs, szTurnServer, iTurnPort,
      szTurnUsername, szTurnPassword, iTurnKeepAlivePeriodSecs,
      bEnableICE, samplesPerFrame, samplesPerSec);
}

OsStatus sipXmediaFactoryImpl::setSpeakerVolume(int iVolume)
{
   OsStatus rc = OS_SUCCESS;
   MpCodec_setVolume(iVolume);

   return rc;
}

OsStatus sipXmediaFactoryImpl::setSpeakerDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setCallDevice(device.data());
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneGain(int iGain)
{
   OsStatus rc;

   miGain = iGain;
   rc = MpCodec_setGain(miGain);
   return rc;
}

OsStatus sipXmediaFactoryImpl::setMicrophoneDevice(const UtlString& device)
{
   OsStatus rc = OS_SUCCESS;
   DmaTask::setInputDevice(device.data());
#ifdef WIN32
   dmaSignalMicDeviceChange();
#endif
   return rc;
}

OsStatus sipXmediaFactoryImpl::muteMicrophone(UtlBoolean bMute)
{
   if (bMute)
   {
      MpCodec_setGain(0);
   }
   else
   {
      MpCodec_setGain(miGain);
   }
   return OS_SUCCESS;
}

OsStatus sipXmediaFactoryImpl::setAudioAECMode(const MEDIA_AEC_MODE mode)
{
   if (MpCallFlowGraph::setAECMode((FLOWGRAPH_AEC_MODE)mode))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::enableAGC(UtlBoolean bEnable)
{
   if (MpCallFlowGraph::setAGC(bEnable))
   {
      return OS_SUCCESS;
   }
   else
   {
      return OS_NOT_SUPPORTED;
   }
}

OsStatus sipXmediaFactoryImpl::setAudioNoiseReductionMode(const MEDIA_NOISE_REDUCTION_MODE mode)
{
   if (mode == MEDIA_NOISE_REDUCTION_DISABLED)
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(FALSE))
      {
         return OS_SUCCESS;
      }
   }
   else
   {
      if (MpCallFlowGraph::setAudioNoiseReduction(TRUE))
      {
         return OS_SUCCESS;
      }
   }
   return OS_NOT_SUPPORTED;
}

OsStatus sipXmediaFactoryImpl::buildCodecFactory(SdpCodecList* pFactory,
                                                 const UtlString& sAudioPreferences,
                                                 const UtlString& sVideoPreferences,
                                                 int videoFormat,
                                                 int* iRejected)
{
   OsStatus rc = OS_FAILED;

   *iRejected = 0;

   if (pFactory)
   {
      pFactory->clearCodecs();

      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sAudioPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sAudioPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sAudioPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
         pCodecFactory->addCodecsToList(*pFactory);

         *iRejected = 0;
         rc = OS_SUCCESS;
      }

#ifdef VIDEO // [
      // If preferred codecs supplied - add them, else add all supported
      // codecs.
      if (sVideoPreferences.length() > 0)
      {
         *iRejected = pFactory->addCodecs(sVideoPreferences);
         OsSysLog::add(FAC_MP, PRI_DEBUG,
                       "sipXmediaFactoryImpl::buildCodecFactory: "
                       "supported codecs = %s with NumReject %d",
                       sVideoPreferences.data(), *iRejected);
         rc = OS_SUCCESS;
      }
      else
      {
         // Build up the supported codecs
         SdpCodec::SdpCodecTypes videoCodecs[] = {};
         const int numVideoCodecs = sizeof(videoCodecs)/sizeof(SdpCodec::SdpCodecTypes);

         *iRejected = pFactory->addCodecs(numVideoCodecs, videoCodecs);
         rc = OS_SUCCESS;
      }
#endif // VIDEO ]
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::updateVideoPreviewWindow(void* displayContext)
{
   return OS_NOT_SUPPORTED;
}

/* ============================ ACCESSORS ================================= */

OsStatus sipXmediaFactoryImpl::getSpeakerVolume(int& iVolume) const
{
   OsStatus rc = OS_SUCCESS;

   iVolume = MpCodec_getVolume();
   if (iVolume==-1)
   {
      rc = OS_FAILED;
      iVolume = 0;
   }
   return rc;
}

OsStatus sipXmediaFactoryImpl::getSpeakerDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getCallDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneGain(int& iGain) const
{
   OsStatus rc = OS_SUCCESS;
   iGain = MpCodec_getGain();
   return rc;
}

OsStatus sipXmediaFactoryImpl::getMicrophoneDevice(UtlString& device) const
{
   OsStatus rc = OS_SUCCESS;
   device = DmaTask::getMicDevice();
   return rc;
}

OsStatus sipXmediaFactoryImpl::setVideoPreviewDisplay(void* pDisplay)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoQuality(int quality)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::setVideoParameters(int bitRate, int frameRate)
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoQuality(int& quality) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoBitRate(int& bitRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getVideoFrameRate(int& frameRate) const
{
   return OS_NOT_YET_IMPLEMENTED;
}

OsStatus sipXmediaFactoryImpl::getLocalAudioConnectionId(int& connectionId) const
{
   connectionId = -1;
   return OS_NOT_SUPPORTED;

}

/* ============================ INQUIRY =================================== */

/* //////////////////////////// PROTECTED ///////////////////////////////// */

/* //////////////////////////// PRIVATE /////////////////////////////////// */

/* ============================ FUNCTIONS ================================= */
<|endoftext|>


<commit_before>/*
 * main.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP),
 *        compiles on many platforms.
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../expr/ExpressionParser.h"
#include "../soe/ParallelPrimeSieve.h"
#include "../soe/pmath.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <iomanip>    /* std::setw(int) */
#include <cstdlib>    /* std::exit(int) */
#include <string>
#include <cstring>    /* std::strlen(const char*) */
#include <cctype>     /* std::tolower(int) */

namespace {
  // Unfortunately there is no easy way to get the CPU L1 and L2 cache
  // size, these values are close for most x86-64 CPUs in 2011
  const uint32_t L1_CACHE_SIZE = 64;
  const uint32_t L2_CACHE_SIZE = 512;
  const uint64_t L2_THRESHOLD = ipow(10, 11) * 5;

  bool quietMode = false;
  bool showExpressionResults = false;

  uint64_t numbers[2] = {0, 0};  /* start and stop number for sieving */
  uint32_t sieveSize = 0;        /* sieve size in KiloBytes */
  uint32_t flags = 0;            /* settings */

  int maxThreads = ParallelPrimeSieve::getMaxThreads();
  int threads = -1;

  std::string primes[7] = { "Prime numbers", "Twin primes", "Prime triplets",
    "Prime quadruplets", "Prime quintuplets", "Prime sextuplets",
    "Prime septuplets" };
}

void version() {
  std::cout << "primesieve 2.0, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl
            << "This is free software: you are free to change and redistribute it." << std::endl
            << "There is NO WARRANTY, to the extent permitted by law." << std::endl;
  std::exit(EXIT_SUCCESS);
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..." << std::endl
            << "Use the sieve of Eratosthenes to find the prime numbers and prime" << std::endl
            << "k-tuplets between START and STOP < 2^64" << std::endl
            << std::endl
            << "Examples:" << std::endl
            << "  primesieve 1 10000000 -p1" << std::endl
            << "  primesieve 1 1e11 -s 32" << std::endl
            << "  primesieve 1e18 1e18+2**32 -c1234567" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  -c[N]        Count prime numbers and/or prime k-tuplets," << std::endl
            << "               e.g -c1 count prime numbers, -c3 count prime triplets, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -p[N]        Print prime numbers or prime k-tuplets," << std::endl
            << "               e.g -p1 print prime numbers, -p2 print twin primes, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -q           Quiet mode, print less output" << std::endl
            << "  -s <SIZE>    Set the sieve size in KiloBytes, e.g. -s 256," << std::endl
            << "               set SIZE to your CPU's L1/L2 cache size for best performance" << std::endl
            << "               SIZE >= 1 and SIZE <= 8192" << std::endl
            << "  -t <THREADS> Set the number of threads for sieving, e.g. -t 4," << std::endl
            << "               THREADS >= 1 and THREADS <= " << maxThreads << " (CPU max threads)" << std::endl
            << "  -test        Run various sieving tests and exit" << std::endl
            << "  -v           Print version and license information and exit" << std::endl;
  std::exit(EXIT_SUCCESS);
}

bool isDigits(const std::string &str) {
  if (str.length() == 0)
    return false;
  return str.find_first_not_of("0123456789") == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
void processOptions(int argc, char* argv[]) {
  if (argc < 2 || argc > 20)
    help();
  ExpressionParser<uint64_t> parser;
  int i = 1;

  // process the START and STOP numbers
  if (argc > 2)
    for (; i <= 2; i++) {
      if (!parser.eval(argv[i])) {
        std::cerr << "Error: \"" << argv[i]  << "\" is not a valid arithmetic expression" << std::endl
                  << "Try `primesieve -help' for more information." << std::endl;
        std::exit(EXIT_FAILURE);
      }
      numbers[i-1] = parser.getResult();
      if (!isDigits(argv[i]))
        showExpressionResults = true;
    }

  // process the options ([OPTION]...)
  for (; i < argc; i++) {
    char* c = argv[i];
    if (*c != '-' && *c != '/')
      help();
    switch (std::tolower(*(++c)++)) {
      case 'c': do {
                  if (*c < '1' || *c > '7')
                    help();
                  flags |= COUNT_PRIMES << (*c - '1');
                } while (*(++c) != 0);
                break;
      case 'p': if (*c < '1' || *c > '7')
                  help();
                flags |= PRINT_PRIMES << (*c - '1');
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 's': if (++i >= argc || !parser.eval(argv[i]))
                  help();
                sieveSize = static_cast<uint32_t> (parser.getResult());
                sieveSize = nextHighestPowerOf2(sieveSize);
                break;
      case 't': if (std::string("test").compare(++argv[i]) == 0) {
                  test();
                  std::exit(EXIT_SUCCESS);
                }
                if (++i >= argc || !parser.eval(argv[i]))
                  help();
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': version();
      default : help();
    }
  }
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  processOptions(argc, argv);
  int width = static_cast<int> (std::strlen("Sieve size"));
  std::cout.setf(std::ios::left);

  // display expression results
  if (!quietMode && showExpressionResults)
    std::cout << std::setw(width) << "START" << " = " << numbers[0] << std::endl
              << std::setw(width) << "STOP"  << " = " << numbers[1]  << std::endl;

  // set default settings
  if ((flags & COUNT_FLAGS) == 0 && (flags & PRINT_FLAGS) == 0)
    flags |= COUNT_PRIMES;
  if (!quietMode && (flags & PRINT_FLAGS) == 0)
    flags |= PRINT_STATUS;
  if (sieveSize == 0)
    sieveSize = (numbers[1] < L2_THRESHOLD) ?L1_CACHE_SIZE :L2_CACHE_SIZE;

  if (!quietMode)
    std::cout << std::setw(width) << "Sieve size" << " = " << sieveSize
              << " KiloBytes" << std::endl;
  try {
    ParallelPrimeSieve primeSieve;
    primeSieve.setStartNumber(numbers[0]);
    primeSieve.setStopNumber(numbers[1]);
    primeSieve.setSieveSize(sieveSize);
    primeSieve.setFlags(flags);

    if (threads == -1)
      threads = primeSieve.getIdealThreadCount();
    if (!quietMode)
      std::cout << std::setw(width) << "Threads" << " = " << threads << std::endl;

    // start sieving primes
    primeSieve.sieve(threads);
    if ((flags & PRINT_STATUS) || (flags & PRINT_FLAGS))
      std::cout << std::endl;

    // get max output string length
    width = static_cast<int> (std::strlen("Time elapsed"));
    for (int i = 0; i < primeSieve.COUNTS_SIZE; i++) {
      if (flags & (COUNT_PRIMES << i)) {
        int length = static_cast<int> (primes[i].length());
        if (width < length)
          width = length;
      }
    }
    // print prime count results
    for (int i = 0; i < primeSieve.COUNTS_SIZE; i++) {
      if (flags & (COUNT_PRIMES << i))
        std::cout << std::setw(width) << primes[i] << " : " <<
            primeSieve.getCounts(i) << std::endl;
    }
    std::cout << std::setw(width) << "Time elapsed" << " : " <<
        primeSieve.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& ex) {
    std::cerr << "Error: " << ex.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    std::exit(EXIT_FAILURE);
  }
  return 0;
}
<commit_msg>updated for primesieve 2.0 release<commit_after>/*
 * main.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP),
 *        compiles on many platforms.
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../expr/ExpressionParser.h"
#include "../soe/ParallelPrimeSieve.h"
#include "../soe/pmath.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <iomanip>    /* std::setw(int) */
#include <cstdlib>    /* std::exit(int) */
#include <string>
#include <cctype>     /* std::tolower(int) */

namespace {
  // Unfortunately there is no easy way to get the CPU L1 and L2 cache
  // size, these values are close for most x86-64 CPUs in 2011
  const uint32_t L1_CACHE_SIZE = 64;
  const uint32_t L2_CACHE_SIZE = 512;
  const uint64_t L2_THRESHOLD = ipow(10, 11) * 5;

  bool quietMode = false;
  bool showExpressionResults = false;

  uint64_t numbers[2] = {0, 0};  /* start and stop number for sieving */
  uint32_t sieveSize = 0;        /* sieve size in KiloBytes */
  uint32_t flags = 0;            /* settings */

  int maxThreads = ParallelPrimeSieve::getMaxThreads();
  int threads = -1;

  std::string primes[7] = { "Prime numbers", "Twin primes", "Prime triplets",
    "Prime quadruplets", "Prime quintuplets", "Prime sextuplets",
    "Prime septuplets" };
}

void version() {
  std::cout << "primesieve 2.0, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl
            << "This is free software: you are free to change and redistribute it." << std::endl
            << "There is NO WARRANTY, to the extent permitted by law." << std::endl;
  std::exit(EXIT_SUCCESS);
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..." << std::endl
            << "Use the sieve of Eratosthenes to find the prime numbers and prime" << std::endl
            << "k-tuplets between START and STOP < 2^64" << std::endl
            << std::endl
            << "Examples:" << std::endl
            << "  primesieve 1 10000000 -p1" << std::endl
            << "  primesieve 1 1e11 -s 32" << std::endl
            << "  primesieve 1e18 1e18+2**32 -c1234567" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  -c[N]        Count prime numbers and/or prime k-tuplets," << std::endl
            << "               e.g -c1 count prime numbers, -c3 count prime triplets, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -p[N]        Print prime numbers or prime k-tuplets," << std::endl
            << "               e.g -p1 print prime numbers, -p2 print twin primes, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -q           Quiet mode, print less output" << std::endl
            << "  -s <SIZE>    Set the sieve size in KiloBytes, e.g. -s 256," << std::endl
            << "               set SIZE to your CPU's L1/L2 cache size for best performance" << std::endl
            << "               SIZE >= 1 and SIZE <= 8192" << std::endl
            << "  -t <THREADS> Set the number of threads for sieving, e.g. -t 4," << std::endl
            << "               THREADS >= 1 and THREADS <= " << maxThreads << " (CPU max threads)" << std::endl
            << "  -test        Run various sieving tests and exit" << std::endl
            << "  -v           Print version and license information and exit" << std::endl;
  std::exit(EXIT_SUCCESS);
}

bool isDigits(const std::string &str) {
  if (str.length() == 0)
    return false;
  return str.find_first_not_of("0123456789") == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
void processOptions(int argc, char* argv[]) {
  if (argc < 2 || argc > 20)
    help();
  ExpressionParser<uint64_t> parser;
  int i = 1;

  // process the START and STOP numbers
  if (argc > 2)
    for (; i <= 2; i++) {
      if (!parser.eval(argv[i])) {
        std::cerr << "Error: \"" << argv[i]  << "\" is not a valid arithmetic expression" << std::endl
                  << "Try `primesieve -help' for more information." << std::endl;
        std::exit(EXIT_FAILURE);
      }
      numbers[i-1] = parser.getResult();
      if (!isDigits(argv[i]))
        showExpressionResults = true;
    }

  // process the options ([OPTION]...)
  for (; i < argc; i++) {
    char* c = argv[i];
    if (*c != '-' && *c != '/')
      help();
    switch (std::tolower(*(++c)++)) {
      case 'c': do {
                  if (*c < '1' || *c > '7')
                    help();
                  flags |= COUNT_PRIMES << (*c - '1');
                } while (*(++c) != 0);
                break;
      case 'p': if (*c < '1' || *c > '7')
                  help();
                flags |= PRINT_PRIMES << (*c - '1');
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 's': if (++i >= argc || !parser.eval(argv[i]))
                  help();
                sieveSize = static_cast<uint32_t> (parser.getResult());
                sieveSize = nextHighestPowerOf2(sieveSize);
                break;
      case 't': if (std::string("test").compare(++argv[i]) == 0) {
                  test();
                  std::exit(EXIT_SUCCESS);
                }
                if (++i >= argc || !parser.eval(argv[i]))
                  help();
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': version();
      default : help();
    }
  }
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  processOptions(argc, argv);
  std::cout.setf(std::ios::left);

  // display expression results
  if (!quietMode && showExpressionResults)
    std::cout << std::setw(10) << "START" << " = " << numbers[0] << std::endl
              << std::setw(10) << "STOP"  << " = " << numbers[1]  << std::endl;

  // set default settings
  if ((flags & COUNT_FLAGS) == 0 && (flags & PRINT_FLAGS) == 0)
    flags |= COUNT_PRIMES;
  if (!quietMode && (flags & PRINT_FLAGS) == 0)
    flags |= PRINT_STATUS;
  if (sieveSize == 0)
    sieveSize = (numbers[1] < L2_THRESHOLD) ?L1_CACHE_SIZE :L2_CACHE_SIZE;

  if (!quietMode)
    std::cout << std::setw(10) << "Sieve size" << " = " << sieveSize
              << " KiloBytes" << std::endl;
  try {
    // init primeSieve
    ParallelPrimeSieve primeSieve;
    primeSieve.setStartNumber(numbers[0]);
    primeSieve.setStopNumber(numbers[1]);
    primeSieve.setSieveSize(sieveSize);
    primeSieve.setFlags(flags);

    if (threads == -1)
      threads = primeSieve.getIdealThreadCount();
    if (!quietMode)
      std::cout << std::setw(10) << "Threads" << " = " << threads << std::endl;

    // start sieving primes
    primeSieve.sieve(threads);

    // print new line
    if ((flags & PRINT_STATUS) || (
        (flags & PRINT_FLAGS) &&
        (flags & COUNT_FLAGS) ))
      std::cout << std::endl;

    // get max output width
    std::size_t width = (quietMode) ?0 :12;
    for (int i = 0; i < primeSieve.COUNTS_SIZE; i++)
      if ((flags & (COUNT_PRIMES << i)) && width < primes[i].length())
        width = primes[i].length();

    // print prime count results
    for (int i = 0; i < primeSieve.COUNTS_SIZE; i++)
      if (flags & (COUNT_PRIMES << i))
        std::cout << std::setw(static_cast<int> (width)) << primes[i] << " : "
                  << primeSieve.getCounts(i) << std::endl;

    // print time elapsed
    if (!quietMode)
      std::cout << std::setw(static_cast<int> (width)) << "Time elapsed" << " : "
                << primeSieve.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& ex) {
    std::cerr << "Error: " << ex.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    std::exit(EXIT_FAILURE);
  }
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>coverity#1213369 Untrusted value as argument<commit_after><|endoftext|>


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

#include <thrust/iterator/iterator_traits.h>
#include <thrust/detail/temporary_array.h>
#include <thrust/merge.h>
#include <thrust/system/detail/sequential/insertion_sort.h>

namespace thrust
{
namespace system
{
namespace detail
{
namespace sequential
{
namespace stable_merge_sort_detail
{

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void inplace_merge(sequential::execution_policy<DerivedPolicy> &exec,
                   RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator>::type value_type;

  thrust::detail::temporary_array<value_type, DerivedPolicy> a(exec, first, middle);
  thrust::detail::temporary_array<value_type, DerivedPolicy> b(exec, middle, last);

  thrust::merge(exec, a.begin(), a.end(), b.begin(), b.end(), first, comp);
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void inplace_merge_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                          RandomAccessIterator1 first1,
                          RandomAccessIterator1 middle1,
                          RandomAccessIterator1 last1,
                          RandomAccessIterator2 first2,
                          StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type value_type1;
  typedef typename thrust::iterator_value<RandomAccessIterator2>::type value_type2;

  RandomAccessIterator2 middle2 = first2 + (middle1 - first1);
  RandomAccessIterator2 last2   = first2 + (last1   - first1);

  thrust::detail::temporary_array<value_type1, DerivedPolicy> lhs1(exec, first1, middle1);
  thrust::detail::temporary_array<value_type1, DerivedPolicy> rhs1(exec, middle1, last1);
  thrust::detail::temporary_array<value_type2, DerivedPolicy> lhs2(exec, first2, middle2);
  thrust::detail::temporary_array<value_type2, DerivedPolicy> rhs2(exec, middle2, last2);

  thrust::merge_by_key(exec,
                       lhs1.begin(), lhs1.end(),
                       rhs1.begin(), rhs1.end(),
                       lhs2.begin(), rhs2.begin(),
                       first1, first2,
                       comp);
}

} // end namespace stable_merge_sort_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void stable_merge_sort(sequential::execution_policy<DerivedPolicy> &exec,
                       RandomAccessIterator first,
                       RandomAccessIterator last,
                       StrictWeakOrdering comp)
{
  if(last - first < 32)
  {
    thrust::system::detail::sequential::insertion_sort(first, last, comp);
  }
  else
  {
    RandomAccessIterator middle = first + (last - first) / 2;

    thrust::system::detail::sequential::stable_merge_sort(exec, first, middle, comp);
    thrust::system::detail::sequential::stable_merge_sort(exec, middle,  last, comp);
    stable_merge_sort_detail::inplace_merge(exec, first, middle, last, comp);
  }
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void stable_merge_sort_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                              RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              StrictWeakOrdering comp)
{
  if(last1 - first1 <= 32)
  {
    thrust::system::detail::sequential::insertion_sort_by_key(first1, last1, first2, comp);
  }
  else
  {
    RandomAccessIterator1 middle1 = first1 + (last1 - first1) / 2;
    RandomAccessIterator2 middle2 = first2 + (last1 - first1) / 2;

    thrust::system::detail::sequential::stable_merge_sort_by_key(exec, first1, middle1, first2,  comp);
    thrust::system::detail::sequential::stable_merge_sort_by_key(exec, middle1,  last1, middle2, comp);
    stable_merge_sort_detail::inplace_merge_by_key(exec, first1, middle1, last1, first2, comp);
  }
}

} // end namespace sequential
} // end namespace detail
} // end namespace system
} // end namespace thrust

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

#include <thrust/iterator/iterator_traits.h>
#include <thrust/detail/temporary_array.h>
#include <thrust/merge.h>
#include <thrust/system/detail/sequential/insertion_sort.h>

namespace thrust
{
namespace system
{
namespace detail
{
namespace sequential
{
namespace stable_merge_sort_detail
{

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void inplace_merge(sequential::execution_policy<DerivedPolicy> &exec,
                   RandomAccessIterator first,
                   RandomAccessIterator middle,
                   RandomAccessIterator last,
                   StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator>::type value_type;

  thrust::detail::temporary_array<value_type, DerivedPolicy> a(exec, first, middle);
  thrust::detail::temporary_array<value_type, DerivedPolicy> b(exec, middle, last);

  thrust::merge(exec, a.begin(), a.end(), b.begin(), b.end(), first, comp);
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void inplace_merge_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                          RandomAccessIterator1 first1,
                          RandomAccessIterator1 middle1,
                          RandomAccessIterator1 last1,
                          RandomAccessIterator2 first2,
                          StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type value_type1;
  typedef typename thrust::iterator_value<RandomAccessIterator2>::type value_type2;

  RandomAccessIterator2 middle2 = first2 + (middle1 - first1);
  RandomAccessIterator2 last2   = first2 + (last1   - first1);

  thrust::detail::temporary_array<value_type1, DerivedPolicy> lhs1(exec, first1, middle1);
  thrust::detail::temporary_array<value_type1, DerivedPolicy> rhs1(exec, middle1, last1);
  thrust::detail::temporary_array<value_type2, DerivedPolicy> lhs2(exec, first2, middle2);
  thrust::detail::temporary_array<value_type2, DerivedPolicy> rhs2(exec, middle2, last2);

  thrust::merge_by_key(exec,
                       lhs1.begin(), lhs1.end(),
                       rhs1.begin(), rhs1.end(),
                       lhs2.begin(), rhs2.begin(),
                       first1, first2,
                       comp);
}

template<typename RandomAccessIterator,
         typename Size,
         typename StrictWeakOrdering>
__host__ __device__
void insertion_sort_each(RandomAccessIterator first,
                         RandomAccessIterator last,
                         Size partition_size,
                         StrictWeakOrdering comp)
{
  if(partition_size > 1)
  {
    for(; first < last; first += partition_size)
    {
      RandomAccessIterator partition_last = thrust::min(last, first + partition_size);

      thrust::system::detail::sequential::insertion_sort(first, partition_last, comp);
    } // end for
  } // end if
} // end insertion_sort_each()

template<typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename Size,
         typename StrictWeakOrdering>
__host__ __device__
void insertion_sort_each_by_key(RandomAccessIterator1 keys_first,
                                RandomAccessIterator1 keys_last,
                                RandomAccessIterator2 values_first,
                                Size partition_size,
                                StrictWeakOrdering comp)
{
  if(partition_size > 1)
  {
    for(; keys_first < keys_last; keys_first += partition_size, values_first += partition_size)
    {
      RandomAccessIterator1 keys_partition_last = thrust::min(keys_last, keys_first + partition_size);

      thrust::system::detail::sequential::insertion_sort_by_key(keys_first, keys_partition_last, values_first, comp);
    } // end for
  } // end if
} // end insertion_sort_each()

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename Size,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void merge_adjacent_partitions(sequential::execution_policy<DerivedPolicy> &exec,
                               RandomAccessIterator1 first,
                               RandomAccessIterator1 last,
                               Size partition_size,
                               RandomAccessIterator2 result,
                               StrictWeakOrdering comp)
{
  for(; first < last; first += 2 * partition_size, result += 2 * partition_size)
  {
    RandomAccessIterator1 interval_middle = thrust::min(last, first + partition_size);
    RandomAccessIterator1 interval_last   = thrust::min(last, interval_middle + partition_size);

    thrust::merge(exec,
                  first, interval_middle,
                  interval_middle, interval_last,
                  result,
                  comp);
  } // end for
} // end merge_adjacent_partitions()

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename Size,
         typename RandomAccessIterator3,
         typename RandomAccessIterator4,
         typename StrictWeakOrdering>
__host__ __device__
void merge_adjacent_partitions_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                                      RandomAccessIterator1 keys_first,
                                      RandomAccessIterator1 keys_last,
                                      RandomAccessIterator2 values_first,
                                      Size partition_size,
                                      RandomAccessIterator3 keys_result,
                                      RandomAccessIterator4 values_result,
                                      StrictWeakOrdering comp)
{
  for(;
      keys_first < keys_last;
      keys_first += 2 * partition_size, values_first += 2 * partition_size, keys_result += 2 * partition_size, values_result += 2 * partition_size)
  {
    RandomAccessIterator1 keys_interval_middle = thrust::min(keys_last, keys_first + partition_size);
    RandomAccessIterator1 keys_interval_last   = thrust::min(keys_last, keys_interval_middle + partition_size);

    RandomAccessIterator2 values_first2 = values_first + (keys_interval_last - keys_interval_middle);

    thrust::merge_by_key(exec,
                         keys_first, keys_interval_middle,
                         keys_interval_middle, keys_interval_last,
                         values_first,
                         values_first2,
                         keys_result,
                         values_result,
                         comp);
  } // end for
} // end merge_adjacent_partitions()

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void iterative_stable_merge_sort(sequential::execution_policy<DerivedPolicy> &exec,
                                 RandomAccessIterator first,
                                 RandomAccessIterator last,
                                 StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator>::type value_type;
  typedef typename thrust::iterator_difference<RandomAccessIterator>::type difference_type;

  difference_type n = last - first;

  thrust::detail::temporary_array<value_type, DerivedPolicy> temp(exec, n);

  // insertion sort each 32 element partition
  difference_type partition_size = 32;
  insertion_sort_each(first, last, partition_size, comp);

  // ping indicates whether or not the latest data is in the source range [first, last)
  bool ping = true;

  // merge adjacent partitions until the partition size covers the entire range
  for(;
      partition_size < n;
      partition_size *= 2, ping = !ping)
  {
    if(ping)
    {
      merge_adjacent_partitions(exec, first, last, partition_size, temp.begin(), comp);
    } // end if
    else
    {
      merge_adjacent_partitions(exec, temp.begin(), temp.end(), partition_size, first, comp);
    } // end else
  } // end for m

  if(!ping)
  {
    thrust::copy(exec, temp.begin(), temp.end(), first);
  } // end if
} // end iterative_stable_merge_sort()

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void iterative_stable_merge_sort_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                                        RandomAccessIterator1 keys_first,
                                        RandomAccessIterator1 keys_last,
                                        RandomAccessIterator2 values_first,
                                        StrictWeakOrdering comp)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type      value_type1;
  typedef typename thrust::iterator_value<RandomAccessIterator2>::type      value_type2;
  typedef typename thrust::iterator_difference<RandomAccessIterator1>::type difference_type;

  difference_type n = keys_last - keys_first;

  thrust::detail::temporary_array<value_type1, DerivedPolicy> keys_temp(exec, n);
  thrust::detail::temporary_array<value_type2, DerivedPolicy> values_temp(exec, n);

  // insertion sort each 32 element partition
  difference_type partition_size = 32;
  insertion_sort_each_by_key(keys_first, keys_last, values_first, partition_size, comp);

  // ping indicates whether or not the latest data is in the source range [first, last)
  bool ping = true;

  // merge adjacent partitions until the partition size covers the entire range
  for(;
      partition_size < n;
      partition_size *= 2, ping = !ping)
  {
    if(ping)
    {
      merge_adjacent_partitions_by_key(exec, keys_first, keys_last, values_first, partition_size, keys_temp.begin(), values_temp.begin(), comp);
    } // end if
    else
    {
      merge_adjacent_partitions_by_key(exec, keys_temp.begin(), keys_temp.end(), values_temp.begin(), partition_size, keys_first, values_first, comp);
    } // end else
  } // end for m

  if(!ping)
  {
    thrust::copy(exec, keys_temp.begin(), keys_temp.end(), keys_first);
    thrust::copy(exec, values_temp.begin(), values_temp.end(), values_first);
  } // end if
} // end iterative_stable_merge_sort()

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void recursive_stable_merge_sort(sequential::execution_policy<DerivedPolicy> &exec,
                                 RandomAccessIterator first,
                                 RandomAccessIterator last,
                                 StrictWeakOrdering comp)
{
  if(last - first < 32)
  {
    thrust::system::detail::sequential::insertion_sort(first, last, comp);
  } // end if
  else
  {
    RandomAccessIterator middle = first + (last - first) / 2;

    stable_merge_sort_detail::recursive_stable_merge_sort(exec, first, middle, comp);
    stable_merge_sort_detail::recursive_stable_merge_sort(exec, middle,  last, comp);
    stable_merge_sort_detail::inplace_merge(exec, first, middle, last, comp);
  } // end else
} // end recursive_stable_merge_sort()

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void recursive_stable_merge_sort_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                                        RandomAccessIterator1 first1,
                                        RandomAccessIterator1 last1,
                                        RandomAccessIterator2 first2,
                                        StrictWeakOrdering comp)
{
  if(last1 - first1 <= 32)
  {
    thrust::system::detail::sequential::insertion_sort_by_key(first1, last1, first2, comp);
  } // end if
  else
  {
    RandomAccessIterator1 middle1 = first1 + (last1 - first1) / 2;
    RandomAccessIterator2 middle2 = first2 + (last1 - first1) / 2;

    stable_merge_sort_detail::recursive_stable_merge_sort_by_key(exec, first1, middle1, first2,  comp);
    stable_merge_sort_detail::recursive_stable_merge_sort_by_key(exec, middle1,  last1, middle2, comp);
    stable_merge_sort_detail::inplace_merge_by_key(exec, first1, middle1, last1, first2, comp);
  } // end else
} // end recursive_stable_merge_sort_by_key()

} // end namespace stable_merge_sort_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator,
         typename StrictWeakOrdering>
__host__ __device__
void stable_merge_sort(sequential::execution_policy<DerivedPolicy> &exec,
                       RandomAccessIterator first,
                       RandomAccessIterator last,
                       StrictWeakOrdering comp)
{
  // avoid recursion in CUDA threads
#ifdef __CUDA_ARCH__
  stable_merge_sort_detail::iterative_stable_merge_sort(exec, first, last, comp);
#else
  stable_merge_sort_detail::recursive_stable_merge_sort(exec, first, last, comp);
#endif
}

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename RandomAccessIterator2,
         typename StrictWeakOrdering>
__host__ __device__
void stable_merge_sort_by_key(sequential::execution_policy<DerivedPolicy> &exec,
                              RandomAccessIterator1 first1,
                              RandomAccessIterator1 last1,
                              RandomAccessIterator2 first2,
                              StrictWeakOrdering comp)
{
  // avoid recursion in CUDA threads
#ifdef __CUDA_ARCH__
  stable_merge_sort_detail::iterative_stable_merge_sort_by_key(exec, first1, last1, first2, comp);
#else
  stable_merge_sort_detail::recursive_stable_merge_sort_by_key(exec, first1, last1, first2, comp);
#endif
}

} // end namespace sequential
} // end namespace detail
} // end namespace system
} // end namespace thrust

<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkIdentColoredPainter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkIdentColoredPainter.h"

#include "vtkActor.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkConfigure.h"
#include "vtkDataArray.h"
#include "vtkObjectFactory.h"
#include "vtkPainterDeviceAdapter.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolygon.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkTimerLog.h"
#include "vtkTriangle.h"
#include "vtkIdTypeArray.h"

#ifndef VTK_IMPLEMENT_MESA_CXX
#  include "vtkOpenGL.h"
#endif

//-----------------------------------------------------------------------------
vtkCxxRevisionMacro(vtkIdentColoredPainter, "1.15");
vtkStandardNewMacro(vtkIdentColoredPainter);

//-----------------------------------------------------------------------------
static inline int vtkIdentColoredPainterGetTotalCells(vtkPolyData* pd,
  unsigned long typeflags)
{
  int total_cells = 0;
  total_cells += (typeflags & vtkPainter::VERTS)?
    pd->GetNumberOfVerts() : 0;
  total_cells += (typeflags & vtkPainter::LINES)?
    pd->GetNumberOfLines() : 0;
  total_cells += (typeflags & vtkPainter::POLYS)?
    pd->GetNumberOfPolys() : 0;
  total_cells += (typeflags & vtkPainter::STRIPS)?
    pd->GetNumberOfStrips() : 0;
  return total_cells;
}

//-----------------------------------------------------------------------------
vtkIdentColoredPainter::vtkIdentColoredPainter()
{
  this->ColorMode = COLORBYIDENT;
  this->ResetCurrentId();

  this->ActorIds = NULL;
  this->PropAddrs = NULL;
}

//-----------------------------------------------------------------------------
vtkIdentColoredPainter::~vtkIdentColoredPainter()
{
  if (this->ActorIds != NULL)
    {
    this->ActorIds->Delete();
    this->ActorIds = NULL;
    delete[] this->PropAddrs;
    this->PropAddrs = NULL;
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByConstant(unsigned int constant)
{
  this->ColorMode = COLORBYCONST;
  this->ResetCurrentId();
  this->CurrentIdPlane0 = constant;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::MakeActorLookupTable(vtkProp **props, vtkIdTypeArray *ids)
{
  //free whatever we were given before this
  if (this->ActorIds != NULL)
    {
    this->ActorIds->Delete();
    this->ActorIds = NULL;
    delete[] this->PropAddrs;
    this->PropAddrs = NULL;
    }

  //sanity checking
  if (props == NULL ||
      ids == NULL ||
      (ids->GetNumberOfComponents() != 1) ||
      (ids->GetNumberOfTuples() == 0))
    {
    vtkWarningMacro("Invalid actor-id lookup table supplied.");
    return;
    }

  //copy over the new lookup table
  this->ActorIds = ids;
  this->ActorIds->Register(this);
  this->PropAddrs = new vtkProp*[ids->GetNumberOfTuples()];
  for (int i = 0; i < ids->GetNumberOfTuples(); i++)
    {
    this->PropAddrs[i] = props[i];
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByActorId(vtkProp *actorAddr)
{
  this->ColorMode = COLORBYCONST;
  this->ResetCurrentId();

  vtkIdType maxId = 0;
  int numIds = 0;
  if (this->ActorIds != NULL)
    {
    numIds = this->ActorIds->GetNumberOfTuples();
    for (int i = 0; i< numIds; i++)
      {
      vtkIdType nextId = this->ActorIds->GetValue(i);
      if (actorAddr == this->PropAddrs[i])
        {
        this->CurrentIdPlane0 = nextId + 1;
        return;
        }
      if (nextId > maxId)
        {
        maxId = nextId;
        }
      }
    }

  //we didn't find the actor in the table, make up an ID and add it
  //cerr << "ID not found for actor " << actorAddr
  //     << " using " << maxId+1 << endl;
  vtkIdTypeArray *arr = vtkIdTypeArray::New();
  arr->SetNumberOfComponents(1);
  arr->SetNumberOfTuples(numIds+1);
  vtkProp **SaveProps = new vtkProp*[numIds+1];
  if (this->ActorIds != NULL)
    {
    for (int i = 0; i< numIds; i++)
      {
      arr->SetValue(i, this->ActorIds->GetValue(i));
      SaveProps[i] = this->PropAddrs[i];
      }
    }
  arr->SetValue(numIds, maxId+1);
  SaveProps[numIds] = actorAddr;
  this->MakeActorLookupTable(SaveProps, arr);
  arr->Delete();

  this->CurrentIdPlane0 = maxId+1;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByIncreasingIdent(unsigned int plane)
{
  this->ColorMode = COLORBYIDENT;
  this->Plane = (plane < 3)?plane:2;
  this->ResetCurrentId();
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ResetCurrentId()
{
  //do not use 0, it is reserved for miss
  this->CurrentIdPlane0 = 1;
  this->CurrentIdPlane1 = 1;
  this->CurrentIdPlane2 = 1;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::IncrementCurrentId()
{
  if (this->ColorMode == COLORBYCONST)
    {
    return;
    }

  //the limits are set up assuming 24 bits total for each for RGB pixel
  //do not use A because the parallel compositing code does not support Alpha
  this->CurrentIdPlane0++;
  if (this->CurrentIdPlane0 >= 0x01000000)
    {
    this->CurrentIdPlane0 = 0x00000001;
    this->CurrentIdPlane1++;
    if (this->CurrentIdPlane1 >= 0x01000000)
      {
      this->CurrentIdPlane1 = 0x00000001;
      this->CurrentIdPlane2++;
      }
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::GetCurrentColor(unsigned char *RGB)
{
  unsigned int val = this->CurrentIdPlane0;
  if (this->ColorMode == COLORBYIDENT)
    {
    if (this->Plane == 1)
      {
      val = this->CurrentIdPlane1;
      }
    else if (this->Plane == 2)
      {
      val = this->CurrentIdPlane2;
      }
    }

  //cerr << "Curr Color is "
  //     << this->ColorMode << " "
  //     << this->CurrentIdPlane2 << ":"
  //     << this->CurrentIdPlane1 << ":"
  //     << this->CurrentIdPlane0 << endl;

  RGB[0] = (val & 0x00FF0000)>>16;
  RGB[1] = (val & 0x0000FF00)>>8;
  RGB[2] = (val & 0x000000FF);
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::RenderInternal(vtkRenderer* renderer,
                                            vtkActor* actor,
                                            unsigned long typeflags)
{
  if (typeflags == 0)
    {
    // No primitive to render.
    return;
    }

  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  if (!device)
    {
    vtkErrorMacro("Painter Device Adapter missing!");
    return;
    }

  this->TotalCells =
    vtkIdentColoredPainterGetTotalCells(this->PolyData, typeflags);

  this->Timer->StartTimer();

  //turn off antialising and lighting so that the colors we draw will be the
  //colors we read back
  int origMultisample = device->QueryMultisampling();
  int origLighting = device->QueryLighting();
  int origBlending = device->QueryBlending();

  device->MakeMultisampling(0);
  device->MakeLighting(0);
  device->MakeBlending(0);

  vtkIdType startCell = 0;
  if (typeflags & vtkPainter::VERTS)
    {
    this->DrawCells(VTK_POLY_VERTEX, this->PolyData->GetVerts(), startCell,
      renderer);
    }
  startCell += this->PolyData->GetNumberOfVerts();

  if (typeflags & vtkPainter::LINES)
    {
    this->DrawCells(VTK_POLY_LINE, this->PolyData->GetLines(), startCell,
      renderer);
    }
  startCell += this->PolyData->GetNumberOfLines();

  if (typeflags & vtkPainter::POLYS)
    {
#if defined(__APPLE__) && (defined(VTK_USE_CARBON) || defined(VTK_USE_COCOA))
    if (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME)
      {
      this->DrawCells(VTK_TETRA, this->PolyData->GetPolys(), startCell,
        renderer);
      }
    else
#endif
      {
      this->DrawCells(VTK_POLYGON, this->PolyData->GetPolys(), startCell,
        renderer);
      }
    }

  startCell += this->PolyData->GetNumberOfPolys();
  if (typeflags & vtkPainter::STRIPS)
    {
    this->DrawCells(VTK_TRIANGLE_STRIP, this->PolyData->GetStrips(), startCell,
      renderer);
    }

  //reset lighting back to the default
  device->MakeBlending(origBlending);
  device->MakeLighting(origLighting);
  device->MakeMultisampling(origMultisample);

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();

  // let the superclass pass on the request to delegate painter.
  // Ofcouse, more than likely, this call will never have a delegate,
  // but anyways.
  this->Superclass::RenderInternal(renderer, actor, typeflags);
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::DrawCells(int mode, vtkCellArray *connectivity,
                                       vtkIdType startCellId,
                                       vtkRenderer *renderer)
{
  if (!this->PolyData)
    {
    vtkWarningMacro("No polydata to render!");
    return;
    }

  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  vtkPoints* p = this->PolyData->GetPoints();
  vtkIdType npts, *pts;
  vtkIdType cellId = startCellId;

  int pointtype = p->GetDataType();
  void* voidpoints = p->GetVoidPointer(0);
  int count = 0;

  unsigned char color[3];
  for (connectivity->InitTraversal(); connectivity->GetNextCell(npts, pts); count++)
    {
    device->BeginPrimitive(mode);

    // fieldColors are same as cell colors except when rendering
    // VTK_TRIANGLE_STRIP, when they represent triangle colors.
    this->GetCurrentColor(color);

    device->SendAttribute(vtkCellData::SCALARS, 3, VTK_UNSIGNED_CHAR, color);

    this->IncrementCurrentId();

    for (vtkIdType cellpointi = 0; cellpointi < npts; cellpointi++)
      {
      vtkIdType pointId = pts[cellpointi];
      // If using field colors, then we must send triangle colors,
      // if rendering triangle strips.
      if (mode == VTK_TRIANGLE_STRIP && cellpointi > 2)
        {
        this->GetCurrentColor(color);

        device->SendAttribute(vtkCellData::SCALARS, 3, VTK_UNSIGNED_CHAR, color);

        this->IncrementCurrentId();
        }

      // Send the point position as the last attribute.
      // TODO: how to mark that point position is being sent? since,
      // vtkDataSetAttributes doesn't define point positions and hence has
      // no enum for that. For now, vtkPointData::NUM_ATTRIBUTES marks
      // point positions.
      device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3,
        pointtype, voidpoints, 3*pointId);
      }
    device->EndPrimitive();

    cellId++;

    if (count == 10000)
      {
      count = 0;
      // report progress
      this->UpdateProgress(static_cast<double>(cellId - startCellId)/this->TotalCells);
      // Abort render.
      if (renderer->GetRenderWindow()->CheckAbortStatus())
        {
        return;
        }
      }
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>BUG: Fix selection on polydata with triangle strips. Took out my partial attempt to give each tri within the strip its own id. Now selection of any tri in the strip will simply return the id for the whole strip.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkIdentColoredPainter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkIdentColoredPainter.h"

#include "vtkActor.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkConfigure.h"
#include "vtkDataArray.h"
#include "vtkObjectFactory.h"
#include "vtkPainterDeviceAdapter.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolygon.h"
#include "vtkProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkTimerLog.h"
#include "vtkTriangle.h"
#include "vtkIdTypeArray.h"

#ifndef VTK_IMPLEMENT_MESA_CXX
#  include "vtkOpenGL.h"
#endif

//-----------------------------------------------------------------------------
vtkCxxRevisionMacro(vtkIdentColoredPainter, "1.16");
vtkStandardNewMacro(vtkIdentColoredPainter);

//-----------------------------------------------------------------------------
static inline int vtkIdentColoredPainterGetTotalCells(vtkPolyData* pd,
  unsigned long typeflags)
{
  int total_cells = 0;
  total_cells += (typeflags & vtkPainter::VERTS)?
    pd->GetNumberOfVerts() : 0;
  total_cells += (typeflags & vtkPainter::LINES)?
    pd->GetNumberOfLines() : 0;
  total_cells += (typeflags & vtkPainter::POLYS)?
    pd->GetNumberOfPolys() : 0;
  total_cells += (typeflags & vtkPainter::STRIPS)?
    pd->GetNumberOfStrips() : 0;
  return total_cells;
}

//-----------------------------------------------------------------------------
vtkIdentColoredPainter::vtkIdentColoredPainter()
{
  this->ColorMode = COLORBYIDENT;
  this->ResetCurrentId();

  this->ActorIds = NULL;
  this->PropAddrs = NULL;
}

//-----------------------------------------------------------------------------
vtkIdentColoredPainter::~vtkIdentColoredPainter()
{
  if (this->ActorIds != NULL)
    {
    this->ActorIds->Delete();
    this->ActorIds = NULL;
    delete[] this->PropAddrs;
    this->PropAddrs = NULL;
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByConstant(unsigned int constant)
{
  this->ColorMode = COLORBYCONST;
  this->ResetCurrentId();
  this->CurrentIdPlane0 = constant;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::MakeActorLookupTable(vtkProp **props, vtkIdTypeArray *ids)
{
  //free whatever we were given before this
  if (this->ActorIds != NULL)
    {
    this->ActorIds->Delete();
    this->ActorIds = NULL;
    delete[] this->PropAddrs;
    this->PropAddrs = NULL;
    }

  //sanity checking
  if (props == NULL ||
      ids == NULL ||
      (ids->GetNumberOfComponents() != 1) ||
      (ids->GetNumberOfTuples() == 0))
    {
    vtkWarningMacro("Invalid actor-id lookup table supplied.");
    return;
    }

  //copy over the new lookup table
  this->ActorIds = ids;
  this->ActorIds->Register(this);
  this->PropAddrs = new vtkProp*[ids->GetNumberOfTuples()];
  for (int i = 0; i < ids->GetNumberOfTuples(); i++)
    {
    this->PropAddrs[i] = props[i];
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByActorId(vtkProp *actorAddr)
{
  this->ColorMode = COLORBYCONST;
  this->ResetCurrentId();

  vtkIdType maxId = 0;
  int numIds = 0;
  if (this->ActorIds != NULL)
    {
    numIds = this->ActorIds->GetNumberOfTuples();
    for (int i = 0; i< numIds; i++)
      {
      vtkIdType nextId = this->ActorIds->GetValue(i);
      if (actorAddr == this->PropAddrs[i])
        {
        this->CurrentIdPlane0 = nextId + 1;
        return;
        }
      if (nextId > maxId)
        {
        maxId = nextId;
        }
      }
    }

  //we didn't find the actor in the table, make up an ID and add it
  //cerr << "ID not found for actor " << actorAddr
  //     << " using " << maxId+1 << endl;
  vtkIdTypeArray *arr = vtkIdTypeArray::New();
  arr->SetNumberOfComponents(1);
  arr->SetNumberOfTuples(numIds+1);
  vtkProp **SaveProps = new vtkProp*[numIds+1];
  if (this->ActorIds != NULL)
    {
    for (int i = 0; i< numIds; i++)
      {
      arr->SetValue(i, this->ActorIds->GetValue(i));
      SaveProps[i] = this->PropAddrs[i];
      }
    }
  arr->SetValue(numIds, maxId+1);
  SaveProps[numIds] = actorAddr;
  this->MakeActorLookupTable(SaveProps, arr);
  arr->Delete();

  this->CurrentIdPlane0 = maxId+1;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ColorByIncreasingIdent(unsigned int plane)
{
  this->ColorMode = COLORBYIDENT;
  this->Plane = (plane < 3)?plane:2;
  this->ResetCurrentId();
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::ResetCurrentId()
{
  //do not use 0, it is reserved for miss
  this->CurrentIdPlane0 = 1;
  this->CurrentIdPlane1 = 1;
  this->CurrentIdPlane2 = 1;
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::IncrementCurrentId()
{
  if (this->ColorMode == COLORBYCONST)
    {
    return;
    }

  //the limits are set up assuming 24 bits total for each for RGB pixel
  //do not use A because the parallel compositing code does not support Alpha
  this->CurrentIdPlane0++;
  if (this->CurrentIdPlane0 >= 0x01000000)
    {
    this->CurrentIdPlane0 = 0x00000001;
    this->CurrentIdPlane1++;
    if (this->CurrentIdPlane1 >= 0x01000000)
      {
      this->CurrentIdPlane1 = 0x00000001;
      this->CurrentIdPlane2++;
      }
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::GetCurrentColor(unsigned char *RGB)
{
  unsigned int val = this->CurrentIdPlane0;
  if (this->ColorMode == COLORBYIDENT)
    {
    if (this->Plane == 1)
      {
      val = this->CurrentIdPlane1;
      }
    else if (this->Plane == 2)
      {
      val = this->CurrentIdPlane2;
      }
    }

  //cerr << "Curr Color is "
  //     << this->ColorMode << " "
  //     << this->CurrentIdPlane2 << ":"
  //     << this->CurrentIdPlane1 << ":"
  //     << this->CurrentIdPlane0 << endl;

  RGB[0] = (val & 0x00FF0000)>>16;
  RGB[1] = (val & 0x0000FF00)>>8;
  RGB[2] = (val & 0x000000FF);
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::RenderInternal(vtkRenderer* renderer,
                                            vtkActor* actor,
                                            unsigned long typeflags)
{
  if (typeflags == 0)
    {
    // No primitive to render.
    return;
    }

  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  if (!device)
    {
    vtkErrorMacro("Painter Device Adapter missing!");
    return;
    }

  this->TotalCells =
    vtkIdentColoredPainterGetTotalCells(this->PolyData, typeflags);

  this->Timer->StartTimer();

  //turn off antialising and lighting so that the colors we draw will be the
  //colors we read back
  int origMultisample = device->QueryMultisampling();
  int origLighting = device->QueryLighting();
  int origBlending = device->QueryBlending();

  device->MakeMultisampling(0);
  device->MakeLighting(0);
  device->MakeBlending(0);

  vtkIdType startCell = 0;

  if (typeflags & vtkPainter::VERTS)
    {
    this->DrawCells(VTK_POLY_VERTEX, this->PolyData->GetVerts(), startCell,
      renderer);
    }
  startCell += this->PolyData->GetNumberOfVerts();

  if (typeflags & vtkPainter::LINES)
    {
    this->DrawCells(VTK_POLY_LINE, this->PolyData->GetLines(), startCell,
      renderer);
    }
  startCell += this->PolyData->GetNumberOfLines();

  if (typeflags & vtkPainter::POLYS)
    {
#if defined(__APPLE__) && (defined(VTK_USE_CARBON) || defined(VTK_USE_COCOA))
    if (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME)
      {
      this->DrawCells(VTK_TETRA, this->PolyData->GetPolys(), startCell,
        renderer);
      }
    else
#endif
      {
      this->DrawCells(VTK_POLYGON, this->PolyData->GetPolys(), startCell,
        renderer);
      }
    }
  startCell += this->PolyData->GetNumberOfPolys();

  if (typeflags & vtkPainter::STRIPS)
    {
    this->DrawCells(VTK_TRIANGLE_STRIP, this->PolyData->GetStrips(), startCell,
      renderer);
    }
  startCell += this->PolyData->GetNumberOfStrips();

  //reset lighting back to the default
  device->MakeBlending(origBlending);
  device->MakeLighting(origLighting);
  device->MakeMultisampling(origMultisample);

  this->Timer->StopTimer();
  this->TimeToDraw = this->Timer->GetElapsedTime();

  // let the superclass pass on the request to delegate painter.
  // Ofcouse, more than likely, this call will never have a delegate,
  // but anyways.
  this->Superclass::RenderInternal(renderer, actor, typeflags);
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::DrawCells(int mode, vtkCellArray *connectivity,
                                       vtkIdType startCellId,
                                       vtkRenderer *renderer)
{
  if (!this->PolyData)
    {
    vtkWarningMacro("No polydata to render!");
    return;
    }

  vtkPainterDeviceAdapter* device = renderer->GetRenderWindow()->
    GetPainterDeviceAdapter();

  vtkPoints* p = this->PolyData->GetPoints();
  vtkIdType npts, *pts;
  vtkIdType cellId = startCellId;

  int pointtype = p->GetDataType();
  void* voidpoints = p->GetVoidPointer(0);
  int count = 0;

  unsigned char color[3];
  for (connectivity->InitTraversal(); connectivity->GetNextCell(npts, pts); count++)
    {
    device->BeginPrimitive(mode);

    // fieldColors are same as cell colors except when rendering
    // VTK_TRIANGLE_STRIP, when they represent triangle colors.
    this->GetCurrentColor(color);

    device->SendAttribute(vtkCellData::SCALARS, 3, VTK_UNSIGNED_CHAR, color);

    for (vtkIdType cellpointi = 0; cellpointi < npts; cellpointi++)
      {
      vtkIdType pointId = pts[cellpointi];
      if (mode == VTK_TRIANGLE_STRIP && cellpointi > 2)
        {
        this->GetCurrentColor(color);

        device->SendAttribute(vtkCellData::SCALARS, 3, VTK_UNSIGNED_CHAR, color);
        }

      // Send the point position as the last attribute.
      // TODO: how to mark that point position is being sent? since,
      // vtkDataSetAttributes doesn't define point positions and hence has
      // no enum for that. For now, vtkPointData::NUM_ATTRIBUTES marks
      // point positions.
      device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3,
        pointtype, voidpoints, 3*pointId);
      }

    this->IncrementCurrentId();

    device->EndPrimitive();

    cellId++;

    if (count == 10000)
      {
      count = 0;
      // report progress
      this->UpdateProgress(static_cast<double>(cellId - startCellId)/this->TotalCells);
      // Abort render.
      if (renderer->GetRenderWindow()->CheckAbortStatus())
        {
        return;
        }
      }
    }
}

//-----------------------------------------------------------------------------
void vtkIdentColoredPainter::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>#ifndef _mex_traits_hpp__
#define _mex_traits_hpp__

// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include "__configure__.hpp"
#include "types.hpp"
#include <exception>

namespace mex {

    template<typename T, type_t U>
    struct common_traits
    {
        typedef T value_type;
        typedef T * pointer;
        typedef const T * const_pointer;
        static const type_t type_code = U;

        static ::mxArray * check ( ::mxArray * array )
        {
            if ( array == 0 ) {
                throw (std::invalid_argument("MATLAB: invalid class"));
            }
            if ( ::mxGetClassID(array) != type_code ) {
                throw (std::bad_cast());
            }
            return (array);
        }

        static const ::mxArray * check ( const ::mxArray * array )
        {
            if ( array == 0 ) {
                throw (std::invalid_argument("MATLAB: invalid class"));
            }
            if ( ::mxGetClassID(array) != type_code ) {
                throw (std::bad_cast());
            }
            return (array);
        }
    };

    template<typename T, type_t U>
    struct numeric_traits :
        public common_traits< T, U >
    {
        static ::mxArray * matrix ( size_t m, size_t n, const real_t& )
        {
            ::mxArray *const result = ::mxCreateNumericMatrix
                (m, n, type_code, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * matrix ( size_t m, size_t n, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateNumericMatrix
                (m, n, type_code, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * array ( int ndim, const int * dims, const real_t& )
        {
            ::mxArray *const result = ::mxCreateNumericArray
                (ndim, dims, type_code, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * array
            ( int ndim, const int * dims, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateNumericArray
                (ndim, dims, type_code, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<typename T> struct traits;

    template<> struct traits< char_t > :
        public common_traits< char_t, mxCHAR_CLASS >
    {
        static ::mxArray * matrix ( size_t m, size_t n )
        {
            const size_t dims[] = { m, n };
            ::mxArray *const result = ::mxCreateCharArray(2, dims);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< double > :
        public common_traits< double, mxDOUBLE_CLASS >
    {
        static ::mxArray * matrix ( size_t m, size_t n, const real_t& )
        {
            ::mxArray *const result = ::mxCreateDoubleMatrix(m, n, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * matrix ( size_t m, size_t n, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateDoubleMatrix(m, n, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< logical > :
        public common_traits< double, mxLOGICAL_CLASS >
    {
        static ::mxArray * create ( size_t m, size_t n )
        {
            ::mxArray *const result = ::mxCreateLogicalMatrix(m, n);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< function > :
        public common_traits< function, mxFUNCTION_CLASS >
    {
    };

    template<> struct traits< unknown > :
        public common_traits< unknown, mxUNKNOWN_CLASS >
    {
    };

    template<> struct traits< object > :
        public common_traits< object, mxOBJECT_CLASS >
    {
    };

    template<> struct traits< int8 > :
        public numeric_traits< int8, mxINT8_CLASS >
    {
    };

    template<> struct traits< uint8 > :
        public numeric_traits< uint8, mxUINT8_CLASS >
    {
    };

    template<> struct traits< int16 > :
        public numeric_traits< int16, mxINT16_CLASS >
    {
    };

    template<> struct traits< uint16 > :
        public numeric_traits< uint16, mxUINT16_CLASS >
    {
    };

    template<> struct traits< int32 > :
        public numeric_traits< int32, mxINT32_CLASS >
    {
    };

    template<> struct traits< uint32 > :
        public numeric_traits< uint32, mxUINT32_CLASS >
    {
    };

    template<> struct traits< int64 > :
        public numeric_traits< int64, mxINT64_CLASS >
    {
    };

    template<> struct traits< uint64 > :
        public numeric_traits< uint64, mxUINT64_CLASS >
    {
    };

}

#endif /* _mex_traits_hpp__ */
<commit_msg>Added support for floats.<commit_after>#ifndef _mex_traits_hpp__
#define _mex_traits_hpp__

// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include "__configure__.hpp"
#include "types.hpp"
#include <exception>

namespace mex {

    template<typename T, type_t U>
    struct common_traits
    {
        typedef T value_type;
        typedef T * pointer;
        typedef const T * const_pointer;
        static const type_t type_code = U;

        static ::mxArray * check ( ::mxArray * array )
        {
            if ( array == 0 ) {
                throw (std::invalid_argument("MATLAB: invalid class"));
            }
            if ( ::mxGetClassID(array) != type_code ) {
                throw (std::bad_cast());
            }
            return (array);
        }

        static const ::mxArray * check ( const ::mxArray * array )
        {
            if ( array == 0 ) {
                throw (std::invalid_argument("MATLAB: invalid class"));
            }
            if ( ::mxGetClassID(array) != type_code ) {
                throw (std::bad_cast());
            }
            return (array);
        }
    };

    template<typename T, type_t U>
    struct numeric_traits :
        public common_traits< T, U >
    {
        static ::mxArray * matrix ( size_t m, size_t n, const real_t& )
        {
            ::mxArray *const result = ::mxCreateNumericMatrix
                (m, n, type_code, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * matrix ( size_t m, size_t n, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateNumericMatrix
                (m, n, type_code, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * array ( int ndim, const int * dims, const real_t& )
        {
            ::mxArray *const result = ::mxCreateNumericArray
                (ndim, dims, type_code, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * array
            ( int ndim, const int * dims, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateNumericArray
                (ndim, dims, type_code, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<typename T> struct traits;

    template<> struct traits< char_t > :
        public common_traits< char_t, mxCHAR_CLASS >
    {
        static ::mxArray * matrix ( size_t m, size_t n )
        {
            const size_t dims[] = { m, n };
            ::mxArray *const result = ::mxCreateCharArray(2, dims);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< double > :
        public common_traits< double, mxDOUBLE_CLASS >
    {
        static ::mxArray * matrix ( size_t m, size_t n, const real_t& )
        {
            ::mxArray *const result = ::mxCreateDoubleMatrix(m, n, mxREAL);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }

        static ::mxArray * matrix ( size_t m, size_t n, const complex_t& )
        {
            ::mxArray *const result = ::mxCreateDoubleMatrix(m, n, mxCOMPLEX);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< logical > :
        public common_traits< bool, mxLOGICAL_CLASS >
    {
        static ::mxArray * create ( size_t m, size_t n )
        {
            ::mxArray *const result = ::mxCreateLogicalMatrix(m, n);
            if ( result == 0 ) {
                throw (std::bad_alloc());
            }
            return (result);
        }
    };

    template<> struct traits< float > :
        public numeric_traits< float, mxSINGLE_CLASS >
    {
    };

    template<> struct traits< function > :
        public common_traits< function, mxFUNCTION_CLASS >
    {
    };

    template<> struct traits< unknown > :
        public common_traits< unknown, mxUNKNOWN_CLASS >
    {
    };

    template<> struct traits< object > :
        public common_traits< object, mxOBJECT_CLASS >
    {
    };

    template<> struct traits< int8 > :
        public numeric_traits< int8, mxINT8_CLASS >
    {
    };

    template<> struct traits< uint8 > :
        public numeric_traits< uint8, mxUINT8_CLASS >
    {
    };

    template<> struct traits< int16 > :
        public numeric_traits< int16, mxINT16_CLASS >
    {
    };

    template<> struct traits< uint16 > :
        public numeric_traits< uint16, mxUINT16_CLASS >
    {
    };

    template<> struct traits< int32 > :
        public numeric_traits< int32, mxINT32_CLASS >
    {
    };

    template<> struct traits< uint32 > :
        public numeric_traits< uint32, mxUINT32_CLASS >
    {
    };

    template<> struct traits< int64 > :
        public numeric_traits< int64, mxINT64_CLASS >
    {
    };

    template<> struct traits< uint64 > :
        public numeric_traits< uint64, mxUINT64_CLASS >
    {
    };

}

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