<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel 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.                                           //
// ======================================================================== //

// ospray
#include "lights/Light.h"
#include "common/Data.h"
#include "common/Core.h"
#include "common/tasking/parallel_for.h"
#include "render/volume/RaycastVolumeRenderer.h"
#include "RaycastVolumeMaterial.h"

// ispc exports
#include "RaycastVolumeRenderer_ispc.h"
#if EXP_DATA_PARALLEL
# include "mpi/DistributedFrameBuffer.h"
# include "volume/DataDistributedBlockedVolume.h"
# include "render/LoadBalancer.h"
#endif

#define TILE_CACHE_SAFE_MUTEX 0

namespace ospray {

  Material *RaycastVolumeRenderer::createMaterial(const char *type)
  {
    return new RaycastVolumeMaterial;
  }

#if EXP_DATA_PARALLEL

  struct CacheForBlockTiles
  {
    CacheForBlockTiles(size_t numBlocks)
      : numBlocks(numBlocks), blockTile(new Tile *[numBlocks])
    {
      for (int i = 0; i < numBlocks; i++) blockTile[i] = nullptr;
    }

    ~CacheForBlockTiles()
    {
      for (int i = 0; i < numBlocks; i++)
        if (blockTile[i]) delete blockTile[i];

      delete[] blockTile;
    }

