<commit_before>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */

#include <map>

#include "db/util/Math.h"
#include "db/util/Date.h"
#include "db/logging/Logger.h"

using namespace std;
using namespace db::io;
using namespace db::util;
using namespace db::logging;

std::multimap<const char*, Logger*, Logger::NameComparator> Logger::sLoggers;

const char* Logger::defaultCategory = "__DEFAULT__";

const char* Logger::levelToString(Level level)
{
   // FIXME: return an std::string, pass in a buffer that
   // has to get filled, or heap-allocate and require the user
   // to delete the return value from this method -- as it stands
   // this stuff will get stack allocated and then wiped out when
   // the function returns, resulting in the return value of this
   // method pointing somewhere unsafe
   const char* rval;

   switch(level)
   {
      case None:
         rval = "";
         break;
      case Error:
         rval = "ERROR";
         break;
      case Warning:
         rval = "WARNING";
         break;
      case Info:
         rval = "INFO";
         break;
      case Debug:
         rval = "DEBUG";
         break;
      case DebugData:
         rval = "DEBUG-DATA";
         break;
      case DebugDetail:
         rval = "DEBUG-DETAIL";
         break;
      default:
         rval = "OTHER";
   }

   return rval;
}

void Logger::addLogger(Logger* logger, const char* category)
{
   sLoggers.insert(pair<const char*, Logger*>(category, logger));
}

void Logger::removeLogger(Logger* logger, const char* category)
{
   // FIXME
   assert(false);
}

Logger::Logger(const char* name, Level level)
{
   mName = new char[strlen(name) + 1];
   strcpy(mName, name);

   setLevel(level);

   mDateFormat = NULL;
   setDateFormat("%Y-%m-%d %H:%M:%S");
}

Logger::~Logger()
{
   delete [] mName;

   if(mDateFormat != NULL)
   {
      delete [] mDateFormat;
   }
}

const char* Logger::getName()
{
   return mName;
}

void Logger::setLevel(Level level)
{
   mLevel = level;
}

Logger::Level Logger::getLevel()
{
   return mLevel;
}

void Logger::getDate(string& date)
{
   date.erase();

   if(strcmp(mDateFormat, "") == 0)
   {
      // shortcut - do nothing
   }
   else
   {
      // handle other date formats here
      Date now;
      date = now.format(date, mDateFormat, "c");
   }
}

bool Logger::setDateFormat(const char* dateFormat)
{
   lock();
   {
      if(mDateFormat != NULL)
      {
         delete [] mDateFormat;
      }

      mDateFormat = new char[strlen(dateFormat) + 1];
      strcpy(mDateFormat, dateFormat);
   }
   unlock();

   return true;
}

bool Logger::log(
   const char* cat,
   Level level,
   const char* file,
   const char* function,
   int line,
   const void* object,
   const char* message)
{
   bool rval = false;

   if(mLevel >= level)
   {
      lock();

      // Output as:
      // [date: ][level: ][cat: ][file:][function:][line: ][object: ]message
      string logText;

      string date;
      getDate(date);
      if(strcmp(date.c_str(), "") != 0)
      {
         logText.append(date);
         logText.append(": ");
      }

      logText.append(levelToString(level));
      logText.append(": ");

      if(cat != NULL && strcmp(cat, defaultCategory) != 0)
      {
         logText.append(cat);
         logText.append(": ");
      }

      if(file)
      {
         logText.append(file);
         logText.append(1, ':');
      }
      if(function)
      {
         logText.append(function);
         logText.append(1, ':');
      }
      if(line != -1)
      {
         char tmp[21];
         snprintf(tmp, 21, "%d", line);
         logText.append(tmp);
         logText.append(1, ':');
      }
      if(file || function || line)
      {
         logText.append(1, ' ');
      }

      if(object)
      {
         char tmp[23];
         snprintf(tmp, 21, "<%p>", object);
         logText.append(tmp);
         logText.append(": ");
      }

      logText.append(message);
      logText.append(1, '\n');

      log(logText.c_str());
      rval = true;

      unlock();
   }

   return rval;
}

void Logger::catLevelLog(
   const char* cat,
   Level level,
   const char* file,
   const char* function,
   int line,
   const void* object,
   const char* message)
{
   multimap<const char*, Logger*, NameComparator>::iterator i = sLoggers.find(cat);
   while(i != sLoggers.end())
   {
      Logger* lg = i->second;
      lg->log(cat, level, file, function, line, object, message);
      i++;
   }
}

#if 0
const char* Logger::getStackTrace(Throwable t)
{
   String rval = "null";

   if(t != null)
   {
      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter(sw);
      t.printStackTrace(pw);
      pw.close();

      rval = sw.toString();
   }

   return rval;
}
#endif
<commit_msg>Changed loop in catLevelLog() to go to sLoggers.upper_bound() instead of sLoggers.end() for iterating over search results in multimap.<commit_after>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */

#include <map>

#include "db/util/Math.h"
#include "db/util/Date.h"
#include "db/logging/Logger.h"

using namespace std;
using namespace db::io;
using namespace db::util;
using namespace db::logging;

std::multimap<const char*, Logger*, Logger::NameComparator> Logger::sLoggers;

const char* Logger::defaultCategory = "__DEFAULT__";

const char* Logger::levelToString(Level level)
{
   // FIXME: return an std::string, pass in a buffer that
   // has to get filled, or heap-allocate and require the user
   // to delete the return value from this method -- as it stands
   // this stuff will get stack allocated and then wiped out when
   // the function returns, resulting in the return value of this
   // method pointing somewhere unsafe
   const char* rval;

   switch(level)
   {
      case None:
         rval = "";
         break;
      case Error:
         rval = "ERROR";
         break;
      case Warning:
         rval = "WARNING";
         break;
      case Info:
         rval = "INFO";
         break;
      case Debug:
         rval = "DEBUG";
         break;
      case DebugData:
         rval = "DEBUG-DATA";
         break;
      case DebugDetail:
         rval = "DEBUG-DETAIL";
         break;
      default:
         rval = "OTHER";
   }

   return rval;
}

void Logger::addLogger(Logger* logger, const char* category)
{
   sLoggers.insert(pair<const char*, Logger*>(category, logger));
}

void Logger::removeLogger(Logger* logger, const char* category)
{
   // FIXME
   assert(false);
}

Logger::Logger(const char* name, Level level)
{
   mName = new char[strlen(name) + 1];
   strcpy(mName, name);

   setLevel(level);

   mDateFormat = NULL;
   setDateFormat("%Y-%m-%d %H:%M:%S");
}

Logger::~Logger()
{
   delete [] mName;

   if(mDateFormat != NULL)
   {
      delete [] mDateFormat;
   }
}

const char* Logger::getName()
{
   return mName;
}

void Logger::setLevel(Level level)
{
   mLevel = level;
}

Logger::Level Logger::getLevel()
{
   return mLevel;
}

void Logger::getDate(string& date)
{
   date.erase();

   if(strcmp(mDateFormat, "") == 0)
   {
      // shortcut - do nothing
   }
   else
   {
      // handle other date formats here
      Date now;
      date = now.format(date, mDateFormat, "c");
   }
}

bool Logger::setDateFormat(const char* dateFormat)
{
   lock();
   {
      if(mDateFormat != NULL)
      {
         delete [] mDateFormat;
      }

      mDateFormat = new char[strlen(dateFormat) + 1];
      strcpy(mDateFormat, dateFormat);
   }
   unlock();

   return true;
}

bool Logger::log(
   const char* cat,
   Level level,
   const char* file,
   const char* function,
   int line,
   const void* object,
   const char* message)
{
   bool rval = false;

   if(mLevel >= level)
   {
      lock();

      // Output as:
      // [date: ][level: ][cat: ][file:][function:][line: ][object: ]message
      string logText;

      string date;
      getDate(date);
      if(strcmp(date.c_str(), "") != 0)
      {
         logText.append(date);
         logText.append(": ");
      }

      logText.append(levelToString(level));
      logText.append(": ");

      if(cat != NULL && strcmp(cat, defaultCategory) != 0)
      {
         logText.append(cat);
         logText.append(": ");
      }

      if(file)
      {
         logText.append(file);
         logText.append(1, ':');
      }
      if(function)
      {
         logText.append(function);
         logText.append(1, ':');
      }
      if(line != -1)
      {
         char tmp[21];
         snprintf(tmp, 21, "%d", line);
         logText.append(tmp);
         logText.append(1, ':');
      }
      if(file || function || line)
      {
         logText.append(1, ' ');
      }

      if(object)
      {
         char tmp[23];
         snprintf(tmp, 21, "<%p>", object);
         logText.append(tmp);
         logText.append(": ");
      }

      logText.append(message);
      logText.append(1, '\n');

      log(logText.c_str());
      rval = true;

      unlock();
   }

   return rval;
}

void Logger::catLevelLog(
   const char* cat,
   Level level,
   const char* file,
   const char* function,
   int line,
   const void* object,
   const char* message)
{
   multimap<const char*, Logger*, NameComparator>::iterator i = sLoggers.find(cat);
   if(i != sLoggers.end())
   {
      multimap<const char*, Logger*, NameComparator>::iterator end =
         sLoggers.upper_bound(cat);
      for(; i != end; i++)
      {
         Logger* lg = i->second;
         lg->log(cat, level, file, function, line, object, message);
      }
   }
}

#if 0
const char* Logger::getStackTrace(Throwable t)
{
   String rval = "null";

   if(t != null)
   {
      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter(sw);
      t.printStackTrace(pw);
      pw.close();

      rval = sw.toString();
   }

   return rval;
}
#endif
<|endoftext|>