    Tile *allocTile()
    {
      float infinity = std::numeric_limits<float>::infinity();
      Tile *tile = new Tile;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->r[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->g[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->b[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->a[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->z[i] = infinity;
      return tile;
    }

    Tile *getTileForBlock(size_t blockID)
    {
#if TILE_CACHE_SAFE_MUTEX
      mutex.lock();
      Tile *tile = blockTile[blockID];
      if (tile == nullptr) {
        blockTile[blockID] = tile = allocTile();
      }
      mutex.unlock();
      return tile;
#else
      Tile *tile = blockTile[blockID];
      if (tile != nullptr) return tile;
      mutex.lock();
      tile = blockTile[blockID];
      if (tile == nullptr) {
        blockTile[blockID] = tile = allocTile();
      }
      mutex.unlock();
      return tile;
#endif
    }

    Mutex mutex;
    size_t numBlocks;
    Tile *volatile *blockTile;
  };

  /*! extern exported function so even ISPC code can access this cache */
  extern "C" Tile *
  CacheForBlockTiles_getTileForBlock(CacheForBlockTiles *cache,
                                     uint32 blockID)
  {
    return cache->getTileForBlock(blockID);
  }

  struct DPRenderTask
  {
    mutable Ref<Renderer>     renderer;
    mutable Ref<FrameBuffer>  fb;
    size_t                    numTiles_x;
    size_t                    numTiles_y;
    uint32                    channelFlags;
    const DataDistributedBlockedVolume *dpv;

    void operator()(int taskIndex) const;
  };

  void DPRenderTask::operator()(int taskIndex) const
  {
    const size_t tileID = taskIndex;
    const size_t tile_y = taskIndex / numTiles_x;
    const size_t tile_x = taskIndex - tile_y*numTiles_x;
    const vec2i tileId(tile_x, tile_y);
    const int32 accumID = fb->accumID(tileId);
    Tile bgTile(tileId, fb->size, accumID);
    Tile fgTile(bgTile);

    size_t numBlocks = dpv->numDDBlocks;
    CacheForBlockTiles blockTileCache(numBlocks);
    bool *blockWasVisible = STACK_BUFFER(bool, numBlocks);

    for (int i = 0; i < numBlocks; i++)
      blockWasVisible[i] = false;

    bool renderForeAndBackground =
        (taskIndex % core::getWorkerCount()) == core::getWorkerRank();

    const int numJobs = (TILE_SIZE*TILE_SIZE)/RENDERTILE_PIXELS_PER_JOB;

    parallel_for(numJobs, [&](int tid){
      ispc::DDDVRRenderer_renderTile(renderer->getIE(),
                                     (ispc::Tile&)fgTile,
                                     (ispc::Tile&)bgTile,
                                     &blockTileCache,
                                     numBlocks,
                                     dpv->ddBlock,
                                     blockWasVisible,
                                     tileID,
                                     ospray::core::getWorkerRank(),
                                     renderForeAndBackground,
                                     tid);
    });

    if (renderForeAndBackground) {
      // this is a tile owned by me - i'm responsible for writing
      // generaition #0, and telling the fb how many more tiles will
      // be coming in generation #1

      size_t totalBlocksInTile = 0;
      for (int blockID = 0; blockID < numBlocks; blockID++) {
        if (blockWasVisible[blockID])
          totalBlocksInTile++;
      }

      size_t nextGenTiles
          = 1 /* expect one additional tile for background tile. */
          + totalBlocksInTile /* plus how many blocks map to this
                                     tile, IN TOTAL (ie, INCLUDING blocks
                                     on other nodes)*/;
      // printf("rank %i total tiles in tile %i is %i\n",
      //        core::getWorkerRank(),taskIndex,nextGenTiles);

      // set background tile
      bgTile.generation = 0;
      bgTile.children   = nextGenTiles;
      fb->setTile(bgTile);

      // set foreground tile
      fgTile.generation = 1;
      fgTile.children   = 0; //nextGenTiles-1;
      fb->setTile(fgTile);
      // all other tiles for gen #1 will be set below, no matter whether
      // it's mine or not
    }

    // now, send all block cache tiles that were generated on this
    // node back to master, too. for this, it doesn't matter if this
    // is our tile or not; it's the job of the owner of this tile to
    // tell the DFB how many tiles will arrive for the final thile
    // _across_all_clients_, but we only have to send ours (assuming
    // that all clients together send exactly as many as the owner
    // told the DFB to expect)
    for (int blockID = 0; blockID < numBlocks; blockID++) {
      Tile *tile = blockTileCache.blockTile[blockID];
      if (tile == nullptr)
        continue;

      tile->region = bgTile.region;
      tile->fbSize = bgTile.fbSize;
      tile->rcp_fbSize = bgTile.rcp_fbSize;
      tile->generation = 1;
      tile->children   = 0; //nextGenTile-1;

      fb->setTile(*tile);
    }
  }

  /*! try if we are running in data-parallel mode, and if
    data-parallel is even required. if not (eg, if there's no
    data-parallel volumes in the scene) return nullptr and render only
    in regular mode; otherwise, compute some precomputations and
    return pointer to that (which'll switch the main renderframe fct
    to render data parallel) */
  float RaycastVolumeRenderer::renderFrame(FrameBuffer *fb,
                                           const uint32 channelFlags)
  {
    int workerRank = ospray::core::getWorkerRank();

    using DDBV = DataDistributedBlockedVolume;
    std::vector<const DDBV*> ddVolumeVec;
    for (int volumeID = 0; volumeID < model->volume.size(); volumeID++) {
      const DDBV* ddv = dynamic_cast<const DDBV*>(model->volume[volumeID].ptr);
      if (!ddv) continue;
      ddVolumeVec.push_back(ddv);
    }

    if (ddVolumeVec.empty()) {
      static bool printed = false;
      if (!printed) {
        cout << "no data parallel volumes, rendering in traditional"
             << " raycast_volume_render mode" << endl;
        printed = true;
      }

      return Renderer::renderFrame(fb,channelFlags);
    }

    // =======================================================
    // OK, we _need_ data-parallel rendering ....
    static bool printed = false;
    if (!printed) {
      std::cout << "#dvr: at least one dp volume"
                   " -> needs data-parallel rendering ..." << std::endl;
      printed = true;
    }

    // check if we're even in mpi parallel mode (can't do
    // data-parallel otherwise)
    if (!ospray::core::isMpiParallel()) {
      throw std::runtime_error("#dvr: need data-parallel rendering, "
                               "but not running in mpi mode!?");
    }

    // switch (distributed) frame buffer into compositing mode
    DistributedFrameBuffer *dfb = dynamic_cast<DistributedFrameBuffer *>(fb);
    if (!dfb) {
      throw std::runtime_error("OSPRay data parallel rendering error. "
                               "this is a data-parallel scene, but we're "
                               "not using the distributed frame buffer!?");
    }

    dfb->setFrameMode(DistributedFrameBuffer::ALPHA_BLEND);

    // note: we can NEVER be the master, since the master doesn't even
    // have an instance of this renderer class -
    assert(workerRank >= 0);

    Renderer::beginFrame(fb);

    dfb->startNewFrame(errorThreshold);

    if (ddVolumeVec.size() > 1) {
      /* note: our assumption below is that all blocks together are
         contiguous, and fill a convex region (ie, any point on a
         given ray is either entirely before any block, entirely
         behind any block, or inside one of the blocks) - if we have
         multiple data distributed volumes that is no longer the case,
         so we're not currently supporting this ... */
      throw std::runtime_error("currently supporting only ONE data parallel "
                               "volume in scene");
    }

    // create the render task
    DPRenderTask renderTask;
    renderTask.fb = fb;
    renderTask.renderer = this;
    renderTask.numTiles_x = divRoundUp(dfb->size.x, TILE_SIZE);
    renderTask.numTiles_y = divRoundUp(dfb->size.y, TILE_SIZE);
    renderTask.channelFlags = channelFlags;
    renderTask.dpv = ddVolumeVec[0];

    size_t NTASKS = renderTask.numTiles_x * renderTask.numTiles_y;
    parallel_for(NTASKS, renderTask);

    dfb->waitUntilFinished();
    Renderer::endFrame(nullptr, channelFlags);
    return fb->endFrame(0.f);
  }

#endif

  void RaycastVolumeRenderer::commit()
  {
    // Create the equivalent ISPC RaycastVolumeRenderer object.
    if (ispcEquivalent == nullptr) {
      ispcEquivalent = ispc::RaycastVolumeRenderer_createInstance();
    }

    // Set the lights if any.
    Data *lightsData = (Data *)getParamData("lights", nullptr);

    lights.clear();

    if (lightsData) {
      for (size_t i=0; i<lightsData->size(); i++)
        lights.push_back(((Light **)lightsData->data)[i]->getIE());
    }

    ispc::RaycastVolumeRenderer_setLights(ispcEquivalent,
                                          lights.empty() ? nullptr : &lights[0],
                                          lights.size());

    // Initialize state in the parent class, must be called after the ISPC
    // object is created.
    Renderer::commit();
  }

  // A renderer type for volumes with embedded surfaces.
  OSP_REGISTER_RENDERER(RaycastVolumeRenderer, raycast_volume_renderer);
  OSP_REGISTER_RENDERER(RaycastVolumeRenderer, dvr);

} // ::ospray

<commit_msg>Correctly set tile accumID for volume data tiles as well.<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel 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.                                           //
// ======================================================================== //

// ospray
#include "lights/Light.h"
#include "common/Data.h"
#include "common/Core.h"
#include "common/tasking/parallel_for.h"
#include "render/volume/RaycastVolumeRenderer.h"
#include "RaycastVolumeMaterial.h"

// ispc exports
#include "RaycastVolumeRenderer_ispc.h"
#if EXP_DATA_PARALLEL
# include "mpi/DistributedFrameBuffer.h"
# include "volume/DataDistributedBlockedVolume.h"
# include "render/LoadBalancer.h"
#endif

#define TILE_CACHE_SAFE_MUTEX 0

namespace ospray {

  Material *RaycastVolumeRenderer::createMaterial(const char *type)
  {
    return new RaycastVolumeMaterial;
  }

#if EXP_DATA_PARALLEL

  struct CacheForBlockTiles
  {
    CacheForBlockTiles(size_t numBlocks)
      : numBlocks(numBlocks), blockTile(new Tile *[numBlocks])
    {
      for (int i = 0; i < numBlocks; i++) blockTile[i] = nullptr;
    }

    ~CacheForBlockTiles()
    {
      for (int i = 0; i < numBlocks; i++)
        if (blockTile[i]) delete blockTile[i];

      delete[] blockTile;
    }

    Tile *allocTile()
    {
      float infinity = std::numeric_limits<float>::infinity();
      Tile *tile = new Tile;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->r[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->g[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->b[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->a[i] = 0.f;
      for (int i = 0; i < TILE_SIZE*TILE_SIZE; i++) tile->z[i] = infinity;
      return tile;
    }

    Tile *getTileForBlock(size_t blockID)
    {
#if TILE_CACHE_SAFE_MUTEX
      mutex.lock();
      Tile *tile = blockTile[blockID];
      if (tile == nullptr) {
        blockTile[blockID] = tile = allocTile();
      }
      mutex.unlock();
      return tile;
#else
      Tile *tile = blockTile[blockID];
      if (tile != nullptr) return tile;
      mutex.lock();
      tile = blockTile[blockID];
      if (tile == nullptr) {
        blockTile[blockID] = tile = allocTile();
      }
      mutex.unlock();
      return tile;
#endif
    }

    Mutex mutex;
    size_t numBlocks;
    Tile *volatile *blockTile;
  };

  /*! extern exported function so even ISPC code can access this cache */
  extern "C" Tile *
  CacheForBlockTiles_getTileForBlock(CacheForBlockTiles *cache,
                                     uint32 blockID)
  {
    return cache->getTileForBlock(blockID);
  }

  struct DPRenderTask
  {
    mutable Ref<Renderer>     renderer;
    mutable Ref<FrameBuffer>  fb;
    size_t                    numTiles_x;
    size_t                    numTiles_y;
    uint32                    channelFlags;
    const DataDistributedBlockedVolume *dpv;

    void operator()(int taskIndex) const;
  };

  void DPRenderTask::operator()(int taskIndex) const
  {
    const size_t tileID = taskIndex;
    const size_t tile_y = taskIndex / numTiles_x;
    const size_t tile_x = taskIndex - tile_y*numTiles_x;
    const vec2i tileId(tile_x, tile_y);
    const int32 accumID = fb->accumID(tileId);
    Tile bgTile(tileId, fb->size, accumID);
    Tile fgTile(bgTile);

    size_t numBlocks = dpv->numDDBlocks;
    CacheForBlockTiles blockTileCache(numBlocks);
    bool *blockWasVisible = STACK_BUFFER(bool, numBlocks);

    for (int i = 0; i < numBlocks; i++)
      blockWasVisible[i] = false;

    bool renderForeAndBackground =
        (taskIndex % core::getWorkerCount()) == core::getWorkerRank();

    const int numJobs = (TILE_SIZE*TILE_SIZE)/RENDERTILE_PIXELS_PER_JOB;

    parallel_for(numJobs, [&](int tid){
      ispc::DDDVRRenderer_renderTile(renderer->getIE(),
                                     (ispc::Tile&)fgTile,
                                     (ispc::Tile&)bgTile,
                                     &blockTileCache,
                                     numBlocks,
                                     dpv->ddBlock,
                                     blockWasVisible,
                                     tileID,
                                     ospray::core::getWorkerRank(),
                                     renderForeAndBackground,
                                     tid);
    });

    if (renderForeAndBackground) {
      // this is a tile owned by me - i'm responsible for writing
      // generaition #0, and telling the fb how many more tiles will
      // be coming in generation #1

      size_t totalBlocksInTile = 0;
      for (int blockID = 0; blockID < numBlocks; blockID++) {
        if (blockWasVisible[blockID])
          totalBlocksInTile++;
      }

      size_t nextGenTiles
          = 1 /* expect one additional tile for background tile. */
          + totalBlocksInTile /* plus how many blocks map to this
                                     tile, IN TOTAL (ie, INCLUDING blocks
                                     on other nodes)*/;
      // printf("rank %i total tiles in tile %i is %i\n",
      //        core::getWorkerRank(),taskIndex,nextGenTiles);

      // set background tile
      bgTile.generation = 0;
      bgTile.children   = nextGenTiles;
      fb->setTile(bgTile);

      // set foreground tile
      fgTile.generation = 1;
      fgTile.children   = 0; //nextGenTiles-1;
      fb->setTile(fgTile);
      // all other tiles for gen #1 will be set below, no matter whether
      // it's mine or not
    }

    // now, send all block cache tiles that were generated on this
    // node back to master, too. for this, it doesn't matter if this
    // is our tile or not; it's the job of the owner of this tile to
    // tell the DFB how many tiles will arrive for the final thile
    // _across_all_clients_, but we only have to send ours (assuming
    // that all clients together send exactly as many as the owner
    // told the DFB to expect)
    for (int blockID = 0; blockID < numBlocks; blockID++) {
      Tile *tile = blockTileCache.blockTile[blockID];
      if (tile == nullptr)
        continue;

      tile->region = bgTile.region;
      tile->fbSize = bgTile.fbSize;
      tile->rcp_fbSize = bgTile.rcp_fbSize;
      tile->accumID = accumID;
      tile->generation = 1;
      tile->children   = 0; //nextGenTile-1;

      fb->setTile(*tile);
    }
  }

  /*! try if we are running in data-parallel mode, and if
    data-parallel is even required. if not (eg, if there's no
    data-parallel volumes in the scene) return nullptr and render only
    in regular mode; otherwise, compute some precomputations and
    return pointer to that (which'll switch the main renderframe fct
    to render data parallel) */
  float RaycastVolumeRenderer::renderFrame(FrameBuffer *fb,
                                           const uint32 channelFlags)
  {
    int workerRank = ospray::core::getWorkerRank();

    using DDBV = DataDistributedBlockedVolume;
    std::vector<const DDBV*> ddVolumeVec;
    for (int volumeID = 0; volumeID < model->volume.size(); volumeID++) {
      const DDBV* ddv = dynamic_cast<const DDBV*>(model->volume[volumeID].ptr);
      if (!ddv) continue;
      ddVolumeVec.push_back(ddv);
    }

    if (ddVolumeVec.empty()) {
      static bool printed = false;
      if (!printed) {
        cout << "no data parallel volumes, rendering in traditional"
             << " raycast_volume_render mode" << endl;
        printed = true;
      }

      return Renderer::renderFrame(fb,channelFlags);
    }

    // =======================================================
    // OK, we _need_ data-parallel rendering ....
    static bool printed = false;
    if (!printed) {
      std::cout << "#dvr: at least one dp volume"
                   " -> needs data-parallel rendering ..." << std::endl;
      printed = true;
    }

    // check if we're even in mpi parallel mode (can't do
    // data-parallel otherwise)
    if (!ospray::core::isMpiParallel()) {
      throw std::runtime_error("#dvr: need data-parallel rendering, "
                               "but not running in mpi mode!?");
    }

    // switch (distributed) frame buffer into compositing mode
    DistributedFrameBuffer *dfb = dynamic_cast<DistributedFrameBuffer *>(fb);
    if (!dfb) {
      throw std::runtime_error("OSPRay data parallel rendering error. "
                               "this is a data-parallel scene, but we're "
                               "not using the distributed frame buffer!?");
    }

    dfb->setFrameMode(DistributedFrameBuffer::ALPHA_BLEND);

    // note: we can NEVER be the master, since the master doesn't even
    // have an instance of this renderer class -
    assert(workerRank >= 0);

    Renderer::beginFrame(fb);

    dfb->startNewFrame(errorThreshold);

    if (ddVolumeVec.size() > 1) {
      /* note: our assumption below is that all blocks together are
         contiguous, and fill a convex region (ie, any point on a
         given ray is either entirely before any block, entirely
         behind any block, or inside one of the blocks) - if we have
         multiple data distributed volumes that is no longer the case,
         so we're not currently supporting this ... */
      throw std::runtime_error("currently supporting only ONE data parallel "
                               "volume in scene");
    }

    // create the render task
    DPRenderTask renderTask;
    renderTask.fb = fb;
    renderTask.renderer = this;
    renderTask.numTiles_x = divRoundUp(dfb->size.x, TILE_SIZE);
    renderTask.numTiles_y = divRoundUp(dfb->size.y, TILE_SIZE);
    renderTask.channelFlags = channelFlags;
    renderTask.dpv = ddVolumeVec[0];

    size_t NTASKS = renderTask.numTiles_x * renderTask.numTiles_y;
    parallel_for(NTASKS, renderTask);

    dfb->waitUntilFinished();
    Renderer::endFrame(nullptr, channelFlags);
    return fb->endFrame(0.f);
  }

#endif

  void RaycastVolumeRenderer::commit()
  {
    // Create the equivalent ISPC RaycastVolumeRenderer object.
    if (ispcEquivalent == nullptr) {
      ispcEquivalent = ispc::RaycastVolumeRenderer_createInstance();
    }

    // Set the lights if any.
    Data *lightsData = (Data *)getParamData("lights", nullptr);

    lights.clear();

    if (lightsData) {
      for (size_t i=0; i<lightsData->size(); i++)
        lights.push_back(((Light **)lightsData->data)[i]->getIE());
    }

    ispc::RaycastVolumeRenderer_setLights(ispcEquivalent,
                                          lights.empty() ? nullptr : &lights[0],
                                          lights.size());

    // Initialize state in the parent class, must be called after the ISPC
    // object is created.
    Renderer::commit();
  }

  // A renderer type for volumes with embedded surfaces.
  OSP_REGISTER_RENDERER(RaycastVolumeRenderer, raycast_volume_renderer);
  OSP_REGISTER_RENDERER(RaycastVolumeRenderer, dvr);

} // ::ospray

<|endoftext|>


<commit_before>#include "monitor-table-model.h"
#include <QIcon>
#include <QStringList>
#include <QtMath>
#include <QVariant>
#include <utility>
#include "monitoring-center.h"
#include "models/monitor.h"
#include "models/monitor-manager.h"
#include "models/site.h"

MonitorTableModel::MonitorTableModel(MonitorManager *monitorManager, QObject *parent)
	: QAbstractTableModel(parent), m_monitorManager(monitorManager)
{
	connect(m_monitorManager, &MonitorManager::inserted, this, &MonitorTableModel::inserted);
	connect(m_monitorManager, &MonitorManager::removed, this, &MonitorTableModel::removed);

	connect(&m_refreshTimer, &QTimer::timeout, [=]() {
		emit dataChanged(index(0, 6), index(rowCount() - 1, 7));
	});
	m_refreshTimer.start(60 * 1000);
}

int MonitorTableModel::rowCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);
	return m_monitorManager->monitors().count();
}

int MonitorTableModel::columnCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);
	return 11;
}

QVariant MonitorTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (role == Qt::DisplayRole) {
		if (orientation == Qt::Horizontal) {
			switch (section)
			{
				case 0: return QString("");
				case 1: return QString("Search");
				case 2: return QString("Source");
				case 3: return QString("Interval");
				case 4: return QString("Action");
				case 5: return QString("Post-filters");
				case 6: return QString("Last check");
				case 7: return QString("Next check");
				case 8: return QString("Last state");
				case 9: return QString("Last state count");
				case 10: return QString("Last state since");
			}
		} else {
			return QString::number(section + 1);
		}
	}
	return {};
}

QString timeToString(int secs)
{
	if (secs >= 0 && secs < 60) {
		return QString("%1 s").arg(secs);
	}

	const int interval = qFloor(secs / 60.0);
	const int days = interval / 1440;
	const int mins = interval % 1440;

	const QString timeFormat = mins >= 60 ? (mins % 60 != 0 ? QObject::tr("h 'h' m 'm'") : QObject::tr("h 'h'")) : QObject::tr("m 'm'");
	QString sDate = days > 0 ? QString("%1 d ").arg(days) : "";
	QString sTime = mins > 0 ? QTime(0, 0, 0).addSecs(mins * 60).toString(timeFormat) : "";

	return sDate + sTime;
}

QVariant MonitorTableModel::data(const QModelIndex &index, int role) const
{
	const int row = index.row();
	const Monitor &monitor = m_monitorManager->monitors()[row];

	// Icon in the first column
	if (role == Qt::DecorationRole && index.column() == 0) {
		static const QMap<MonitoringCenter::MonitoringStatus, QIcon> s_iconMap
		{
			{ MonitoringCenter::Waiting, QIcon(":/images/status/pending.png") },
			{ MonitoringCenter::Checking, QIcon(":/images/status/downloading.png") },
			{ MonitoringCenter::Performing, QIcon(":/images/status/ok.png") },
		};
		auto status = m_statuses.contains(row) ? m_statuses[row] : MonitoringCenter::Waiting;
		if (!s_iconMap.contains(status)) {
			return {};
		}
		return s_iconMap[status];
	}

	if (role != Qt::DisplayRole) {
		return {};
	}

	switch (index.column())
	{
		case 1:
			return monitor.query().toString();

		case 2:
		{
			QStringList sites;
			for (auto site : monitor.sites()) {
				sites.append(site->url());
			}
			return sites.join(", ");
		}

		case 3:
			return timeToString(monitor.interval());

		case 4:
		{
			QStringList actions;
			if (monitor.notify()) {
				actions.append("Notify");
			}
			if (monitor.download()) {
				actions.append("Download");
			}
			return actions.join(", ");
		}

		case 5:
			return monitor.postFilters().join(' ');

		case 6:
			return monitor.lastCheck();

		case 7:
			return timeToString(monitor.secsToNextCheck());

		case 8:
			return monitor.lastState();

		case 9:
			if (monitor.lastState().isEmpty()) {
				return {};
			}
			return tr("%n time(s)", "", monitor.lastStateCount());

		case 10:
			if (monitor.lastState().isEmpty()) {
				return {};
			}
			return monitor.lastStateSince();
	}

	return {};
}

void MonitorTableModel::inserted(int position)
{
	if (!m_freeze) {
		beginInsertRows(QModelIndex(), position, position);
		endInsertRows();
	}
}

bool MonitorTableModel::insertRows(int position, int rows, const QModelIndex &parent)
{
	Q_UNUSED(parent);

	m_freeze = true;
	beginInsertRows(QModelIndex(), position, position + rows - 1);

	for (int row = 0; row < rows; ++row) {
		m_monitorManager->add(Monitor(QList<Site*>(), 24 * 60 * 60, QDateTime::currentDateTime(), false, QString(), QString()), position);
	}

	endInsertRows();
	m_freeze = false;

	return true;
}

void MonitorTableModel::removed(int position)
{
	if (!m_freeze) {
		beginRemoveRows(QModelIndex(), position, position);
		endRemoveRows();
	}
}

bool MonitorTableModel::removeRows(int position, int rows, const QModelIndex &parent)
{
	Q_UNUSED(parent);

	m_freeze = true;
	beginRemoveRows(QModelIndex(), position, position + rows - 1);

	for (int row = 0; row < rows; ++row) {
		m_monitorManager->remove(m_monitorManager->monitors()[position]);
	}

	endRemoveRows();
	m_freeze = false;

	return true;
}

bool MonitorTableModel::setStatus(const Monitor &monitor, MonitoringCenter::MonitoringStatus status)
{
	int position = m_monitorManager->monitors().indexOf(monitor);
	if (position < 0) {
		return false;
	}

	m_statuses[position] = status;

	auto index = this->index(position, 0);
	emit dataChanged(index, index);

	return true;
}
<commit_msg>Add icons for last state in monitors tab (fix #2478)<commit_after>#include "monitor-table-model.h"
#include <QIcon>
#include <QStringList>
#include <QtMath>
#include <QVariant>
#include <utility>
#include "monitoring-center.h"
#include "models/monitor.h"
#include "models/monitor-manager.h"
#include "models/site.h"

MonitorTableModel::MonitorTableModel(MonitorManager *monitorManager, QObject *parent)
	: QAbstractTableModel(parent), m_monitorManager(monitorManager)
{
	connect(m_monitorManager, &MonitorManager::inserted, this, &MonitorTableModel::inserted);
	connect(m_monitorManager, &MonitorManager::removed, this, &MonitorTableModel::removed);

	connect(&m_refreshTimer, &QTimer::timeout, [=]() {
		emit dataChanged(index(0, 6), index(rowCount() - 1, 7));
	});
	m_refreshTimer.start(60 * 1000);
}

int MonitorTableModel::rowCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);
	return m_monitorManager->monitors().count();
}

int MonitorTableModel::columnCount(const QModelIndex &parent) const
{
	Q_UNUSED(parent);
	return 11;
}

QVariant MonitorTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (role == Qt::DisplayRole) {
		if (orientation == Qt::Horizontal) {
			switch (section)
			{
				case 0: return QString("");
				case 1: return QString("Search");
				case 2: return QString("Source");
				case 3: return QString("Interval");
				case 4: return QString("Action");
				case 5: return QString("Post-filters");
				case 6: return QString("Last check");
				case 7: return QString("Next check");
				case 8: return QString("Last state");
				case 9: return QString("Last state count");
				case 10: return QString("Last state since");
			}
		} else {
			return QString::number(section + 1);
		}
	}
	return {};
}

QString timeToString(int secs)
{
	if (secs >= 0 && secs < 60) {
		return QString("%1 s").arg(secs);
	}

	const int interval = qFloor(secs / 60.0);
	const int days = interval / 1440;
	const int mins = interval % 1440;

	const QString timeFormat = mins >= 60 ? (mins % 60 != 0 ? QObject::tr("h 'h' m 'm'") : QObject::tr("h 'h'")) : QObject::tr("m 'm'");
	QString sDate = days > 0 ? QString("%1 d ").arg(days) : "";
	QString sTime = mins > 0 ? QTime(0, 0, 0).addSecs(mins * 60).toString(timeFormat) : "";

	return sDate + sTime;
}

QVariant MonitorTableModel::data(const QModelIndex &index, int role) const
{
	const int row = index.row();
	const Monitor &monitor = m_monitorManager->monitors()[row];

	// Icon in the first column
	if (role == Qt::DecorationRole) {
		switch (index.column())
		{
			case 0: {
				static const QMap<MonitoringCenter::MonitoringStatus, QIcon> s_statusIconMap
				{
					{MonitoringCenter::Waiting, QIcon(":/images/status/pending.png")},
					{MonitoringCenter::Checking, QIcon(":/images/status/downloading.png")},
					{MonitoringCenter::Performing, QIcon(":/images/status/ok.png")},
				};
				const auto status = m_statuses.contains(row) ? m_statuses[row] : MonitoringCenter::Waiting;
				if (!s_statusIconMap.contains(status)) {
					return {};
				}
				return s_statusIconMap[status];
			}

			case 8: {
				static const QMap<QString, QIcon> s_lastStateIconMap
				{
					{"empty", QIcon(":/images/status/error.png")},
					{"finished", QIcon(":/images/status/ignored.png")},
					{"ok", QIcon(":/images/status/ok.png")},
					{"mixed", QIcon(":/images/status/unknown.png")},
				};
				const QString lastState = monitor.lastState();
				if (!s_lastStateIconMap.contains(lastState)) {
					return {};
				}
				return s_lastStateIconMap[lastState];
			}
		}
		return {};
	}

	if (role != Qt::DisplayRole) {
		return {};
	}

	switch (index.column())
	{
		case 1:
			return monitor.query().toString();

		case 2:
		{
			QStringList sites;
			for (auto site : monitor.sites()) {
				sites.append(site->url());
			}
			return sites.join(", ");
		}

		case 3:
			return timeToString(monitor.interval());

		case 4:
		{
			QStringList actions;
			if (monitor.notify()) {
				actions.append("Notify");
			}
			if (monitor.download()) {
				actions.append("Download");
			}
			return actions.join(", ");
		}

		case 5:
			return monitor.postFilters().join(' ');

		case 6:
			return monitor.lastCheck();

		case 7:
			return timeToString(monitor.secsToNextCheck());

		case 8:
			return monitor.lastState();

		case 9:
			if (monitor.lastState().isEmpty()) {
				return {};
			}
			return tr("%n time(s)", "", monitor.lastStateCount());

		case 10:
			if (monitor.lastState().isEmpty()) {
				return {};
			}
			return monitor.lastStateSince();
	}

	return {};
}