<commit_before>/*
 * STDPConn.hpp
 *
 *  Created on: Jan 28, 2011
 *      Author: sorenrasmussen
 */

#ifndef STDPCONN_HPP_
#define STDPCONN_HPP_

#include "HyPerConn.hpp"

namespace PV {

class STDPConn : HyPerConn {
public:
   STDPConn();
   STDPConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
             ChannelType channel);
   virtual ~STDPConn();

   virtual int initializeThreadBuffers();
   virtual int initializeThreadKernels();

   virtual PVPatch     * getPlasticityIncrement(int k, int arbor);
   inline  PVLayerCube * getPlasticityDecrement()     {return pDecr;}

protected:

   int initialize();

   PVLayerCube    * pDecr;      // plasticity decrement variable (Mi) for post-synaptic layer
   PVPatch       ** pIncr;      // list of stdp patches Psij variable

   bool     localWmaxFlag;  // presence of rate dependent wMax;
   pvdata_t * Wmax;   // adaptive upper STDP weight boundary

   // STDP parameters for modifying weights
   float ampLTP; // long term potentiation amplitude
   float ampLTD; // long term depression amplitude
   float tauLTP;
   float tauLTD;
   float dWMax;
};

}

#endif /* STDPCONN_HPP_ */
<commit_msg>Modifications needed to implement STDPConn.<commit_after>/*
 * STDPConn.hpp
 *
 *  Created on: Jan 28, 2011
 *      Author: sorenrasmussen
 */

#ifndef STDPCONN_HPP_
#define STDPCONN_HPP_

#include "HyPerConn.hpp"
#include <stdio.h>

namespace PV {

class STDPConn : HyPerConn {
public:
   STDPConn();
   STDPConn(const char * name, HyPerCol * hc, HyPerLayer * pre, HyPerLayer * post,
            ChannelType channel, const char * filename=NULL);
   virtual ~STDPConn();

   int setParams(PVParams * params);

   virtual int initializeThreadBuffers();
   virtual int initializeThreadKernels();

   virtual int deleteWeights();

   virtual float maxWeight();

   virtual int updateState(float time, float dt);
   virtual int updateWeights(int axonId);
   virtual int outputState(float time, bool last=false);
   virtual int writeTextWeightsExtra(FILE * fd, int k);

   virtual PVPatch     * getPlasticityIncrement(int k, int arbor);
   virtual PVLayerCube * getPlasticityDecrement();

protected:

   int initialize(const char * name, HyPerCol * hc,
                  HyPerLayer * pre, HyPerLayer * post,
                  ChannelType channel, const char * filename);

   virtual int adjustAxonalPatches(PVAxonalArbor * arbor, int nxPatch, int nyPatch, int dx, int dy);

   PVLayerCube    * pDecr;      // plasticity decrement variable (Mi) for post-synaptic layer
   PVPatch       ** pIncr;      // list of stdp patches Psij variable

   bool       stdpFlag;         // presence of spike timing dependent plasticity
   bool       localWmaxFlag;    // presence of rate dependent wMax;
   pvdata_t * Wmax;             // adaptive upper STDP weight boundary

   // STDP parameters for modifying weights
   float ampLTP; // long term potentiation amplitude
   float ampLTD; // long term depression amplitude
   float tauLTP;
   float tauLTD;
   float dWMax;
};

}

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


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt 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 notices for more information.

=========================================================================*/
#include "otbStandardShader.h"
#include "otbFragmentShaderRegistry.h"
#include "otbGlVersionChecker.h"
#include <GL/glew.h>

namespace otb
{

StandardShader::StandardShader() :
  m_LocalContrastRange( 50 ),
  m_SpectralAngleRange( 10 ),
  m_Center(),
  m_Radius( 200 ),
  m_ChessboardSize( 256 ),
  m_SliderPosition( 500 ),
  m_VerticalSlider( false ),
  m_ShaderType( SHADER_STANDARD )
{
  m_Center.Fill( 0 );

  BuildShader();
}

StandardShader::~StandardShader()
{}

std::string StandardShader::GetSource() const
{
  const char * glVersion = NULL;
  const char * glslVersion = NULL;
  if(!otb::GlVersionChecker::CheckGLCapabilities( glVersion, glslVersion))
    {
    itkExceptionMacro(<<" Required GL and GLSL versions were not found (GL version is "<<glVersion<<", should be at least "<<otb::GlVersionChecker::REQUIRED_GL_VERSION<<", GLSL version is "<<glslVersion<<", should be at least "<<otb::GlVersionChecker::REQUIRED_GLSL_VERSION<<")");
    }

  bool isGLSLS140Available  = otb::GlVersionChecker::VerCmp(glslVersion,"1.40")>=0;

  std::string shader_source = "";

  if(isGLSLS140Available)
    {
    shader_source+="#version 140 \n";
    }
  else
    {
    shader_source+="#version 130 \n";
    }

  shader_source =
    "uniform sampler2D src;\n"                                          \
    "uniform vec4 shader_a;\n"                                          \
    "uniform vec4 shader_b;\n"                                          \
    "uniform int shader_use_no_data;\n"                                 \
    "uniform float shader_no_data;\n"                                   \
    "uniform vec3 shader_current;\n"                                    \
    "uniform vec4 shader_gamma;\n"                                      \
    "uniform float shader_alpha;\n"                                     \
    "uniform vec2 shader_center;\n"                                     \
    "uniform int shader_type;\n"                                        \
    "uniform float shader_radius;\n"                                    \
    "uniform float shader_localc_range;\n"                              \
    "uniform float shader_spectral_angle_range;\n"                      \
    "uniform float shader_chessboard_size;\n"                           \
    "uniform float shader_slider_pos;\n"                                \
    "uniform int shader_vertical_slider_flag;\n"                        \
    "void main (void) {\n"                                              \
    "vec4 p = texture2D(src, gl_TexCoord[0].xy);\n"                     \
    "gl_FragColor = clamp(pow((p+shader_b)*shader_a,shader_gamma), 0.0, 1.0);\n" \
    "gl_FragColor[3] = clamp(shader_alpha,0.0,1.0);\n"                  \
    "if(shader_use_no_data > 0 && vec3(p) == vec3(shader_no_data)){\n"  \
    "gl_FragColor[3] = 0.;\n"                                           \
    "}\n"                                                               \
    "float alpha = gl_FragColor[3];\n"                                  \
    "float dist = distance(gl_FragCoord.xy,shader_center);\n" \
    "if(shader_type == 1)\n"                                            \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "vec3 tmp = clamp((vec3(p)-vec3(shader_current)+vec3(shader_localc_range))/(2.*vec3(shader_localc_range)),0.0,1.0);\n" \
    "gl_FragColor[0] = tmp[0];\n"                                       \
    "gl_FragColor[1] = tmp[1];\n"                                       \
    "gl_FragColor[2] = tmp[2];\n"                                       \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n"                                                               \
    "else if(shader_type == 2)"                                         \
    "{\n"                                                               \
    "gl_FragColor[3] = dist > shader_radius ? 1.0 : 0.0; \n"            \
    "}\n"                                                               \
    "else if(shader_type == 3)\n"                                       \
    "{\n"                                                               \
    "float alpha = (mod(floor(gl_FragCoord.x / shader_chessboard_size), 2.0) == 0.) != (mod(floor(gl_FragCoord.y / shader_chessboard_size), 2.0) == 1.) ? shader_alpha : 0.0;\n" \
    "gl_FragColor[3] = clamp(alpha,0.0,1.0);\n"                         \
    "}\n"                                                               \
    "else if(shader_type == 4)\n"                                       \
    "{\n"                                                               \
    "float alpha = (shader_vertical_slider_flag == 0 && gl_FragCoord.x > shader_slider_pos) || (shader_vertical_slider_flag == 1 && gl_FragCoord.y > shader_slider_pos) ? 1.0 : 0.0;\n" \
    "gl_FragColor[3] = clamp(alpha,0.0,1.0);\n"                         \
    "}\n"                                                               \
    "else if(shader_type == 5)\n"                                       \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "float angle = acos(clamp(dot(vec3(p),shader_current)/(length(vec3(p))*length(shader_current)),-1.0,1.0));\n" \
    "vec3 tmp = clamp(vec3(1.-shader_spectral_angle_range*abs(angle)/3.142),0.0,1.0);\n" \
    "gl_FragColor[0] = tmp[0];\n"                                       \
    "gl_FragColor[1] = tmp[1];\n"                                       \
    "gl_FragColor[2] = tmp[2];\n"                                       \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n";

  if(isGLSLS140Available)
    {
    shader_source+=
    "else if(shader_type == 6)\n"                                       \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "vec2 size = vec2(textureSize(src,0));\n"                           \
    "vec2 dx = vec2(gl_TexCoord[0].xy);\n"                              \
    "dx[0]+=1.0/size[0];\n"                                             \
    "vec2 dy = vec2(gl_TexCoord[0].xy);\n"                              \
    "dy[1]+=1.0/size[1];\n"                                             \
    "vec4 pdx = texture2D(src, dx);\n"                                  \
    "vec4 pdy = texture2D(src, dy);\n"                                  \
    "gl_FragColor = clamp(pow(5*shader_a*(0.5*abs((pdx-p))+ 0.5*abs((pdy-p))),shader_gamma),0.0,1.0);\n" \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n";
    }
  shader_source+="}";
  return shader_source;
}

std::string StandardShader::GetName() const
{
  return "StandardShader";
}

void StandardShader::SetupShader()
{
  assert( !m_ImageSettings.IsNull() );

  //
  // Compute shifts.
  double shr = -m_ImageSettings->GetMinRed();
  double shg = -m_ImageSettings->GetMinGreen();
  double shb = -m_ImageSettings->GetMinBlue();
  //
  // Compute scales.
  double scr = 1.0 / ( m_ImageSettings->GetMaxRed()+shr );
  double scg = 1.0 / ( m_ImageSettings->GetMaxGreen()+shg );
  double scb = 1.0 / ( m_ImageSettings->GetMaxBlue()+shb );

  double gamma = m_ImageSettings->GetGamma();

  GLint shader_a = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_a");
  glUniform4f(shader_a,scr,scg,scb,1.);

  GLint shader_b = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_b");
  glUniform4f(shader_b,shr,shg,shb,0);

  GLint shader_use_no_data = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_use_no_data");
  glUniform1i(shader_use_no_data, m_ImageSettings->GetUseNoData()  );

  GLint shader_no_data = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_no_data");
  glUniform1f( shader_no_data, m_ImageSettings->GetNoData() );

  GLint shader_gamma = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_gamma");
  glUniform4f( shader_gamma, gamma, gamma, gamma, gamma );

  GLint shader_alpha = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_alpha");
  glUniform1f( shader_alpha, m_ImageSettings->GetAlpha() );

  GLint shader_radius = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_radius");
  glUniform1f(shader_radius,m_Radius);

  GLint shader_center = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_center");
  glUniform2f(shader_center,m_Center[0],m_Center[1]);

  GLint shader_type = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_type");
  glUniform1i(shader_type,m_ShaderType);

  // std::cout
  //   << "r: " << m_ImageSettings->GetCurrentRed()
  //   << " g: " << m_ImageSettings->GetCurrentGreen()
  //   << " b: " << m_ImageSettings->GetCurrentBlue()
  //   << std::endl;

  GLint shader_current = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_current");
  glUniform3f(
    shader_current,
    m_ImageSettings->GetCurrentRed(),
    m_ImageSettings->GetCurrentGreen(),
    m_ImageSettings->GetCurrentBlue()
  );

  GLint shader_localc_range = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_localc_range");
  glUniform1f(shader_localc_range,m_LocalContrastRange);

  GLint shader_spectral_angle_range = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_spectral_angle_range");
  glUniform1f(shader_spectral_angle_range,m_SpectralAngleRange);

  GLint shader_chessboard_size = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_chessboard_size");
  glUniform1f(shader_chessboard_size,m_ChessboardSize);

  GLint shader_slider_pos = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_slider_pos");
  glUniform1f(shader_slider_pos,m_SliderPosition);

  GLint shader_vertical_slider_flag = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_vertical_slider_flag");
  glUniform1i(shader_vertical_slider_flag,m_VerticalSlider);

}

} // End namespace otb