void MonitorTableModel::inserted(int position)
{
	if (!m_freeze) {
		beginInsertRows(QModelIndex(), position, position);
		endInsertRows();
	}
}

bool MonitorTableModel::insertRows(int position, int rows, const QModelIndex &parent)
{
	Q_UNUSED(parent);

	m_freeze = true;
	beginInsertRows(QModelIndex(), position, position + rows - 1);

	for (int row = 0; row < rows; ++row) {
		m_monitorManager->add(Monitor(QList<Site*>(), 24 * 60 * 60, QDateTime::currentDateTime(), false, QString(), QString()), position);
	}

	endInsertRows();
	m_freeze = false;

	return true;
}

void MonitorTableModel::removed(int position)
{
	if (!m_freeze) {
		beginRemoveRows(QModelIndex(), position, position);
		endRemoveRows();
	}
}

bool MonitorTableModel::removeRows(int position, int rows, const QModelIndex &parent)
{
	Q_UNUSED(parent);

	m_freeze = true;
	beginRemoveRows(QModelIndex(), position, position + rows - 1);

	for (int row = 0; row < rows; ++row) {
		m_monitorManager->remove(m_monitorManager->monitors()[position]);
	}

	endRemoveRows();
	m_freeze = false;

	return true;
}

bool MonitorTableModel::setStatus(const Monitor &monitor, MonitoringCenter::MonitoringStatus status)
{
	int position = m_monitorManager->monitors().indexOf(monitor);
	if (position < 0) {
		return false;
	}

	m_statuses[position] = status;

	auto index = this->index(position, 0);
	emit dataChanged(index, index);

	return true;
}
<|endoftext|>


<commit_before>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/** @file   AliHLTFileWriter.cxx
    @author Matthias Richter
    @date
    @brief  HLT file writer component implementation. */

#if __GNUC__>= 3
using namespace std;
#endif

#include "AliHLTFileWriter.h"
#include <TObjArray.h>
#include <TObjString.h>
//#include <TMath.h>
//#include <TFile.h>

/** the global object for component registration */
AliHLTFileWriter gAliHLTFileWriter;

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTFileWriter)

AliHLTFileWriter::AliHLTFileWriter()
  :
  AliHLTDataSink(),
  fBaseName(""),
  fExtension(""),
  fDirectory(""),
  fCurrentFileName(""),
  fMode(0)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTFileWriter::AliHLTFileWriter(const AliHLTFileWriter&)
  :
  AliHLTDataSink(),
  fBaseName(""),
  fExtension(""),
  fDirectory(""),
  fCurrentFileName(""),
  fMode(0)
{
  // see header file for class documentation
  HLTFatal("copy constructor untested");
}

AliHLTFileWriter& AliHLTFileWriter::operator=(const AliHLTFileWriter&)
{
  // see header file for class documentation
  HLTFatal("assignment operator untested");
  return *this;
}

AliHLTFileWriter::~AliHLTFileWriter()
{
  // see header file for class documentation

  // file list and file name list are owner of their objects and
  // delete all the objects
}

const char* AliHLTFileWriter::GetComponentID()
{
  // see header file for class documentation
  return "FileWriter";
}

void AliHLTFileWriter::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
{
  // see header file for class documentation
  list.clear();
  list.push_back(kAliHLTAnyDataType);
}

AliHLTComponent* AliHLTFileWriter::Spawn()
{
  // see header file for class documentation
  return new AliHLTFileWriter;
}

int AliHLTFileWriter::DoInit( int argc, const char** argv )
{
  // see header file for class documentation
  int iResult=0;
  TString argument="";
  int bMissingParam=0;
  for (int i=0; i<argc && iResult>=0; i++) {
    argument=argv[i];
    if (argument.IsNull()) continue;

    // -basename
    if (argument.CompareTo("-datafile")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      fBaseName=argv[i];
      TObjArray* pTokens=fBaseName.Tokenize(".");
      if (pTokens) {
	int iEntries=pTokens->GetEntries();
	if (iEntries>1) {
	  int i=0;
	  fBaseName=((TObjString*)pTokens->At(i++))->GetString();
	  while (i<iEntries-1) {
	    fBaseName+="." + ((TObjString*)pTokens->At(i++))->GetString();
	  }
	  fExtension=((TObjString*)pTokens->At(i))->GetString();
	}
	delete pTokens;
      }

      // -directory
    } else if (argument.CompareTo("-directory")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      fDirectory=argv[i];

      // -enumeration
    } else if (argument.CompareTo("-enumerate")==0) {
      SetMode(kEnumerate);

      // -concatenate-blocks
    } else if (argument.CompareTo("-concatenate-blocks")==0) {
      SetMode(kConcatenateBlocks);

      // -concatenate-events
    } else if (argument.CompareTo("-concatenate-events")==0) {
      SetMode(kConcatenateEvents);

    } else {
      if ((iResult=ScanArgument(argc-i, &argv[i]))==-EINVAL) {
	HLTError("unknown argument %s", argument.Data());
	break;
      } else if (iResult==-EPROTO) {
	bMissingParam=1;
	break;
      } else if (iResult>=0) {
	i+=iResult;
	iResult=0;
      }
    }
  }
  if (bMissingParam) {
    HLTError("missing parameter for argument %s", argument.Data());
    iResult=-EINVAL;
  }
  if (iResult>=0) {
    iResult=InitWriter();
  }

  return iResult;
}