<commit_msg>COMP: Added missing include header-file.<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt 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 notices for more information.

=========================================================================*/
#include "otbStandardShader.h"

#include <cassert>
#include <GL/glew.h>

#include "otbFragmentShaderRegistry.h"
#include "otbGlVersionChecker.h"

namespace otb
{

StandardShader::StandardShader() :
  m_LocalContrastRange( 50 ),
  m_SpectralAngleRange( 10 ),
  m_Center(),
  m_Radius( 200 ),
  m_ChessboardSize( 256 ),
  m_SliderPosition( 500 ),
  m_VerticalSlider( false ),
  m_ShaderType( SHADER_STANDARD )
{
  m_Center.Fill( 0 );

  BuildShader();
}

StandardShader::~StandardShader()
{}

std::string StandardShader::GetSource() const
{
  const char * glVersion = NULL;
  const char * glslVersion = NULL;
  if(!otb::GlVersionChecker::CheckGLCapabilities( glVersion, glslVersion))
    {
    itkExceptionMacro(<<" Required GL and GLSL versions were not found (GL version is "<<glVersion<<", should be at least "<<otb::GlVersionChecker::REQUIRED_GL_VERSION<<", GLSL version is "<<glslVersion<<", should be at least "<<otb::GlVersionChecker::REQUIRED_GLSL_VERSION<<")");
    }

  bool isGLSLS140Available  = otb::GlVersionChecker::VerCmp(glslVersion,"1.40")>=0;

  std::string shader_source = "";

  if(isGLSLS140Available)
    {
    shader_source+="#version 140 \n";
    }
  else
    {
    shader_source+="#version 130 \n";
    }

  shader_source =
    "uniform sampler2D src;\n"                                          \
    "uniform vec4 shader_a;\n"                                          \
    "uniform vec4 shader_b;\n"                                          \
    "uniform int shader_use_no_data;\n"                                 \
    "uniform float shader_no_data;\n"                                   \
    "uniform vec3 shader_current;\n"                                    \
    "uniform vec4 shader_gamma;\n"                                      \
    "uniform float shader_alpha;\n"                                     \
    "uniform vec2 shader_center;\n"                                     \
    "uniform int shader_type;\n"                                        \
    "uniform float shader_radius;\n"                                    \
    "uniform float shader_localc_range;\n"                              \
    "uniform float shader_spectral_angle_range;\n"                      \
    "uniform float shader_chessboard_size;\n"                           \
    "uniform float shader_slider_pos;\n"                                \
    "uniform int shader_vertical_slider_flag;\n"                        \
    "void main (void) {\n"                                              \
    "vec4 p = texture2D(src, gl_TexCoord[0].xy);\n"                     \
    "gl_FragColor = clamp(pow((p+shader_b)*shader_a,shader_gamma), 0.0, 1.0);\n" \
    "gl_FragColor[3] = clamp(shader_alpha,0.0,1.0);\n"                  \
    "if(shader_use_no_data > 0 && vec3(p) == vec3(shader_no_data)){\n"  \
    "gl_FragColor[3] = 0.;\n"                                           \
    "}\n"                                                               \
    "float alpha = gl_FragColor[3];\n"                                  \
    "float dist = distance(gl_FragCoord.xy,shader_center);\n" \
    "if(shader_type == 1)\n"                                            \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "vec3 tmp = clamp((vec3(p)-vec3(shader_current)+vec3(shader_localc_range))/(2.*vec3(shader_localc_range)),0.0,1.0);\n" \
    "gl_FragColor[0] = tmp[0];\n"                                       \
    "gl_FragColor[1] = tmp[1];\n"                                       \
    "gl_FragColor[2] = tmp[2];\n"                                       \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n"                                                               \
    "else if(shader_type == 2)"                                         \
    "{\n"                                                               \
    "gl_FragColor[3] = dist > shader_radius ? 1.0 : 0.0; \n"            \
    "}\n"                                                               \
    "else if(shader_type == 3)\n"                                       \
    "{\n"                                                               \
    "float alpha = (mod(floor(gl_FragCoord.x / shader_chessboard_size), 2.0) == 0.) != (mod(floor(gl_FragCoord.y / shader_chessboard_size), 2.0) == 1.) ? shader_alpha : 0.0;\n" \
    "gl_FragColor[3] = clamp(alpha,0.0,1.0);\n"                         \
    "}\n"                                                               \
    "else if(shader_type == 4)\n"                                       \
    "{\n"                                                               \
    "float alpha = (shader_vertical_slider_flag == 0 && gl_FragCoord.x > shader_slider_pos) || (shader_vertical_slider_flag == 1 && gl_FragCoord.y > shader_slider_pos) ? 1.0 : 0.0;\n" \
    "gl_FragColor[3] = clamp(alpha,0.0,1.0);\n"                         \
    "}\n"                                                               \
    "else if(shader_type == 5)\n"                                       \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "float angle = acos(clamp(dot(vec3(p),shader_current)/(length(vec3(p))*length(shader_current)),-1.0,1.0));\n" \
    "vec3 tmp = clamp(vec3(1.-shader_spectral_angle_range*abs(angle)/3.142),0.0,1.0);\n" \
    "gl_FragColor[0] = tmp[0];\n"                                       \
    "gl_FragColor[1] = tmp[1];\n"                                       \
    "gl_FragColor[2] = tmp[2];\n"                                       \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n";

  if(isGLSLS140Available)
    {
    shader_source+=
    "else if(shader_type == 6)\n"                                       \
    "{\n"                                                               \
    "if(dist < shader_radius)\n"                                        \
    "{\n"                                                               \
    "vec2 size = vec2(textureSize(src,0));\n"                           \
    "vec2 dx = vec2(gl_TexCoord[0].xy);\n"                              \
    "dx[0]+=1.0/size[0];\n"                                             \
    "vec2 dy = vec2(gl_TexCoord[0].xy);\n"                              \
    "dy[1]+=1.0/size[1];\n"                                             \
    "vec4 pdx = texture2D(src, dx);\n"                                  \
    "vec4 pdy = texture2D(src, dy);\n"                                  \
    "gl_FragColor = clamp(pow(5*shader_a*(0.5*abs((pdx-p))+ 0.5*abs((pdy-p))),shader_gamma),0.0,1.0);\n" \
    "gl_FragColor[3] = alpha;\n"                                        \
    "}\n"                                                               \
    "}\n";
    }
  shader_source+="}";
  return shader_source;
}

std::string StandardShader::GetName() const
{
  return "StandardShader";
}

void StandardShader::SetupShader()
{
  assert( !m_ImageSettings.IsNull() );

  //
  // Compute shifts.
  double shr = -m_ImageSettings->GetMinRed();
  double shg = -m_ImageSettings->GetMinGreen();
  double shb = -m_ImageSettings->GetMinBlue();
  //
  // Compute scales.
  double scr = 1.0 / ( m_ImageSettings->GetMaxRed()+shr );
  double scg = 1.0 / ( m_ImageSettings->GetMaxGreen()+shg );
  double scb = 1.0 / ( m_ImageSettings->GetMaxBlue()+shb );

  double gamma = m_ImageSettings->GetGamma();

  GLint shader_a = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_a");
  glUniform4f(shader_a,scr,scg,scb,1.);

  GLint shader_b = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_b");
  glUniform4f(shader_b,shr,shg,shb,0);

  GLint shader_use_no_data = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_use_no_data");
  glUniform1i(shader_use_no_data, m_ImageSettings->GetUseNoData()  );

  GLint shader_no_data = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_no_data");
  glUniform1f( shader_no_data, m_ImageSettings->GetNoData() );

  GLint shader_gamma = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_gamma");
  glUniform4f( shader_gamma, gamma, gamma, gamma, gamma );

  GLint shader_alpha = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_alpha");
  glUniform1f( shader_alpha, m_ImageSettings->GetAlpha() );

  GLint shader_radius = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_radius");
  glUniform1f(shader_radius,m_Radius);

  GLint shader_center = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_center");
  glUniform2f(shader_center,m_Center[0],m_Center[1]);

  GLint shader_type = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_type");
  glUniform1i(shader_type,m_ShaderType);

  // std::cout
  //   << "r: " << m_ImageSettings->GetCurrentRed()
  //   << " g: " << m_ImageSettings->GetCurrentGreen()
  //   << " b: " << m_ImageSettings->GetCurrentBlue()
  //   << std::endl;

  GLint shader_current = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_current");
  glUniform3f(
    shader_current,
    m_ImageSettings->GetCurrentRed(),
    m_ImageSettings->GetCurrentGreen(),
    m_ImageSettings->GetCurrentBlue()
  );

  GLint shader_localc_range = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_localc_range");
  glUniform1f(shader_localc_range,m_LocalContrastRange);

  GLint shader_spectral_angle_range = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_spectral_angle_range");
  glUniform1f(shader_spectral_angle_range,m_SpectralAngleRange);

  GLint shader_chessboard_size = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_chessboard_size");
  glUniform1f(shader_chessboard_size,m_ChessboardSize);

  GLint shader_slider_pos = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_slider_pos");
  glUniform1f(shader_slider_pos,m_SliderPosition);

  GLint shader_vertical_slider_flag = glGetUniformLocation(otb::FragmentShaderRegistry::Instance()->GetShaderProgram("StandardShader"), "shader_vertical_slider_flag");
  glUniform1i(shader_vertical_slider_flag,m_VerticalSlider);

}

} // End namespace otb

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2012.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "Event.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Execution;

/*
 * Design notes:
 *
 *      o   The use of condition variables is non-obvious. I haven't found good documentation, but
 *          the best I've found would be
 *              https://computing.llnl.gov/tutorials/pthreads/#ConVarOverview
 *
 *          In particular, on the surface, it looks like the mutex locks in Wait() and signal should prevent things
 *          form working (deadlock). But they apparently do not cause a deadlock because
 *              "pthread_cond_wait() blocks the calling thread until the specified condition is signalled.
 *               This routine should be called while mutex is locked, and it will automatically release the
 *               mutex while it waits. After signal is received and thread is awakened, mutex will be
 *               automatically locked for use by the thread. The programmer is then responsible for
 *               unlocking mutex when the thread is finished with it."
 *
 */

/*
 * TODO:
 *          o   POSIX/C++ code below on wait is a bit of a KLUGE. Unclear if it was a red-herring or
 *              osmething like that needed. Review once threading stuff stable.
 *                  -- LGP 2011-10-27
 *              NB: its been working and stable for quite a while. It could use cleanup/docs (working on that).
 *              and the timeout part maybe wrong (esp with signals). But it appears to mostly be
 *              correct.
 */

/*
 ********************************************************************************
 ************************************** Event ***********************************
 ********************************************************************************
 */
#if     qTrack_ThreadUtils_HandleCounts
uint32_t    Event::sCurAllocatedHandleCount     =   0;
#endif
void    Event::Wait (Time::DurationSecondsType timeout)
{
    //Debug::TraceContextBumper ctx (TSTR ("Event::Wait"));
    //DbgTrace ("(timeout = %.2f)", timeout);
    CheckForThreadAborting ();
#if         qPlatform_Windows
    AssertNotNull (fEventHandle);
    // must be careful about rounding errors in int->DurationSecondsType->int
Again:
    DWORD   result  =   ::WaitForSingleObjectEx (fEventHandle, Platform::Windows::Duration2Milliseconds (timeout), true);
    switch (result) {
        case    WAIT_TIMEOUT:
            DoThrow (WaitTimedOutException ());
        case    WAIT_ABANDONED:
            DoThrow (WaitAbandonedException ());
        case    WAIT_IO_COMPLETION:
            CheckForThreadAborting ();
            goto Again;  // roughly right to goto again - should decrement timeout- APC other than for abort - we should just keep waiting
    }
    Verify (result == WAIT_OBJECT_0);
#elif       qUseThreads_StdCPlusPlus
    std::unique_lock<std::mutex> lock (fMutex_);
    Time::DurationSecondsType   until   =   Time::GetTickCount () + timeout;
    Assert (until >= timeout);  // so no funny overflow issues...
    /*
     * The reason for the loop is that fConditionVariable_.wait_for() can return for things like errno==EINTR,
     * but must keep waiting. wait_for () returns no_timeout if for a real reason (notify called) OR spurrious.
     */
    while (not fTriggered_) {
        CheckForThreadAborting ();
        Time::DurationSecondsType   remaining   =   until - Time::GetTickCount ();
        if (remaining < 0) {
            DoThrow (WaitTimedOutException ());
        }
        if (fConditionVariable_.wait_for (lock, std::chrono::duration<double> (remaining)) == std::cv_status::timeout) {
            DoThrow (WaitTimedOutException ());
        }
    }
    fTriggered_ = false ;   // autoreset
#else
    AssertNotImplemented ();
#endif
}
<commit_msg>Slight cleanup of UNIX/std:c++ cond-variable Wait code - including BWA (hopefully temporary) for interupt issue with thread/abort in threadpool code<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2012.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    "../Time/Duration.h"

#include    "Event.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Execution;

using   Stroika::Foundation::Time::Duration;

/*
 * Design notes:
 *
 *      o   The use of condition variables is non-obvious. I haven't found good documentation, but
 *          the best I've found would be
 *              https://computing.llnl.gov/tutorials/pthreads/#ConVarOverview
 *
 *          In particular, on the surface, it looks like the mutex locks in Wait() and signal should prevent things
 *          form working (deadlock). But they apparently do not cause a deadlock because
 *              "pthread_cond_wait() blocks the calling thread until the specified condition is signalled.
 *               This routine should be called while mutex is locked, and it will automatically release the
 *               mutex while it waits. After signal is received and thread is awakened, mutex will be
 *               automatically locked for use by the thread. The programmer is then responsible for
 *               unlocking mutex when the thread is finished with it."
 *
 */

/*
 * TODO:
 *          o   POSIX/C++ code below on wait is a bit of a KLUGE. Unclear if it was a red-herring or
 *              osmething like that needed. Review once threading stuff stable.
 *                  -- LGP 2011-10-27
 *              NB: its been working and stable for quite a while. It could use cleanup/docs (working on that).
 *              and the timeout part maybe wrong (esp with signals). But it appears to mostly be
 *              correct.
 */

/*
 ********************************************************************************
 ************************************** Event ***********************************
 ********************************************************************************
 */
#if     qTrack_ThreadUtils_HandleCounts
uint32_t    Event::sCurAllocatedHandleCount     =   0;
#endif
void    Event::Wait (Time::DurationSecondsType timeout)
{
    //Debug::TraceContextBumper ctx (TSTR ("Event::Wait"));
    //DbgTrace ("(timeout = %.2f)", timeout);
    CheckForThreadAborting ();
#if         qPlatform_Windows
    AssertNotNull (fEventHandle);
    // must be careful about rounding errors in int->DurationSecondsType->int
Again:
    DWORD   result  =   ::WaitForSingleObjectEx (fEventHandle, Platform::Windows::Duration2Milliseconds (timeout), true);
    switch (result) {
        case    WAIT_TIMEOUT:
            DoThrow (WaitTimedOutException ());
        case    WAIT_ABANDONED:
            DoThrow (WaitAbandonedException ());
        case    WAIT_IO_COMPLETION:
            CheckForThreadAborting ();
            goto Again;  // roughly right to goto again - should decrement timeout- APC other than for abort - we should just keep waiting
    }
    Verify (result == WAIT_OBJECT_0);
#elif       qUseThreads_StdCPlusPlus
    std::unique_lock<std::mutex> lock (fMutex_);
    Time::DurationSecondsType   until   =   Time::GetTickCount () + timeout;
    Assert (until >= timeout);  // so no funny overflow issues...
    /*
     * The reason for the loop is that fConditionVariable_.wait_for() can return for things like errno==EINTR,
     * but must keep waiting. wait_for () returns no_timeout if for a real reason (notify called) OR spurrious.
     */
    while (not fTriggered_) {
        CheckForThreadAborting ();
        Time::DurationSecondsType   remaining   =   until - Time::GetTickCount ();
        if (remaining < 0) {
            DoThrow (WaitTimedOutException ());
        }
        // avoid roundoff issues - and not  a big deal to wakeup and wait again once a day ;-)
        const Time::DurationSecondsType k1Day   =   Time::DurationSecondsType (60 * 60 * 24);
        if (remaining >= k1Day) {
            remaining = k1Day;
        }

// hack needed for theadpool test??? Because Abort_ isn't interupting its WAIT
// -- LGP 2012-05-26
#if 1
if (remaining > 5) {
remaining = 5;
}
#endif

        if (fConditionVariable_.wait_for (lock, Time::Duration (remaining).As<std::chrono::duration<double>> ()) == std::cv_status::timeout) {
            // No need for this, since could be caught next time through the loop...
            // And it interferes with the bounding of the 'remaining' count used to avoid overflows
            // DoThrow (WaitTimedOutException ());
        }
    }
    fTriggered_ = false ;   // autoreset
#else
    AssertNotImplemented ();
#endif
}
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkSortByImagePositionPatient.h"
#include "mitkDICOMTag.h"