int AliHLTFileWriter::InitWriter()
{
  // see header file for class documentation

  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return 0; // note: this doesn't mean 'error'
}

int AliHLTFileWriter::ScanArgument(int argc, const char** argv)
{
  // see header file for class documentation

  // there are no other arguments than the standard ones
  if (argc==0 && argv==NULL) {
    // this is just to get rid of the warning "unused parameter"
  }
  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return -EINVAL;
}

int AliHLTFileWriter::DoDeinit()
{
  // see header file for class documentation
  int iResult=CloseWriter();
  ClearMode(kEnumerate);
  return iResult;
}

int AliHLTFileWriter::CloseWriter()
{
  // see header file for class documentation

  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return 0; // note: this doesn't mean 'error'
}

int AliHLTFileWriter::DumpEvent( const AliHLTComponentEventData& evtData,
			 const AliHLTComponentBlockData* blocks,
			 AliHLTComponentTriggerData& trigData )
{
  // see header file for class documentation
  int iResult=0;
  if (CheckMode(kConcatenateEvents)==0) {
    // reset the current file name in order to open a new file
    // for the first block. If events are concatenated, the current
    // file name stays in order to be opended in append mode.
    fCurrentFileName="";
  }
  for (int n=0; n<(int)evtData.fBlockCnt; n++ ) {
    //HLTDebug("block %d out of %d", n, evtData.fBlockCnt);
    TString filename;
    HLTDebug("dataspec 0x%x", blocks[n].fSpecification);
    iResult=BuildFileName(evtData.fEventID, n, blocks[n].fDataType, filename);
    ios::openmode filemode=(ios::openmode)0;
    if (fCurrentFileName.CompareTo(filename)==0) {
      // append to the file
      filemode=ios::app;
    } else {
      // store the file for the next block
      fCurrentFileName=filename;
    }
    if (iResult>=0) {
      ofstream dump(filename.Data(), filemode);
      if (dump.good()) {
	dump.write((const char*)blocks[n].fPtr, blocks[n].fSize);
	HLTDebug("wrote %d byte(s) to file %s", blocks[n].fSize, filename.Data());
      } else {
	HLTError("can not open file %s for writing", filename.Data());
	iResult=-EBADF;
      }
      dump.close();
    }
  }
  if (trigData.fStructSize==0) {
    // this is just to get rid of the warning "unused parameter"
  }
  return iResult;
}

int AliHLTFileWriter::BuildFileName(const AliHLTEventID_t eventID, const int blockID, const AliHLTComponentDataType& dataType, TString& filename)
{
  // see header file for class documentation
  int iResult=0;
  //HLTDebug("build file name for event %d block %d", eventID, blockID);
  filename="";
  if (!fDirectory.IsNull()) {
    filename+=fDirectory;
    if (!fDirectory.EndsWith("/"))
      filename+="/";
  }
  if (!fBaseName.IsNull())
    filename+=fBaseName;
  else
    filename+="event";
  if (!CheckMode(kConcatenateEvents)) {
    if (!CheckMode(kEnumerate)) {
      if (eventID!=kAliHLTVoidEventID) {
	filename+=Form("_0x%08x", eventID);
      }
    } else {
      filename+=Form("_%d", GetEventCount());
    }
  }
  if (blockID>=0 && !CheckMode(kConcatenateBlocks)) {
    filename+=Form("_0x%x", blockID);
    if (dataType!=kAliHLTVoidDataType) {
      filename+="_";
      filename+=AliHLTComponent::DataType2Text(dataType).data();
    }
  }
  if (!fExtension.IsNull())
    filename+="." + fExtension;
  filename.ReplaceAll(" ", "");
  return iResult;
}

int AliHLTFileWriter::SetMode(Short_t mode)
{
  // see header file for class documentation
  fMode|=mode;
  //HLTDebug("mode set to 0x%x", fMode);
  return fMode;
}

int AliHLTFileWriter::ClearMode(Short_t mode)
{
  // see header file for class documentation
  fMode&=~mode;
  //HLTDebug("mode set to 0x%x", fMode);
  return fMode;
}

int AliHLTFileWriter::CheckMode(Short_t mode) const
{
  // see header file for class documentation

  //HLTDebug("check mode 0x%x for flag 0x%x: %d", fMode, mode, (fMode&mode)!=0);
  return (fMode&mode)!=0;
}
<commit_msg>bugfix: consider both pointer and offset of block descriptor<commit_after>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/** @file   AliHLTFileWriter.cxx
    @author Matthias Richter
    @date
    @brief  HLT file writer component implementation. */

#if __GNUC__>= 3
using namespace std;
#endif

#include "AliHLTFileWriter.h"
#include <TObjArray.h>
#include <TObjString.h>
//#include <TMath.h>
//#include <TFile.h>

/** the global object for component registration */
AliHLTFileWriter gAliHLTFileWriter;

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTFileWriter)

AliHLTFileWriter::AliHLTFileWriter()
  :
  AliHLTDataSink(),
  fBaseName(""),
  fExtension(""),
  fDirectory(""),
  fCurrentFileName(""),
  fMode(0)
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTFileWriter::AliHLTFileWriter(const AliHLTFileWriter&)
  :
  AliHLTDataSink(),
  fBaseName(""),
  fExtension(""),
  fDirectory(""),
  fCurrentFileName(""),
  fMode(0)
{
  // see header file for class documentation
  HLTFatal("copy constructor untested");
}

AliHLTFileWriter& AliHLTFileWriter::operator=(const AliHLTFileWriter&)
{
  // see header file for class documentation
  HLTFatal("assignment operator untested");
  return *this;
}

AliHLTFileWriter::~AliHLTFileWriter()
{
  // see header file for class documentation

  // file list and file name list are owner of their objects and
  // delete all the objects
}

const char* AliHLTFileWriter::GetComponentID()
{
  // see header file for class documentation
  return "FileWriter";
}

void AliHLTFileWriter::GetInputDataTypes( vector<AliHLTComponentDataType>& list)
{
  // see header file for class documentation
  list.clear();
  list.push_back(kAliHLTAnyDataType);
}

AliHLTComponent* AliHLTFileWriter::Spawn()
{
  // see header file for class documentation
  return new AliHLTFileWriter;
}

int AliHLTFileWriter::DoInit( int argc, const char** argv )
{
  // see header file for class documentation
  int iResult=0;
  TString argument="";
  int bMissingParam=0;
  for (int i=0; i<argc && iResult>=0; i++) {
    argument=argv[i];
    if (argument.IsNull()) continue;

    // -basename
    if (argument.CompareTo("-datafile")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      fBaseName=argv[i];
      TObjArray* pTokens=fBaseName.Tokenize(".");
      if (pTokens) {
	int iEntries=pTokens->GetEntries();
	if (iEntries>1) {
	  int i=0;
	  fBaseName=((TObjString*)pTokens->At(i++))->GetString();
	  while (i<iEntries-1) {
	    fBaseName+="." + ((TObjString*)pTokens->At(i++))->GetString();
	  }
	  fExtension=((TObjString*)pTokens->At(i))->GetString();
	}
	delete pTokens;
      }

      // -directory
    } else if (argument.CompareTo("-directory")==0) {
      if ((bMissingParam=(++i>=argc))) break;
      fDirectory=argv[i];

      // -enumeration
    } else if (argument.CompareTo("-enumerate")==0) {
      SetMode(kEnumerate);

      // -concatenate-blocks
    } else if (argument.CompareTo("-concatenate-blocks")==0) {
      SetMode(kConcatenateBlocks);

      // -concatenate-events
    } else if (argument.CompareTo("-concatenate-events")==0) {
      SetMode(kConcatenateEvents);

    } else {
      if ((iResult=ScanArgument(argc-i, &argv[i]))==-EINVAL) {
	HLTError("unknown argument %s", argument.Data());
	break;
      } else if (iResult==-EPROTO) {
	bMissingParam=1;
	break;
      } else if (iResult>=0) {
	i+=iResult;
	iResult=0;
      }
    }
  }
  if (bMissingParam) {
    HLTError("missing parameter for argument %s", argument.Data());
    iResult=-EINVAL;
  }
  if (iResult>=0) {
    iResult=InitWriter();
  }

  return iResult;
}

int AliHLTFileWriter::InitWriter()
{
  // see header file for class documentation

  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return 0; // note: this doesn't mean 'error'
}

int AliHLTFileWriter::ScanArgument(int argc, const char** argv)
{
  // see header file for class documentation

  // there are no other arguments than the standard ones
  if (argc==0 && argv==NULL) {
    // this is just to get rid of the warning "unused parameter"
  }
  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return -EINVAL;
}

int AliHLTFileWriter::DoDeinit()
{
  // see header file for class documentation
  int iResult=CloseWriter();
  ClearMode(kEnumerate);
  return iResult;
}