mitk::SortByImagePositionPatient
::SortByImagePositionPatient(DICOMSortCriterion::Pointer secondaryCriterion)
:DICOMSortCriterion(secondaryCriterion)
{
}

mitk::SortByImagePositionPatient
::~SortByImagePositionPatient()
{
}

mitk::SortByImagePositionPatient
::SortByImagePositionPatient(const SortByImagePositionPatient& other )
:DICOMSortCriterion(other)
{
}

mitk::SortByImagePositionPatient&
mitk::SortByImagePositionPatient
::operator=(const SortByImagePositionPatient& other)
{
  if (this != &other)
  {
    DICOMSortCriterion::operator=(other);
  }
  return *this;
}

mitk::DICOMTagList
mitk::SortByImagePositionPatient
::GetTagsOfInterest() const
{
  DICOMTagList tags;
  tags.push_back( DICOMTag(0x0020, 0x0032) ); // ImagePositionPatient
  tags.push_back( DICOMTag(0x0020, 0x0037) ); // ImageOrientationPatient

  return tags;
}

bool
mitk::SortByImagePositionPatient
::IsLeftBeforeRight(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right) const
{
  // sort by distance to world origin, assuming (almost) equal orientation
  static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
  static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

  static Vector3D leftRight; leftRight.Fill(0.0);
  static Vector3D leftUp; leftUp.Fill(0.0);
  static bool leftHasOrientation(false);
  DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ),
                                   leftRight, leftUp, leftHasOrientation );

  static Vector3D rightRight; rightRight.Fill(0.0);
  static Vector3D rightUp; rightUp.Fill(0.0);
  static bool rightHasOrientation(false);
  DICOMStringToOrientationVectors( right->GetTagValueAsString( tagImageOrientation ),
                                   rightRight, rightUp, rightHasOrientation );

  static Point3D leftOrigin; leftOrigin.Fill(0.0f);
  static bool leftHasOrigin(false);
  leftOrigin = DICOMStringToPoint3D( left->GetTagValueAsString( tagImagePositionPatient ), leftHasOrigin );

  static Point3D rightOrigin; rightOrigin.Fill(0.0f);
  static bool rightHasOrigin(false);
  rightOrigin = DICOMStringToPoint3D( right->GetTagValueAsString( tagImagePositionPatient ), rightHasOrigin );

  //   we tolerate very small differences in image orientation, since we got to know about
  //   acquisitions where these values change across a single series (7th decimal digit)
  //   (http://bugs.mitk.org/show_bug.cgi?id=12263)
  //   still, we want to check if our assumption of 'almost equal' orientations is valid
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    if (   fabs(leftRight[dim] - rightRight[dim]) > 0.0001
        || fabs(leftUp[dim] - rightUp[dim]) > 0.0001)
    {
      MITK_ERROR << "Dicom images have different orientations.";
      throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images.");
    }
  }

  static Vector3D normal;
  normal[0] = leftRight[1] * leftUp[5] - leftRight[2] * leftUp[4];
  normal[1] = leftRight[2] * leftUp[3] - leftRight[0] * leftUp[5];
  normal[2] = leftRight[0] * leftUp[4] - leftRight[1] * leftUp[3];

  static double leftDistance = 0.0;
  static double rightDistance = 0.0;
  leftDistance = 0.0;
  rightDistance = 0.0;

  // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    leftDistance += normal[dim] * leftOrigin[dim];
    rightDistance += normal[dim] * rightOrigin[dim];
  }

  // if we can sort by just comparing the distance, we do exactly that
  if ( fabs(leftDistance - rightDistance) >= mitk::eps)
  {
    // default: compare position
    return leftDistance < rightDistance;
  }
  else
  {
    return this->NextLevelIsLeftBeforeRight(left, right);
  }
}
<commit_msg>Fix image position sorting (formerly: wrong indices used)<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkSortByImagePositionPatient.h"
#include "mitkDICOMTag.h"

mitk::SortByImagePositionPatient
::SortByImagePositionPatient(DICOMSortCriterion::Pointer secondaryCriterion)
:DICOMSortCriterion(secondaryCriterion)
{
}

mitk::SortByImagePositionPatient
::~SortByImagePositionPatient()
{
}

mitk::SortByImagePositionPatient
::SortByImagePositionPatient(const SortByImagePositionPatient& other )
:DICOMSortCriterion(other)
{
}

mitk::SortByImagePositionPatient&
mitk::SortByImagePositionPatient
::operator=(const SortByImagePositionPatient& other)
{
  if (this != &other)
  {
    DICOMSortCriterion::operator=(other);
  }
  return *this;
}

mitk::DICOMTagList
mitk::SortByImagePositionPatient
::GetTagsOfInterest() const
{
  DICOMTagList tags;
  tags.push_back( DICOMTag(0x0020, 0x0032) ); // ImagePositionPatient
  tags.push_back( DICOMTag(0x0020, 0x0037) ); // ImageOrientationPatient

  return tags;
}

bool
mitk::SortByImagePositionPatient
::IsLeftBeforeRight(const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right) const
{
  // sort by distance to world origin, assuming (almost) equal orientation
  static const DICOMTag tagImagePositionPatient = DICOMTag(0x0020,0x0032); // Image Position (Patient)
  static const DICOMTag    tagImageOrientation = DICOMTag(0x0020, 0x0037); // Image Orientation

  static Vector3D leftRight; leftRight.Fill(0.0);
  static Vector3D leftUp; leftUp.Fill(0.0);
  static bool leftHasOrientation(false);
  DICOMStringToOrientationVectors( left->GetTagValueAsString( tagImageOrientation ),
                                   leftRight, leftUp, leftHasOrientation );

  static Vector3D rightRight; rightRight.Fill(0.0);
  static Vector3D rightUp; rightUp.Fill(0.0);
  static bool rightHasOrientation(false);
  DICOMStringToOrientationVectors( right->GetTagValueAsString( tagImageOrientation ),
                                   rightRight, rightUp, rightHasOrientation );

  static Point3D leftOrigin; leftOrigin.Fill(0.0f);
  static bool leftHasOrigin(false);
  leftOrigin = DICOMStringToPoint3D( left->GetTagValueAsString( tagImagePositionPatient ), leftHasOrigin );

  static Point3D rightOrigin; rightOrigin.Fill(0.0f);
  static bool rightHasOrigin(false);
  rightOrigin = DICOMStringToPoint3D( right->GetTagValueAsString( tagImagePositionPatient ), rightHasOrigin );

  //   we tolerate very small differences in image orientation, since we got to know about
  //   acquisitions where these values change across a single series (7th decimal digit)
  //   (http://bugs.mitk.org/show_bug.cgi?id=12263)
  //   still, we want to check if our assumption of 'almost equal' orientations is valid
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    if (   fabs(leftRight[dim] - rightRight[dim]) > 0.0001
        || fabs(leftUp[dim] - rightUp[dim]) > 0.0001)
    {
      MITK_ERROR << "Dicom images have different orientations.";
      throw std::logic_error("Dicom images have different orientations. Call GetSeries() first to separate images.");
    }
  }

  static Vector3D normal;
  normal[0] = leftRight[1] * leftUp[2] - leftRight[2] * leftUp[1];
  normal[1] = leftRight[2] * leftUp[0] - leftRight[0] * leftUp[2];
  normal[2] = leftRight[0] * leftUp[1] - leftRight[1] * leftUp[0];

  static double leftDistance = 0.0;
  static double rightDistance = 0.0;
  leftDistance = 0.0;
  rightDistance = 0.0;

  // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes
  for (unsigned int dim = 0; dim < 3; ++dim)
  {
    leftDistance += normal[dim] * leftOrigin[dim];
    rightDistance += normal[dim] * rightOrigin[dim];
  }

  // if we can sort by just comparing the distance, we do exactly that
  if ( fabs(leftDistance - rightDistance) >= mitk::eps)
  {
    // default: compare position
    return leftDistance < rightDistance;
  }
  else
  {
    return this->NextLevelIsLeftBeforeRight(left, right);
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2002-2005 The Apache Software Foundation.
 *
 * 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.
 */

/*
 * XSEC
 *
 * XSECCryptoUtils:= Helper crypo utilities that make life easier
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 */

#include <xsec/framework/XSECDefs.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/enc/XSECCryptoUtils.hpp>
#include <xsec/enc/XSECCryptoKeyHMAC.hpp>
#include <xsec/utils/XSECPlatformUtils.hpp>

#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>

XERCES_CPP_NAMESPACE_USE

// --------------------------------------------------------------------------------
//           XKMS Limited-Use Shared Secret handling
// --------------------------------------------------------------------------------

int CleanXKMSPassPhrase(unsigned char * input, int inputLen, safeBuffer &output) {

	int j = 0;
	unsigned char c;
	for (int i = 0; i < inputLen; ++i) {

		c = input[i];

		if (c >= 'A' && c <= 'Z') {
			output[j++] = c - 'A' + 'a';
		}
		else if (c != '\n' && c != '\r' && c != '\t' && c != ' ') {
			output[j++] = c;
		}

	}

	return j;

}

int DSIG_EXPORT CalculateXKMSAuthenticationKey(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSAuthenticationValue};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);
	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding1(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSRevocationCodeIdenfitierEncoding1};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding2(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char tmpBuf[XSEC_MAX_HASH_SIZE];
	int tmpLen = CalculateXKMSRevocationCodeIdentifierEncoding1(input, inputLen, tmpBuf, XSEC_MAX_HASH_SIZE);
	return CalculateXKMSRevocationCodeIdentifierEncoding2From1(tmpBuf, tmpLen, output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding2From1(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSRevocationCodeIdenfitierEncoding2};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	h->hash(input, inputLen);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSKEK(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSKeyEncryption};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

// --------------------------------------------------------------------------------
//           Some Base64 helpers
// --------------------------------------------------------------------------------

XMLCh DSIG_EXPORT * EncodeToBase64XMLCh(unsigned char * input, int inputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);
	unsigned char * output;
	int outputLen = ((4 * inputLen) / 3) + 5;
	XSECnew(output, unsigned char[outputLen]);
	ArrayJanitor<unsigned char> j_output(output);

	b64->encodeInit();
	int j = b64->encode(input, inputLen, output, outputLen - 1);
	j += b64->encodeFinish(&output[j], outputLen - j - 1);

	// Strip any trailing \n\r
	while (j > 0 && (output[j-1] == '\n' || output[j-1] == '\r'))
		j--;

	// Now transcode and get out of here
	output[j] = '\0';
	return XMLString::transcode((char *) output);

}

unsigned int DSIG_EXPORT DecodeFromBase64XMLCh(const XMLCh * input, unsigned char * output, int maxOutputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);

	char * tinput = XMLString::transcode(input);
	ArrayJanitor<char> j_tinput(tinput);

	b64->decodeInit();
	unsigned int j = b64->decode((unsigned char *) tinput, strlen(tinput), output, maxOutputLen - 1);
	j += b64->encodeFinish(&output[j], maxOutputLen - j - 1);

	return j;
}

unsigned int DSIG_EXPORT DecodeFromBase64(const char * input, unsigned char * output, int maxOutputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);

	b64->decodeInit();
	unsigned int j = b64->decode((unsigned char *) input, strlen(input), output, maxOutputLen - 1);
	j += b64->encodeFinish(&output[j], maxOutputLen - j - 1);

	return j;
}

// --------------------------------------------------------------------------------
//           Some stuff to help with wierd signatures
// --------------------------------------------------------------------------------

const unsigned char ASNDSAProlog[] = {0x30, 0x2c, 0x02, 0x14};
const unsigned char ASNDSAMiddle[] = {0x02, 0x14};

bool ASN2DSASig(const unsigned char * input, unsigned char * r, unsigned char * s) {

	if (memcmp(ASNDSAProlog, input, 4) != 0 ||
		memcmp(ASNDSAMiddle, &input[24], 2) != 0)

		return false;

	memcpy(r, &input[4], 20);
	memcpy(s, &input[26], 20);

	return true;

}

<commit_msg>Helps if you don't use encode calls when doing base64 decoding...<commit_after>/*
 * Copyright 2002-2005 The Apache Software Foundation.
 *
 * 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.
 */

/*
 * XSEC
 *
 * XSECCryptoUtils:= Helper crypo utilities that make life easier
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 */

#include <xsec/framework/XSECDefs.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/enc/XSECCryptoUtils.hpp>
#include <xsec/enc/XSECCryptoKeyHMAC.hpp>
#include <xsec/utils/XSECPlatformUtils.hpp>

#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>

XERCES_CPP_NAMESPACE_USE

// --------------------------------------------------------------------------------
//           XKMS Limited-Use Shared Secret handling
// --------------------------------------------------------------------------------

int CleanXKMSPassPhrase(unsigned char * input, int inputLen, safeBuffer &output) {

	int j = 0;
	unsigned char c;
	for (int i = 0; i < inputLen; ++i) {

		c = input[i];

		if (c >= 'A' && c <= 'Z') {
			output[j++] = c - 'A' + 'a';
		}
		else if (c != '\n' && c != '\r' && c != '\t' && c != ' ') {
			output[j++] = c;
		}

	}

	return j;

}

int DSIG_EXPORT CalculateXKMSAuthenticationKey(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSAuthenticationValue};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);
	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding1(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSRevocationCodeIdenfitierEncoding1};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding2(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char tmpBuf[XSEC_MAX_HASH_SIZE];
	int tmpLen = CalculateXKMSRevocationCodeIdentifierEncoding1(input, inputLen, tmpBuf, XSEC_MAX_HASH_SIZE);
	return CalculateXKMSRevocationCodeIdentifierEncoding2From1(tmpBuf, tmpLen, output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSRevocationCodeIdentifierEncoding2From1(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSRevocationCodeIdenfitierEncoding2};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	Janitor<XSECCryptoKeyHMAC> j_k(k);
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	h->hash(input, inputLen);
	return h->finish(output, maxOutputLen);

}

int DSIG_EXPORT CalculateXKMSKEK(unsigned char * input, int inputLen, unsigned char * output, int maxOutputLen) {

	unsigned char keyVal[] = {XKMSKeyEncryption};

	XSECCryptoKeyHMAC * k = XSECPlatformUtils::g_cryptoProvider->keyHMAC();
	k->setKey(keyVal, 1);

	XSECCryptoHash *h = XSECPlatformUtils::g_cryptoProvider->hashHMACSHA1();
	Janitor<XSECCryptoHash> j_h(h);

	h->setKey(k);

	// Clean the input
	safeBuffer sb;
	int l = CleanXKMSPassPhrase(input, inputLen, sb);

	h->hash((unsigned char *) sb.rawBuffer(), l);
	return h->finish(output, maxOutputLen);

}

// --------------------------------------------------------------------------------
//           Some Base64 helpers
// --------------------------------------------------------------------------------

XMLCh DSIG_EXPORT * EncodeToBase64XMLCh(unsigned char * input, int inputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);
	unsigned char * output;
	int outputLen = ((4 * inputLen) / 3) + 5;
	XSECnew(output, unsigned char[outputLen]);
	ArrayJanitor<unsigned char> j_output(output);

	b64->encodeInit();
	int j = b64->encode(input, inputLen, output, outputLen - 1);
	j += b64->encodeFinish(&output[j], outputLen - j - 1);

	// Strip any trailing \n\r
	while (j > 0 && (output[j-1] == '\n' || output[j-1] == '\r'))
		j--;

	// Now transcode and get out of here
	output[j] = '\0';
	return XMLString::transcode((char *) output);

}

unsigned int DSIG_EXPORT DecodeFromBase64XMLCh(const XMLCh * input, unsigned char * output, int maxOutputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);

	char * tinput = XMLString::transcode(input);
	ArrayJanitor<char> j_tinput(tinput);

	b64->decodeInit();
	unsigned int j = b64->decode((unsigned char *) tinput, strlen(tinput), output, maxOutputLen - 1);
	j += b64->decodeFinish(&output[j], maxOutputLen - j - 1);

	return j;
}

unsigned int DSIG_EXPORT DecodeFromBase64(const char * input, unsigned char * output, int maxOutputLen) {

	XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64();
	Janitor<XSECCryptoBase64> j_b64(b64);

	b64->decodeInit();
	unsigned int j = b64->decode((unsigned char *) input, strlen(input), output, maxOutputLen - 1);
	j += b64->decodeFinish(&output[j], maxOutputLen - j - 1);

	return j;
}

// --------------------------------------------------------------------------------
//           Some stuff to help with wierd signatures
// --------------------------------------------------------------------------------

const unsigned char ASNDSAProlog[] = {0x30, 0x2c, 0x02, 0x14};
const unsigned char ASNDSAMiddle[] = {0x02, 0x14};

bool ASN2DSASig(const unsigned char * input, unsigned char * r, unsigned char * s) {

	if (memcmp(ASNDSAProlog, input, 4) != 0 ||
		memcmp(ASNDSAMiddle, &input[24], 2) != 0)

		return false;

	memcpy(r, &input[4], 20);
	memcpy(s, &input[26], 20);

	return true;

}

<|endoftext|>


<commit_before>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * 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.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */
#include "GcScanProcessor.hpp"

#include "ChainedVersionRecord.hpp"
#include "LogstructuredMemoryStore.hpp"
#include "Table.hpp"
#include "VersionRecordIterator.hpp"

#include <crossbow/logger.hpp>

#include <boost/config.hpp>