int AliHLTFileWriter::CloseWriter()
{
  // see header file for class documentation

  // fCurrentFileName is used in dump event, just touched her to avoid
  // coding convention violation RC11. The function can not be declared
  // const since it is just the default implementation, overloaded
  // virtual function might not be const
  fCurrentFileName="";
  return 0; // note: this doesn't mean 'error'
}

int AliHLTFileWriter::DumpEvent( const AliHLTComponentEventData& evtData,
			 const AliHLTComponentBlockData* blocks,
			 AliHLTComponentTriggerData& trigData )
{
  // see header file for class documentation
  int iResult=0;
  if (CheckMode(kConcatenateEvents)==0) {
    // reset the current file name in order to open a new file
    // for the first block. If events are concatenated, the current
    // file name stays in order to be opended in append mode.
    fCurrentFileName="";
  }
  for (int n=0; n<(int)evtData.fBlockCnt; n++ ) {
    //HLTDebug("block %d out of %d", n, evtData.fBlockCnt);
    TString filename;
    HLTDebug("dataspec 0x%x", blocks[n].fSpecification);
    iResult=BuildFileName(evtData.fEventID, n, blocks[n].fDataType, filename);
    ios::openmode filemode=(ios::openmode)0;
    if (fCurrentFileName.CompareTo(filename)==0) {
      // append to the file
      filemode=ios::app;
    } else {
      // store the file for the next block
      fCurrentFileName=filename;
    }
    if (iResult>=0) {
      ofstream dump(filename.Data(), filemode);
      if (dump.good()) {
	dump.write((static_cast<const char*>(blocks[n].fPtr))+blocks[n].fOffset, blocks[n].fSize);
	HLTDebug("wrote %d byte(s) to file %s", blocks[n].fSize, filename.Data());
      } else {
	HLTError("can not open file %s for writing", filename.Data());
	iResult=-EBADF;
      }
      dump.close();
    }
  }
  if (trigData.fStructSize==0) {
    // this is just to get rid of the warning "unused parameter"
  }
  return iResult;
}

int AliHLTFileWriter::BuildFileName(const AliHLTEventID_t eventID, const int blockID, const AliHLTComponentDataType& dataType, TString& filename)
{
  // see header file for class documentation
  int iResult=0;
  //HLTDebug("build file name for event %d block %d", eventID, blockID);
  filename="";
  if (!fDirectory.IsNull()) {
    filename+=fDirectory;
    if (!fDirectory.EndsWith("/"))
      filename+="/";
  }
  if (!fBaseName.IsNull())
    filename+=fBaseName;
  else
    filename+="event";
  if (!CheckMode(kConcatenateEvents)) {
    if (!CheckMode(kEnumerate)) {
      if (eventID!=kAliHLTVoidEventID) {
	filename+=Form("_0x%08x", eventID);
      }
    } else {
      filename+=Form("_%d", GetEventCount());
    }
  }
  if (blockID>=0 && !CheckMode(kConcatenateBlocks)) {
    filename+=Form("_0x%x", blockID);
    if (dataType!=kAliHLTVoidDataType) {
      filename+="_";
      filename+=AliHLTComponent::DataType2Text(dataType).data();
    }
  }
  if (!fExtension.IsNull())
    filename+="." + fExtension;
  filename.ReplaceAll(" ", "");
  return iResult;
}

int AliHLTFileWriter::SetMode(Short_t mode)
{
  // see header file for class documentation
  fMode|=mode;
  //HLTDebug("mode set to 0x%x", fMode);
  return fMode;
}

int AliHLTFileWriter::ClearMode(Short_t mode)
{
  // see header file for class documentation
  fMode&=~mode;
  //HLTDebug("mode set to 0x%x", fMode);
  return fMode;
}

int AliHLTFileWriter::CheckMode(Short_t mode) const
{
  // see header file for class documentation

  //HLTDebug("check mode 0x%x for flag 0x%x: %d", fMode, mode, (fMode&mode)!=0);
  return (fMode&mode)!=0;
}
<|endoftext|>


<commit_before>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

// ----------------------------------------------------------------------
//
// EvalNode.C
//   the implementation of evaluation tree nodes
//
// ----------------------------------------------------------------------

//************************ System Include Files ******************************

#include <iostream>

#ifdef NO_STD_CHEADERS
# include <math.h>
#else
# include <cmath>
using namespace std; // For compatibility with non-std C headers
#endif

//************************* User Include Files *******************************

#include <include/general.h>

#include "EvalNode.h"
#include <lib/support/Nan.h>
#include <lib/support/Trace.h>

//************************ Forward Declarations ******************************

using std::cout;
using std::endl;

//****************************************************************************

// ----------------------------------------------------------------------
// class Const
// ----------------------------------------------------------------------

Const::Const(double c) : val(c) { }

Const::~Const() { }

double Const::eval(const ScopeInfo *si) {
  IFTRACE << "constant=" << val << endl;
  return val;
}

void Const::print() { cout << "(" << val << ")"; }

// ----------------------------------------------------------------------
// class Neg
// ----------------------------------------------------------------------

Neg::Neg(EvalNode* aNode) { node = aNode; }

Neg::~Neg() { delete node; }

double Neg::eval(const ScopeInfo *si) {
  double tmp;
  if (node == NULL || IsNaNorInfinity(tmp = node->eval(si)))
    return NaNVal;
  IFTRACE << "neg=" << -tmp << endl;
  return -tmp;
}

void Neg::print() { cout << "(-"; node->print(); cout << ")"; }

// ----------------------------------------------------------------------
// class Var
// ----------------------------------------------------------------------

Var::Var(String n, int i) : name(n), index(i) { }

Var::~Var() { }

double Var::eval(const ScopeInfo *si) {
  return si->PerfData(index);
}

void Var::print() { cout << name; }

// ----------------------------------------------------------------------
// class Power
// ----------------------------------------------------------------------

Power::Power(EvalNode* b, EvalNode* e) : base(b), exponent(e) { }

Power::~Power() { delete base; delete exponent; }

double Power::eval(const ScopeInfo *si) {
  if (base == NULL || exponent == NULL)
    return NaNVal;
  double b = base->eval(si);
  double e = exponent->eval(si);
  if (IsNaNorInfinity(b) || IsNaNorInfinity(e))
    return NaNVal;
  IFTRACE << "pow=" << pow(b, e) << endl;
  return pow(b, e);
}

void Power::print() {
  cout << "("; base->print(); cout << "**"; exponent->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Divide
// ----------------------------------------------------------------------

Divide::Divide(EvalNode* num, EvalNode* denom)
    : numerator(num), denominator(denom) { }

Divide::~Divide() { delete numerator; delete denominator; }

double Divide::eval(const ScopeInfo *si) {
  if (numerator == NULL || denominator == NULL)
    return NaNVal;
  double n = numerator->eval(si);
  double d = denominator->eval(si);
  if (d == 0.0 || IsNaNorInfinity(d) || IsNaNorInfinity(n))
    return NaNVal;
  IFTRACE << "divident=" << n/d << endl;
  return n / d;
}

void Divide::print() {
  cout << "("; numerator->print(); cout << "/";
  denominator->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Minus
// ----------------------------------------------------------------------

Minus::Minus(EvalNode* m, EvalNode* s) : minuend(m), subtrahend(s) { }

Minus::~Minus() { delete minuend; delete subtrahend; }

double Minus::eval(const ScopeInfo *si) {
  if (minuend == NULL || subtrahend == NULL)
    return NaNVal;
  double m = minuend->eval(si);
  double s = subtrahend->eval(si);
  if (IsNaNorInfinity(m) || IsNaNorInfinity(s))
    return NaNVal;
  IFTRACE << "diff=" << m-s << endl;
  return m - s;
}

void Minus::print() {
  cout << "("; minuend->print(); cout << "-"; subtrahend->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Plus
// ----------------------------------------------------------------------

Plus::Plus(EvalNode** oprnds, int numOprnds) : nodes(oprnds), n(numOprnds) { }

Plus::~Plus() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Plus::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
       result = tmp;
       break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      result += tmp;
    }
  }
  IFTRACE << "sum=" << result << endl;
  return result;
}

void Plus::print() {
  cout << "(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << "+";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Times
// ----------------------------------------------------------------------

Times::Times(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Times::~Times() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Times::eval(const ScopeInfo *si) {
  double product = 1.0;
  for (int i = 0; i < n; i++) {
    double tmp = nodes[i]->eval(si);
    if (IsNaNorInfinity(tmp))
      return NaNVal;
    product *= tmp;
  }
  IFTRACE << "product=" << product << endl;
  return product;
}

void Times::print() {
  cout << "(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << "*";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Min
// ----------------------------------------------------------------------

Min::Min(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Min::~Min() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Min::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      // if i > 0, there is an empty value that we will treat as 0.0
      result = (i == 0) ? tmp : MIN(tmp, 0.0);
      break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) tmp = 0.0;
      result = MIN(result, tmp);
    }
  }
  IFTRACE << "min=" << result << endl;
  return result;
}

void Min::print() {
  cout << "min(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << ",";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Max
// ----------------------------------------------------------------------

Max::Max(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Max::~Max() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Max::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      // if i > 0, there is an empty value that we will treat as 0.0
      result = (i == 0) ? tmp : MAX(tmp, 0.0);
      result = tmp;
      break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) tmp = 0.0;
      result = MAX(result, tmp);
    }
  }
  IFTRACE << "max=" << result << endl;
  return result;
}