namespace tell {
namespace store {
namespace logstructured {
namespace {

/**
 * @brief Utilization threshold when to recycle a page in percent
 */
constexpr size_t gGcThreshold = 50;

} // anonymous namespace

std::vector<GcScanProcessor> GcScanProcessor::startScan(Table& table, size_t numThreads, const char* queryBuffer,
        const std::vector<ScanQuery*>& queries) {
    if (numThreads == 0) {
        return {};
    }

    std::vector<GcScanProcessor> result;
    result.reserve(numThreads);

    auto version = table.minVersion();
    auto& log = table.mLog;

    auto numPages = log.pages();
    auto begin = log.pageBegin();
    auto end = log.pageEnd();

    auto mod = numPages % numThreads;
    auto iter = begin;
    for (decltype(numThreads) i = 1; i < numThreads; ++i) {
        auto step = numPages / numThreads + (i < mod ? 1 : 0);
        // Increment the page iterator by step pages (but not beyond the end page)
        for (decltype(step) j = 0; j < step && iter != end; ++j, ++iter) {
        }

        result.emplace_back(table, begin, iter, queryBuffer, queries, version);
        begin = iter;
    }

    // The last scan takes the remaining pages
    result.emplace_back(table, begin, end, queryBuffer, queries, version);

    return result;
}

GcScanProcessor::GcScanProcessor(Table& table, const LogImpl::PageIterator& begin, const LogImpl::PageIterator& end,
        const char* queryBuffer, const std::vector<ScanQuery*>& queryData, uint64_t minVersion)
        : mTable(table),
          mQueries(queryBuffer, queryData),
          mMinVersion(minVersion),
          mPagePrev(begin),
          mPageIt(begin),
          mPageEnd(end),
          mEntryIt(mPageIt == mPageEnd ? LogPage::EntryIterator() : mPageIt->begin()),
          mEntryEnd(mPageIt == mPageEnd ? LogPage::EntryIterator() : mPageIt->end()),
          mRecyclingHead(nullptr),
          mRecyclingTail(nullptr),
          mGarbage(0x0u),
          mSealed(false),
          mRecycle(false) {
}

GcScanProcessor::GcScanProcessor(GcScanProcessor&& other)
        : mTable(other.mTable),
          mQueries(std::move(other.mQueries)),
          mMinVersion(other.mMinVersion),
          mPagePrev(std::move(other.mPagePrev)),
          mPageIt(std::move(other.mPageIt)),
          mPageEnd(std::move(other.mPageEnd)),
          mEntryIt(std::move(other.mEntryIt)),
          mEntryEnd(std::move(other.mEntryEnd)),
          mRecyclingHead(other.mRecyclingHead),
          mRecyclingTail(other.mRecyclingTail),
          mGarbage(other.mGarbage),
          mSealed(other.mSealed),
          mRecycle(other.mRecycle) {
    other.mRecyclingHead = nullptr;
    other.mRecyclingTail = nullptr;
    other.mGarbage = 0x0u;
    other.mSealed = false;
    other.mRecycle = false;
}

void GcScanProcessor::process() {
    // Abort if the processor already is at the end
    if (mPageIt == mPageEnd) {
        return;
    }

    // Advance to the next page if the first page contains no entries
    if (mEntryIt == mEntryEnd && !advancePage()) {
        return;
    }

    do {
        if (BOOST_UNLIKELY(!mEntryIt->sealed())) {
            LOG_ASSERT(!mRecycle, "Recycling page even though not all entries are sealed");
            mSealed = false;
            continue;
        }
        LOG_ASSERT(mEntryIt->size() >= sizeof(ChainedVersionRecord), "Log record is smaller than record header");

        auto record = reinterpret_cast<ChainedVersionRecord*>(mEntryIt->data());

        auto context = record->mutableData();
        if (context.isInvalid()) {
            // The element is already marked as invalid - Increase the garbage counter
            mGarbage += mEntryIt->entrySize();
            continue;
        }

        auto type = crossbow::from_underlying<VersionRecordType>(mEntryIt->type());
        if (context.validTo() <= mMinVersion) {
            // No version can read the current element - Mark it as invalid and increase the garbage counter
#ifdef NDEBUG
            record->invalidate();
#else
            auto res = record->tryInvalidate(context, nullptr);
            LOG_ASSERT(res, "Invalidating expired element failed");
#endif
            mGarbage += mEntryIt->entrySize();
            continue;
        } else if ((type == VersionRecordType::DELETION) && (record->validFrom() <= mMinVersion)) {
            // Try to mark the deletion as invalid and set the next pointer to null
            // This basically truncates the version list and marks the deletion entry as deleted in the version history
            // Because the entry is still alive (i.e. can be accessed by other transactions) we have to use a CAS to
            // invalidate the entry
            if (!record->tryInvalidate(context, nullptr)) {
                continue;
            }
            mGarbage += mEntryIt->entrySize();

            // Iterate over the whole version list for this key, this ensures the removal of the invalid deletion entry
            for (VersionRecordIterator recIter(mTable, record->key()); !recIter.done(); recIter.next()) {
            }
            continue;
        }

        if (mRecycle) {
            recycleEntry(record, mEntryIt->size(), mEntryIt->type());
        }

        // Skip the element if it is not a data entry (i.e. deletion)
        if (type != VersionRecordType::DATA) {
            continue;
        }

        // Process the element
        auto recordLength = mEntryIt->size() - sizeof(ChainedVersionRecord);
        mQueries.processRecord(mTable.record(), record->key(), record->data(), recordLength, record->validFrom(),
                context.validTo());
    } while (advanceEntry());

    // Append recycled entries to the log
    if (mRecyclingHead != nullptr) {
        LOG_ASSERT(mRecyclingTail, "Recycling tail is null despite head being non null");
        mTable.mLog.appendPage(mRecyclingHead, mRecyclingTail);
    }
}

bool GcScanProcessor::advanceEntry() {
    // Advance the iterator to the next entry
    if (++mEntryIt != mEntryEnd) {
        return true;
    }

    // Advance to next page
    return advancePage();
}

bool GcScanProcessor::advancePage() {
    do {
        // Advance to next page
        if (mRecycle) {
            ++mPageIt;
            mTable.mLog.erase(mPagePrev.operator->(), mPageIt.operator->());
        } else {
            // Only store the garbage statistic when every entry in the page was sealed
            if (mSealed) {
                mPageIt->context().store(mGarbage);
            }
            mPagePrev = mPageIt++;
        }

        if (mPageIt == mPageEnd) {
            return false;
        }
        mEntryIt = mPageIt->begin();
        mEntryEnd = mPageIt->end();

        // Retrieve usage statistics of the current page
        mGarbage = 0x0u;
        uint32_t offset;
        std::tie(offset, mSealed) = mPageIt->offsetAndSealed();
        auto currentGarbage = mPageIt->context().load();
        auto size = (currentGarbage >= offset ? 0u : offset - currentGarbage);
        mRecycle = (mSealed && ((size * 100) / LogPage::MAX_DATA_SIZE < gGcThreshold));
    } while (mEntryIt == mEntryEnd);

    return true;
}

void GcScanProcessor::recycleEntry(ChainedVersionRecord* oldElement, uint32_t size, uint32_t type) {
    if (mRecyclingHead == nullptr) {
        mRecyclingHead = mTable.mLog.acquirePage();
        if (mRecyclingHead == nullptr) {
            LOG_ERROR("PageManager ran out of space");
            mRecycle = false;
            return;
        }
        mRecyclingTail = mRecyclingHead;
    }

    auto newEntry = mRecyclingHead->append(size, type);
    if (newEntry == nullptr) {
        auto newHead = mTable.mLog.acquirePage();
        if (newHead == nullptr) {
            LOG_ERROR("PageManager ran out of space");
            mRecycle = false;
            return;
        }
        newHead->next().store(mRecyclingHead);
        mRecyclingHead->seal();
        mRecyclingHead = newHead;
        newEntry = mRecyclingHead->append(size, type);
        LOG_ASSERT(newEntry, "Unable to allocate entry on fresh page");
    }

    auto newElement = new (newEntry->data()) ChainedVersionRecord(oldElement->key(), oldElement->validFrom());
    memcpy(newElement->data(), oldElement->data(), size - sizeof(ChainedVersionRecord));

    if (!replaceElement(oldElement, newElement)) {
        newElement->invalidate();
    }

    newEntry->seal();
}

bool GcScanProcessor::replaceElement(ChainedVersionRecord* oldElement, ChainedVersionRecord* newElement) {
    LOG_ASSERT(oldElement->key() == newElement->key(), "Keys do not match");

    // Search for the old element in the version list - if it was not found it has to be invalidated by somebody else
    VersionRecordIterator recIter(mTable, oldElement->key());
    if (!recIter.find(oldElement)) {
        LOG_ASSERT(oldElement->mutableData().isInvalid(), "Old element not in version list but not invalid");
        return false;
    }

    // Replace can fail because the next pointer or validTo version of the current element has changed or it was
    // invalidated by someone else - if it was invalidated then the iterator will point to a different element
    while (!recIter.replace(newElement)) {
        if (recIter.value() != oldElement) {
            LOG_ASSERT(oldElement->mutableData().isInvalid(), "Old element not in version list but not invalid");
            return false;
        }
    }

    // A successful replace only guarantees that the old element was invalidated (and replaced with the new element) but
    // the old element could still be in the version list - Traverse the iterator until the new element is reached (this
    // ensures all previous elements were valid at some time and we can safely reuse the memory of the old element)
    if (!recIter.find(newElement)) {
        LOG_ASSERT(newElement->mutableData().isInvalid(), "New element not in version list but not invalid");
    }
    return true;
}

void GcScanGarbageCollector::run(const std::vector<Table*>& tables, uint64_t /* minVersion */) {
    for (auto i : tables) {
        LOG_TRACE("Starting garbage collection on table %1%", i->id());
        if (!mStorage.scan(i->id(), nullptr)) {
            LOG_ERROR("Unable to start Garbage Collection scan");
            return;
        }
    }
}

} // namespace logstructured
} // namespace store
} // namespace tell
<commit_msg>Fix false error message<commit_after>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * 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.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */
#include "GcScanProcessor.hpp"

#include "ChainedVersionRecord.hpp"
#include "LogstructuredMemoryStore.hpp"
#include "Table.hpp"
#include "VersionRecordIterator.hpp"

#include <crossbow/logger.hpp>

#include <boost/config.hpp>