void Max::print() {
  cout << "max(";

  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << ",";
  }
  cout << ")";
}
<commit_msg>updated handling for missing data in expression evaluator   - if all operands are missing, the result is missing   - plus, max, min were handled correctly if some operands were present;     changed behavior for minus, power, divide to assume a missing operand     is zero. For divide result will be empty if denominator is missing or     zero. For power result will be empty if the base is negative.   - did not modify behavior for times, because any missing operand is     assumed zero and the result will be zero. Now, the result will be empty     in such a case which is equivalent. The difference is that it will make     the scope not to be included in the final tree if this zero result was     the only displayed metric having a value (in case the tree pruning looks     only at the displayed values).<commit_after>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

// ----------------------------------------------------------------------
//
// EvalNode.C
//   the implementation of evaluation tree nodes
//
// ----------------------------------------------------------------------

//************************ System Include Files ******************************

#include <iostream>

#ifdef NO_STD_CHEADERS
# include <math.h>
#else
# include <cmath>
using namespace std; // For compatibility with non-std C headers
#endif

//************************* User Include Files *******************************

#include <include/general.h>

#include "EvalNode.h"
#include <lib/support/Nan.h>
#include <lib/support/Trace.h>

//************************ Forward Declarations ******************************

using std::cout;
using std::endl;

//****************************************************************************

// ----------------------------------------------------------------------
// class Const
// ----------------------------------------------------------------------

Const::Const(double c) : val(c) { }

Const::~Const() { }

double Const::eval(const ScopeInfo *si) {
  IFTRACE << "constant=" << val << endl;
  return val;
}

void Const::print() { cout << "(" << val << ")"; }

// ----------------------------------------------------------------------
// class Neg
// ----------------------------------------------------------------------

Neg::Neg(EvalNode* aNode) { node = aNode; }

Neg::~Neg() { delete node; }

double Neg::eval(const ScopeInfo *si) {
  double tmp;
  if (node == NULL || IsNaNorInfinity(tmp = node->eval(si)))
    return NaNVal;
  IFTRACE << "neg=" << -tmp << endl;
  return -tmp;
}

void Neg::print() { cout << "(-"; node->print(); cout << ")"; }

// ----------------------------------------------------------------------
// class Var
// ----------------------------------------------------------------------

Var::Var(String n, int i) : name(n), index(i) { }

Var::~Var() { }

double Var::eval(const ScopeInfo *si) {
  return si->PerfData(index);
}

void Var::print() { cout << name; }

// ----------------------------------------------------------------------
// class Power
// ----------------------------------------------------------------------

Power::Power(EvalNode* b, EvalNode* e) : base(b), exponent(e) { }

Power::~Power() { delete base; delete exponent; }

double Power::eval(const ScopeInfo *si) {
  if (base == NULL || exponent == NULL)
    return NaNVal;
  double b = base->eval(si);
  double e = exponent->eval(si);
  if (IsNaNorInfinity(e) && IsNaNorInfinity(b))  // do not create a value if
                                                 // both are missing
    return (NaNVal);
  if (IsNaNorInfinity(e) || e==0)  // exp is missing, assume it is zero
    return (1);
  else
    if (IsNaNorInfinity(b) || b==0)
      return (0);
  // if b < 0, pow works only if e is integer
  // I will simplify. If b<0, return NaNVal;
  if (b < 0)
    return NaNVal;
  IFTRACE << "pow=" << pow(b, e) << endl;
  return pow(b, e);
}

void Power::print() {
  cout << "("; base->print(); cout << "**"; exponent->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Divide
// ----------------------------------------------------------------------

Divide::Divide(EvalNode* num, EvalNode* denom)
    : numerator(num), denominator(denom) { }

Divide::~Divide() { delete numerator; delete denominator; }

double Divide::eval(const ScopeInfo *si) {
  if (numerator == NULL || denominator == NULL)
    return NaNVal;
  double n = numerator->eval(si);
  double d = denominator->eval(si);
  if (IsNaNorInfinity(d) || d == 0.0)
    return NaNVal;
  if (IsNaNorInfinity(n))
    return (0);
  IFTRACE << "divident=" << n/d << endl;
  return n / d;
}

void Divide::print() {
  cout << "("; numerator->print(); cout << "/";
  denominator->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Minus
// ----------------------------------------------------------------------

Minus::Minus(EvalNode* m, EvalNode* s) : minuend(m), subtrahend(s) { }

Minus::~Minus() { delete minuend; delete subtrahend; }

double Minus::eval(const ScopeInfo *si) {
  if (minuend == NULL || subtrahend == NULL)
    return NaNVal;
  double m = minuend->eval(si);
  double s = subtrahend->eval(si);
  if (IsNaNorInfinity(m) && IsNaNorInfinity(s))
    return NaNVal;
  if (IsNaNorInfinity(m))
    m = 0.0;
  if (IsNaNorInfinity(s))
    s = 0.0;
  IFTRACE << "diff=" << m-s << endl;
  return (m - s);
}

void Minus::print() {
  cout << "("; minuend->print(); cout << "-"; subtrahend->print(); cout << ")";
}

// ----------------------------------------------------------------------
// class Plus
// ----------------------------------------------------------------------

Plus::Plus(EvalNode** oprnds, int numOprnds) : nodes(oprnds), n(numOprnds) { }

Plus::~Plus() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Plus::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
       result = tmp;
       break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      result += tmp;
    }
  }
  IFTRACE << "sum=" << result << endl;
  return result;
}

void Plus::print() {
  cout << "(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << "+";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Times
// ----------------------------------------------------------------------

Times::Times(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Times::~Times() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Times::eval(const ScopeInfo *si) {
  double product = 1.0;
  for (int i = 0; i < n; i++) {
    double tmp = nodes[i]->eval(si);
    if (IsNaNorInfinity(tmp))
      return NaNVal;
    product *= tmp;
  }
  IFTRACE << "product=" << product << endl;
  return product;
}

void Times::print() {
  cout << "(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << "*";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Min
// ----------------------------------------------------------------------

Min::Min(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Min::~Min() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Min::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      // if i > 0, there is an empty value that we will treat as 0.0
      result = (i == 0) ? tmp : MIN(tmp, 0.0);
      break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) tmp = 0.0;
      result = MIN(result, tmp);
    }
  }
  IFTRACE << "min=" << result << endl;
  return result;
}

void Min::print() {
  cout << "min(";
  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << ",";
  }
  cout << ")";
}

// ----------------------------------------------------------------------
// class Max
// ----------------------------------------------------------------------

Max::Max(EvalNode** oprnds, int numOprnds) :
  nodes(oprnds), n(numOprnds) { }

Max::~Max() {
  for (int i = 0; i < n; i++)
    delete nodes[i];
  delete[] nodes;
}

double Max::eval(const ScopeInfo *si) {
  double result = NaNVal;
  int i;
  for (i = 0; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) continue;
      // if i > 0, there is an empty value that we will treat as 0.0
      result = (i == 0) ? tmp : MAX(tmp, 0.0);
      result = tmp;
      break;
    }
  }
  for (i++; i < n; i++) {
    if (nodes[i] != NULL) {
      double tmp = nodes[i]->eval(si);
      if (IsNaNorInfinity(tmp)) tmp = 0.0;
      result = MAX(result, tmp);
    }
  }
  IFTRACE << "max=" << result << endl;
  return result;
}

void Max::print() {
  cout << "max(";

  for (int i = 0; i < n; i++) {
      nodes[i]->print();
      if (i < n-1) cout << ",";
  }
  cout << ")";
}
<|endoftext|>


<commit_before>#ifndef IMPL_AX_TYPE_DESCRIPTOR_HPP
#define IMPL_AX_TYPE_DESCRIPTOR_HPP

#include <cstddef>
#include <typeindex>
#include <functional>
#include <unordered_map>
#include <memory>

#include "prelude.hpp"
#include "type.hpp"
#include "reflectable.hpp"
#include "symbol.hpp"

namespace ax
{
    class type_descriptor
    {
    public:

        CONSTRAINT(type_descriptor);

        void inspect_value(const reflectable& source, const field& field, void* target_ptr) const;
        void inject_value(const field& field, const void* source_ptr, reflectable& target) const;

        virtual void inspect_value(const void* source_ptr, void* target_ptr) const = 0;
        virtual void inject_value(const void* source_ptr, void* target_ptr) const = 0;
        virtual void read_value(const symbol& source_symbol, void* target_ptr) const = 0;
        virtual void write_value(const void* source_ptr, symbol& target_symbol) const = 0;

    protected:

        template<typename T, typename D>
        friend std::shared_ptr<D> register_type_descriptor(const std::shared_ptr<D>& type_descriptor);
        friend const std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>>& get_type_descriptor_map();

    private:

        static std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>> type_descriptor_map;
    };

    // The alias for a type descriptor map.
    using type_descriptor_map = std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>>;

    // Get the type descriptor map.
    const type_descriptor_map& get_type_descriptor_map();

    // Get the type descriptor for the given type index.
    std::shared_ptr<type_descriptor> get_type_descriptor(std::type_index type_index);

    // Get a type descriptor for the given template argument.
    template<typename T>
    std::shared_ptr<type_descriptor> get_type_descriptor()
    {
        VAL& type_index = std::type_index(typeid(T));
        return get_type_descriptor(type_index);
    }

    // Register a type descriptor.
    template<typename T, typename D>
    std::shared_ptr<D> register_type_descriptor(const std::shared_ptr<D>& type_descriptor)
    {
        CONSTRAIN(D, type_descriptor);
        VAL& type_index = std::type_index(typeid(T));
        VAR insertion = type_descriptor::type_descriptor_map.emplace(type_index, type_descriptor);
        if (!insertion.second) insertion.first->second = type_descriptor;
        return type_descriptor;
    }

    // Assign a value via void ptrs.
    template<typename T>
    void assign_value(const void* source_ptr, void* target_ptr)
    {
        VAL* source_ptr_t = static_cast<const T*>(source_ptr);
        VAR* target_ptr_t = static_cast<T*>(target_ptr);
        *target_ptr_t = *source_ptr_t;
    }

    // Assign a shared_ptr via void ptrs.
    template<typename T>
    void assign_shared_ptr(const void* source_ptr, void* target_ptr)
    {
        CONSTRAIN_AS_SHARED_PTR(T);
        VAL* source_ptr_ptr = static_cast<const std::shared_ptr<T>*>(source_ptr);
        VAR* target_ptr_ptr = static_cast<std::shared_ptr<T>*>(target_ptr);
        *target_ptr_ptr = *source_ptr_ptr;
    }

    // Assign a unique_ptr via void ptrs.
    template<typename T>
    void assign_unique_ptr(void* source_ptr, void* target_ptr)
    {
        CONSTRAIN_AS_UNIQUE_PTR(T);
        VAR* source_ptr_ptr = static_cast<std::unique_ptr<T>*>(source_ptr);
        VAR* target_ptr_ptr = static_cast<std::unique_ptr<T>*>(target_ptr);
        target_ptr_ptr->reset(source_ptr_ptr->get());
    }

    // Inspect a value of a reflectable value.
    template<typename T>
    void inspect_value(const reflectable& source, const field& field, T& target)
    {
        VAL& type_index = field.get_type_index();
        if (type_index != std::type_index(typeid(T))) throw std::invalid_argument("Field is not of required type.");
        VAL& type_descriptor = get_type_descriptor(type_index);
        VAR* target_ptr = static_cast<void*>(&target);
        type_descriptor->inspect_value(source, field, target_ptr);
    }

    // Inject a value into a reflectable value.
    template<typename T>
    void inject_value(const field& field, const T& source, reflectable& target)
    {
        VAL& type_index = field.get_type_index();
        if (type_index != std::type_index(typeid(T))) throw std::invalid_argument("Field is not of required type.");
        VAL& type_descriptor = get_type_descriptor(type_index);
        VAL* source_ptr = static_cast<const void*>(&source);
        type_descriptor->inject_value(field, source_ptr, target);
    }

    // Read a reflectable value from a symbol.
    void read_value(const symbol& source_symbol, reflectable& target_reflectable);

    // Write a reflectable value to a symbol.
    void write_value(const reflectable& source_reflectable, symbol& target_symbol);

    // A generalized type descriptor for reflectable types.
    class reflectable_descriptor : public type_descriptor
    {
    public:
        void inspect_value(const void* source_ptr, void* target_ptr) const override;
        void inject_value(const void* source_ptr, void* target_ptr) const override;
        void read_value(const symbol& source_symbol, void* target_ptr) const override;
        void write_value(const void* source_ptr, symbol& target_symbol) const override;
    };

    // Register the common type descriptors.
    // NOTE: this is actually defined in type_descriptors.cpp, but exposed here so that the large
    // type_descriptors.hpp need not be included to access this.
    void register_common_type_descriptors();
}

#endif
<commit_msg>clang warning fix.<commit_after>#ifndef IMPL_AX_TYPE_DESCRIPTOR_HPP
#define IMPL_AX_TYPE_DESCRIPTOR_HPP

#include <cstddef>
#include <typeindex>
#include <functional>
#include <unordered_map>
#include <memory>

#include "prelude.hpp"
#include "type.hpp"
#include "reflectable.hpp"
#include "symbol.hpp"

namespace ax
{
    class type_descriptor
    {
    public:

        CONSTRAINT(type_descriptor);
        virtual ~type_descriptor() = default;

        void inspect_value(const reflectable& source, const field& field, void* target_ptr) const;
        void inject_value(const field& field, const void* source_ptr, reflectable& target) const;

        virtual void inspect_value(const void* source_ptr, void* target_ptr) const = 0;
        virtual void inject_value(const void* source_ptr, void* target_ptr) const = 0;
        virtual void read_value(const symbol& source_symbol, void* target_ptr) const = 0;
        virtual void write_value(const void* source_ptr, symbol& target_symbol) const = 0;

    protected:

        template<typename T, typename D>
        friend std::shared_ptr<D> register_type_descriptor(const std::shared_ptr<D>& type_descriptor);
        friend const std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>>& get_type_descriptor_map();

    private:

        static std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>> type_descriptor_map;
    };

    // The alias for a type descriptor map.
    using type_descriptor_map = std::unordered_map<std::type_index, std::shared_ptr<type_descriptor>>;

    // Get the type descriptor map.
    const type_descriptor_map& get_type_descriptor_map();

    // Get the type descriptor for the given type index.
    std::shared_ptr<type_descriptor> get_type_descriptor(std::type_index type_index);

    // Get a type descriptor for the given template argument.
    template<typename T>
    std::shared_ptr<type_descriptor> get_type_descriptor()
    {
        VAL& type_index = std::type_index(typeid(T));
        return get_type_descriptor(type_index);
    }

    // Register a type descriptor.
    template<typename T, typename D>
    std::shared_ptr<D> register_type_descriptor(const std::shared_ptr<D>& type_descriptor)
    {
        CONSTRAIN(D, type_descriptor);
        VAL& type_index = std::type_index(typeid(T));
        VAR insertion = type_descriptor::type_descriptor_map.emplace(type_index, type_descriptor);
        if (!insertion.second) insertion.first->second = type_descriptor;
        return type_descriptor;
    }

    // Assign a value via void ptrs.
    template<typename T>
    void assign_value(const void* source_ptr, void* target_ptr)
    {
        VAL* source_ptr_t = static_cast<const T*>(source_ptr);
        VAR* target_ptr_t = static_cast<T*>(target_ptr);
        *target_ptr_t = *source_ptr_t;
    }

    // Assign a shared_ptr via void ptrs.
    template<typename T>
    void assign_shared_ptr(const void* source_ptr, void* target_ptr)
    {
        CONSTRAIN_AS_SHARED_PTR(T);
        VAL* source_ptr_ptr = static_cast<const std::shared_ptr<T>*>(source_ptr);
        VAR* target_ptr_ptr = static_cast<std::shared_ptr<T>*>(target_ptr);
        *target_ptr_ptr = *source_ptr_ptr;
    }

    // Assign a unique_ptr via void ptrs.
    template<typename T>
    void assign_unique_ptr(void* source_ptr, void* target_ptr)
    {
        CONSTRAIN_AS_UNIQUE_PTR(T);
        VAR* source_ptr_ptr = static_cast<std::unique_ptr<T>*>(source_ptr);
        VAR* target_ptr_ptr = static_cast<std::unique_ptr<T>*>(target_ptr);
        target_ptr_ptr->reset(source_ptr_ptr->get());
    }

    // Inspect a value of a reflectable value.
    template<typename T>
    void inspect_value(const reflectable& source, const field& field, T& target)
    {
        VAL& type_index = field.get_type_index();
        if (type_index != std::type_index(typeid(T))) throw std::invalid_argument("Field is not of required type.");
        VAL& type_descriptor = get_type_descriptor(type_index);
        VAR* target_ptr = static_cast<void*>(&target);
        type_descriptor->inspect_value(source, field, target_ptr);
    }

    // Inject a value into a reflectable value.
    template<typename T>
    void inject_value(const field& field, const T& source, reflectable& target)
    {
        VAL& type_index = field.get_type_index();
        if (type_index != std::type_index(typeid(T))) throw std::invalid_argument("Field is not of required type.");
        VAL& type_descriptor = get_type_descriptor(type_index);
        VAL* source_ptr = static_cast<const void*>(&source);
        type_descriptor->inject_value(field, source_ptr, target);
    }

    // Read a reflectable value from a symbol.
    void read_value(const symbol& source_symbol, reflectable& target_reflectable);

    // Write a reflectable value to a symbol.
    void write_value(const reflectable& source_reflectable, symbol& target_symbol);

    // A generalized type descriptor for reflectable types.
    class reflectable_descriptor : public type_descriptor
    {
    public:
        void inspect_value(const void* source_ptr, void* target_ptr) const override;
        void inject_value(const void* source_ptr, void* target_ptr) const override;
        void read_value(const symbol& source_symbol, void* target_ptr) const override;
        void write_value(const void* source_ptr, symbol& target_symbol) const override;
    };

    // Register the common type descriptors.
    // NOTE: this is actually defined in type_descriptors.cpp, but exposed here so that the large
    // type_descriptors.hpp need not be included to access this.
    void register_common_type_descriptors();
}

#endif
<|endoftext|>