namespace tell {
namespace store {
namespace logstructured {
namespace {

/**
 * @brief Utilization threshold when to recycle a page in percent
 */
constexpr size_t gGcThreshold = 50;

} // anonymous namespace

std::vector<GcScanProcessor> GcScanProcessor::startScan(Table& table, size_t numThreads, const char* queryBuffer,
        const std::vector<ScanQuery*>& queries) {
    if (numThreads == 0) {
        return {};
    }

    std::vector<GcScanProcessor> result;
    result.reserve(numThreads);

    auto version = table.minVersion();
    auto& log = table.mLog;

    auto numPages = log.pages();
    auto begin = log.pageBegin();
    auto end = log.pageEnd();

    auto mod = numPages % numThreads;
    auto iter = begin;
    for (decltype(numThreads) i = 1; i < numThreads; ++i) {
        auto step = numPages / numThreads + (i < mod ? 1 : 0);
        // Increment the page iterator by step pages (but not beyond the end page)
        for (decltype(step) j = 0; j < step && iter != end; ++j, ++iter) {
        }

        result.emplace_back(table, begin, iter, queryBuffer, queries, version);
        begin = iter;
    }

    // The last scan takes the remaining pages
    result.emplace_back(table, begin, end, queryBuffer, queries, version);

    return result;
}

GcScanProcessor::GcScanProcessor(Table& table, const LogImpl::PageIterator& begin, const LogImpl::PageIterator& end,
        const char* queryBuffer, const std::vector<ScanQuery*>& queryData, uint64_t minVersion)
        : mTable(table),
          mQueries(queryBuffer, queryData),
          mMinVersion(minVersion),
          mPagePrev(begin),
          mPageIt(begin),
          mPageEnd(end),
          mEntryIt(mPageIt == mPageEnd ? LogPage::EntryIterator() : mPageIt->begin()),
          mEntryEnd(mPageIt == mPageEnd ? LogPage::EntryIterator() : mPageIt->end()),
          mRecyclingHead(nullptr),
          mRecyclingTail(nullptr),
          mGarbage(0x0u),
          mSealed(false),
          mRecycle(false) {
}

GcScanProcessor::GcScanProcessor(GcScanProcessor&& other)
        : mTable(other.mTable),
          mQueries(std::move(other.mQueries)),
          mMinVersion(other.mMinVersion),
          mPagePrev(std::move(other.mPagePrev)),
          mPageIt(std::move(other.mPageIt)),
          mPageEnd(std::move(other.mPageEnd)),
          mEntryIt(std::move(other.mEntryIt)),
          mEntryEnd(std::move(other.mEntryEnd)),
          mRecyclingHead(other.mRecyclingHead),
          mRecyclingTail(other.mRecyclingTail),
          mGarbage(other.mGarbage),
          mSealed(other.mSealed),
          mRecycle(other.mRecycle) {
    other.mRecyclingHead = nullptr;
    other.mRecyclingTail = nullptr;
    other.mGarbage = 0x0u;
    other.mSealed = false;
    other.mRecycle = false;
}

void GcScanProcessor::process() {
    // Abort if the processor already is at the end
    if (mPageIt == mPageEnd) {
        return;
    }

    // Advance to the next page if the first page contains no entries
    if (mEntryIt == mEntryEnd && !advancePage()) {
        return;
    }

    do {
        if (BOOST_UNLIKELY(!mEntryIt->sealed())) {
            LOG_ASSERT(!mRecycle, "Recycling page even though not all entries are sealed");
            mSealed = false;
            continue;
        }
        LOG_ASSERT(mEntryIt->size() >= sizeof(ChainedVersionRecord), "Log record is smaller than record header");

        auto record = reinterpret_cast<ChainedVersionRecord*>(mEntryIt->data());

        auto context = record->mutableData();
        if (context.isInvalid()) {
            // The element is already marked as invalid - Increase the garbage counter
            mGarbage += mEntryIt->entrySize();
            continue;
        }

        auto type = crossbow::from_underlying<VersionRecordType>(mEntryIt->type());
        if (context.validTo() <= mMinVersion) {
            // No version can read the current element - Mark it as invalid and increase the garbage counter
#ifdef NDEBUG
            record->invalidate();
#else
            auto res = record->tryInvalidate(context, nullptr);
            LOG_ASSERT(res, "Invalidating expired element failed");
#endif
            mGarbage += mEntryIt->entrySize();
            continue;
        } else if ((type == VersionRecordType::DELETION) && (record->validFrom() <= mMinVersion)) {
            // Try to mark the deletion as invalid and set the next pointer to null
            // This basically truncates the version list and marks the deletion entry as deleted in the version history
            // Because the entry is still alive (i.e. can be accessed by other transactions) we have to use a CAS to
            // invalidate the entry
            if (!record->tryInvalidate(context, nullptr)) {
                continue;
            }
            mGarbage += mEntryIt->entrySize();

            // Iterate over the whole version list for this key, this ensures the removal of the invalid deletion entry
            for (VersionRecordIterator recIter(mTable, record->key()); !recIter.done(); recIter.next()) {
            }
            continue;
        }

        if (mRecycle) {
            recycleEntry(record, mEntryIt->size(), mEntryIt->type());
        }

        // Skip the element if it is not a data entry (i.e. deletion)
        if (type != VersionRecordType::DATA) {
            continue;
        }

        // Process the element
        auto recordLength = mEntryIt->size() - sizeof(ChainedVersionRecord);
        mQueries.processRecord(mTable.record(), record->key(), record->data(), recordLength, record->validFrom(),
                context.validTo());
    } while (advanceEntry());

    // Append recycled entries to the log
    if (mRecyclingHead != nullptr) {
        LOG_ASSERT(mRecyclingTail, "Recycling tail is null despite head being non null");
        mTable.mLog.appendPage(mRecyclingHead, mRecyclingTail);
    }
}

bool GcScanProcessor::advanceEntry() {
    // Advance the iterator to the next entry
    if (++mEntryIt != mEntryEnd) {
        return true;
    }

    // Advance to next page
    return advancePage();
}

bool GcScanProcessor::advancePage() {
    do {
        // Advance to next page
        if (mRecycle) {
            ++mPageIt;
            mTable.mLog.erase(mPagePrev.operator->(), mPageIt.operator->());
        } else {
            // Only store the garbage statistic when every entry in the page was sealed
            if (mSealed) {
                mPageIt->context().store(mGarbage);
            }
            mPagePrev = mPageIt++;
        }

        if (mPageIt == mPageEnd) {
            return false;
        }
        mEntryIt = mPageIt->begin();
        mEntryEnd = mPageIt->end();

        // Retrieve usage statistics of the current page
        mGarbage = 0x0u;
        uint32_t offset;
        std::tie(offset, mSealed) = mPageIt->offsetAndSealed();
        auto currentGarbage = mPageIt->context().load();
        auto size = (currentGarbage >= offset ? 0u : offset - currentGarbage);
        mRecycle = (mSealed && ((size * 100) / LogPage::MAX_DATA_SIZE < gGcThreshold));
    } while (mEntryIt == mEntryEnd);

    return true;
}

void GcScanProcessor::recycleEntry(ChainedVersionRecord* oldElement, uint32_t size, uint32_t type) {
    if (mRecyclingHead == nullptr) {
        mRecyclingHead = mTable.mLog.acquirePage();
        if (mRecyclingHead == nullptr) {
            LOG_ERROR("PageManager ran out of space");
            mRecycle = false;
            return;
        }
        mRecyclingTail = mRecyclingHead;
    }

    auto newEntry = mRecyclingHead->append(size, type);
    if (newEntry == nullptr) {
        auto newHead = mTable.mLog.acquirePage();
        if (newHead == nullptr) {
            LOG_ERROR("PageManager ran out of space");
            mRecycle = false;
            return;
        }
        newHead->next().store(mRecyclingHead);
        mRecyclingHead->seal();
        mRecyclingHead = newHead;
        newEntry = mRecyclingHead->append(size, type);
        LOG_ASSERT(newEntry, "Unable to allocate entry on fresh page");
    }

    auto newElement = new (newEntry->data()) ChainedVersionRecord(oldElement->key(), oldElement->validFrom());
    memcpy(newElement->data(), oldElement->data(), size - sizeof(ChainedVersionRecord));

    if (!replaceElement(oldElement, newElement)) {
        newElement->invalidate();
    }

    newEntry->seal();
}

bool GcScanProcessor::replaceElement(ChainedVersionRecord* oldElement, ChainedVersionRecord* newElement) {
    LOG_ASSERT(oldElement->key() == newElement->key(), "Keys do not match");

    // Search for the old element in the version list - if it was not found it has to be invalidated by somebody else
    VersionRecordIterator recIter(mTable, oldElement->key());
    if (!recIter.find(oldElement)) {
        LOG_ASSERT(oldElement->mutableData().isInvalid(), "Old element not in version list but not invalid");
        return false;
    }

    // Replace can fail because the next pointer or validTo version of the current element has changed or it was
    // invalidated by someone else - if it was invalidated then the iterator will point to a different element
    while (!recIter.replace(newElement)) {
        if (recIter.value() != oldElement) {
            LOG_ASSERT(oldElement->mutableData().isInvalid(), "Old element not in version list but not invalid");
            return false;
        }
    }

    // A successful replace only guarantees that the old element was invalidated (and replaced with the new element) but
    // the old element could still be in the version list - Traverse the iterator until the new element is reached (this
    // ensures all previous elements were valid at some time and we can safely reuse the memory of the old element)
    if (!recIter.find(newElement)) {
        LOG_ASSERT(newElement->mutableData().isInvalid(), "New element not in version list but not invalid");
    }
    return true;
}

void GcScanGarbageCollector::run(const std::vector<Table*>& tables, uint64_t /* minVersion */) {
    for (auto i : tables) {
        LOG_TRACE("Starting garbage collection on table %1%", i->id());
        if (mStorage.scan(i->id(), nullptr)) {
            LOG_ERROR("Unable to start Garbage Collection scan");
            return;
        }
    }
}

} // namespace logstructured
} // namespace store
} // namespace tell
<|endoftext|>