<commit_before>/**
 * @file
 * @author Jason Lingle
 *
 * @brief Implementation of explosion_pool.hxx
 */

#include <GL/gl.h>
#include <vector>
#include <deque>
#include <cmath>
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstring>

#include "explosion_pool.hxx"
#include "explosion.hxx"
#include "old_style_explosion.hxx"
#include "src/globals.hxx"
#include "src/opto_flags.hxx"
#include "src/fasttrig.hxx"
#include "src/sim/game_field.hxx"
#include "src/graphics/vec.hxx"
#include "src/graphics/matops.hxx"
#include "src/graphics/glhelp.hxx"
#include "src/graphics/shader.hxx"
#include "src/graphics/shader_loader.hxx"
#include "src/graphics/cmn_shaders.hxx"
#include "src/camera/effects_handler.hxx"

//Our debugging with FPE exceptions leads to problems with
//the use of uninitialised values in the arrays, so we'll need
//to temporarily disable the exceptions during update
#if !defined(WIN32) && defined(DEBUG)
#include </usr/include/fenv.h>
#endif

using namespace std;

#define MAX_EXPLOSIONS_DRAWN 3000

static int numExDrawn;

static GLuint vao, vbo;

struct ExplosionUniform {
  float ex, ey;
  float elapsedTime, sizeAt1Sec, density;
  unsigned id;
  vec4 colour;
};

#ifndef AB_OPENGL_14
namespace shader {
  #define VERTEX_TYPE shader::Vert2
  #define UNIFORM_TYPE ::ExplosionUniform
  DELAY_SHADER(simpleExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static simpleEx);

  DELAY_SHADER(sparkExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static spark);

  DELAY_SHADER(bigSparkExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static bigSpark);

  DELAY_SHADER(sparkleExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static sparkle);

  DELAY_SHADER(incursionExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static incursion);

  DELAY_SHADER(flameExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static flame);
}

static const Shader* shaders[6];
#endif /* AB_OPENGL_14 */

ExplosionPoolSegment::ExplosionPoolSegment() {
  freeCount=EXPLOSIONS_PER_SEGMENT;
  for (unsigned int i=0; i<sizeof(usage)/sizeof(unsigned int); ++i)
    usage[i]=0;
  //Set everything in the time stripe to infinity
  float a=0;
  float infinity=INFINITY; //1.0f/a;
  for (unsigned i=0; i<lenof(timeStripe); i+=2) timeStripe[i]=infinity;
}

ExplosionPoolSegment::~ExplosionPoolSegment() {
}

inline void ExplosionPoolSegment::update(float et) noth {
  //First, update sizes
  //We don't care whether anything is in use,
  //because it'd take longer to check than
  //to just do the calculations
  float* ptr=coordStripe;
  float* end=ptr+EXPLOSIONS_PER_SEGMENT*EX_VLEN;
  while (ptr<end) {
    *ptr += (*(ptr+1))*et;
    ptr += 2;
  }

  //Now go through times.
  //If any time is too high, unset the usage bit
  unsigned int* usage=this->usage;
  unsigned int mask=1;
  GLfloat (*colours)[4]=this->colours;
  ptr=timeStripe;
  end=ptr+EXPLOSIONS_PER_SEGMENT*EX_TLEN;
  while (ptr<end) {
    //This line triggers a warning from Valgrind
    //That is OK, this was designed to crunch
    //through uninitialized values
    *ptr-=et;
    if (*ptr < 0) {
      //The time has expired, mark free
      *usage &= ~mask;
      ++freeCount;
      //Make ptr infinite
      float a=0;
      *ptr = 1/a;
    }
    (*colours)[3] = (*ptr / *(ptr+1));
    mask<<=1;
    //If we are 0, we have gone through
    //all 64 or 32 bits
    if (mask==0) {
      ++usage;
      mask=1;
    }
    ptr+=2;
    ++colours;
  }
}

#define GETX(i) coordStripe[EX_X_OFF + ((i)*EX_VLEN)]
#define GETY(i) coordStripe[EX_Y_OFF + ((i)*EX_VLEN)]
#define GETET(i) timeStripe[EX_ET_OFF + ((i)*EX_TLEN)]
#define GETLT(i) timeStripe[EX_LT_OFF + ((i)*EX_TLEN)]

ExplosionPool::ExplosionPool()
{
  static bool hasVAO=false;
#ifndef AB_OPENGL_14
  if (!hasVAO && !headless) {
    static const shader::Vert2 vertices[4] = {
      {{{-1,+1}}},
      {{{-1,-1}}},
      {{{+1,+1}}},
      {{{+1,-1}}},
    };

    vao=newVAO();
    glBindVertexArray(vao);
    vbo=newVBO();
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    shader::spark->setupVBO();

    shaders[Explosion::Simple   ] = shader::simpleEx .operator->();
    shaders[Explosion::Spark    ] = shader::spark    .operator->();
    shaders[Explosion::BigSpark ] = shader::bigSpark .operator->();
    shaders[Explosion::Sparkle  ] = shader::sparkle  .operator->();
    shaders[Explosion::Incursion] = shader::incursion.operator->();
    shaders[Explosion::Flame    ] = shader::flame    .operator->();
  }
#endif /* AB_OPENGL_14 */
}

void ExplosionPoolSegment::draw() noth {
#ifndef AB_OPENGL_14
  ExplosionUniform uni;
  //We can afford to be a bit more sane because this is called less often
  //and the majority of the grunt work is handled by GL
  for (unsigned int i=0; i<EXPLOSIONS_PER_SEGMENT; ++i) {
    if (usage[i/sizeof(unsigned int)/8] & (1 << (i%(sizeof(unsigned int)*8)))) {
      if (++numExDrawn >= MAX_EXPLOSIONS_DRAWN && (rand()&1)) continue;
      uni.ex = coordStripe[i*EX_VLEN + EX_X_OFF];
      uni.ey = coordStripe[i*EX_VLEN + EX_Y_OFF];
      uni.elapsedTime = (timeStripe[i*EX_TLEN + EX_LT_OFF] - timeStripe[i*EX_TLEN + EX_ET_OFF])/1000;
      uni.sizeAt1Sec = sizes[i];
      uni.density = densities[i];
      GLfloat red=colours[i][0], green=colours[i][1], blue=colours[i][2], alpha=colours[i][3];
      //Somewhat realistic (looking) blackbody radiation:
      //Blue and green fade out earlier
      blue *= (alpha>0.25? (alpha-0.25f)/0.75f : 0);
      green *= alpha;
      uni.colour = Vec4(red,green,blue,alpha);
      uni.id=i+1;
      shaders[types[i]]->activate(&uni);
      #ifndef AB_OPENGL_21
      glDrawArrays(GL_POINTS, 0, 1); //The actual vertex is ignored
      #else
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
      #endif
    }
  }
#endif /* AB_OPENGL_14 */
}

ExplosionPool::~ExplosionPool() {
  for (unsigned int i=0; i<segments.size(); ++i)
    delete segments[i];
}

void ExplosionPool::update(float et) noth {
  #if defined(DEBUG) && !defined(WIN32)
  assert(-1 != fedisableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID));
  #endif

  for (unsigned i=0; i<hungryExplosions.size(); ++i)
    if (!--hungryExplosions[i].framesLeft)
      hungryExplosions.erase(hungryExplosions.begin() + (i--));

  for (unsigned int i=0; i<segments.size(); ++i)
    segments[i]->update(et);

  ++segmentGCCounter;
  //Disabled for now. It may have been causeing performance issues, since
  //the buffers are naturally rolled through.
  if (segmentGCCounter==0 && false) {
    //Kill any segment that is completely empty, other than the first
    for (unsigned int i=1; i<segments.size(); ++i) {
      for (unsigned int j=0; j<sizeof(segments[i]->usage)/sizeof(unsigned int); ++j)
        if (segments[i]->usage[j]) goto used;

      //Unused if we get here
      delete segments[i];
      segments.erase(segments.begin() + i);
      --i;
      continue;

      used:;
    }
  }

  #if defined(DEBUG) && !defined(WIN32)
  assert(-1 != feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID));
  #endif
}

void ExplosionPool::draw() noth {
#ifndef AB_OPENGL_14
  BEGINGP("ExplosionPool")
  numExDrawn=0;
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  for (unsigned int i=0; i<segments.size(); ++i)
    segments[i]->draw();
  ENDGP
#endif /* AB_OPENGL_14 */
}

/* I put these in separate functions for profiling.
 * Anyway, even in debug mode where they are not inlined,
 * three function calls shouldn't be too much of a penalty.
 */
#ifdef PROFILE
#define inline
#endif
inline void ExplosionPool::findFreeSegment(ExplosionPoolSegment*& segment, int& block, int& bit, int& index,
                                           vector<ExplosionPoolSegment*>& segments) noth {
  for (unsigned int i=0; i<segments.size(); ++i) {
    if (segments[i]->freeCount) {
      for (unsigned int j=0; j<sizeof(segments[i]->usage)/sizeof(unsigned int); ++j) {
        if (~segments[i]->usage[j]) {
          segment=segments[i];
          block=j;
          for (unsigned int k=0; k<sizeof(unsigned int)*8; ++k) {
            if (! (segment->usage[block] & (1 << k)) ) {
              bit=k;
              index=bit + block*sizeof(unsigned int)*8;
              return;
            }
          }
        }
      }
    }
  }

  //Not found, allocate new segment
  segments.push_back(segment=new ExplosionPoolSegment);
  block=0;
  index=0;
  bit=0;
}

void ExplosionPool::add(Explosion* ex) noth {
#ifdef AB_OPENGL_14
  delete ex;
  return;
#else
  if (headless) {
    delete ex;
    return;
  }

  ex->getField()->effects->explode(ex);

  if (ex->type == Explosion::Invisible) {
    delete ex;
    return;
  }

  //See if it is to be dropped
  for (unsigned i=0; i<hungryExplosions.size(); ++i) {
    if (hungryExplosions[i].type == ex->type
    &&  hungryExplosions[i].minX <= ex->x
    &&  hungryExplosions[i].maxX >  ex->x
    &&  hungryExplosions[i].minY <= ex->y
    &&  hungryExplosions[i].maxY >  ex->y) {
      //Drop
      delete ex;
      return;
    }
  }

  if (ex->hungry) {
    HungryExplosion he = {ex->type, ex->x-0.05f, ex->x+0.05f, ex->y-0.05f, ex->y+0.5f, 8};
    hungryExplosions.push_back(he);
  }

  /* Possibly redirect to old-style explosion */
  if (ex->type == Explosion::BigSpark
  &&  conf["shaders"][isLSDModeForced()? "lsd" :
                      (const char*)conf["conf"]["graphics"]["shader_profile"]]["redirect_big_spark_explosion"]) {
    ex->field->add(new OldStyleExplosion(ex));
    delete ex;
    return;
  }

  //Find a free item
  ExplosionPoolSegment* segment;
  int block, bit, index;
  findFreeSegment(segment, block, bit, index, segments);

  //Copy parms
  float* coords=segment->coordStripe+index*EX_VLEN;
  *(coords+EX_X_OFF)=ex->x;
  *(coords+EX_Y_OFF)=ex->y;
  *(coords+EX_VX_OFF)=ex->vx;
  *(coords+EX_VY_OFF)=ex->vy;
  float* times=segment->timeStripe+index*EX_TLEN;
  *(times+EX_ET_OFF)=ex->lifetime;
  *(times+EX_LT_OFF)=ex->lifetime;

  segment->colours[index][0]=ex->colour[0];
  segment->colours[index][1]=ex->colour[1];
  segment->colours[index][2]=ex->colour[2];
  segment->colours[index][3]=1; //full alpha at beginning

  segment->types[index] = ex->type;
  segment->sizes[index] = ex->sizeAt1Sec;
  segment->densities[index] = ex->density;

  //Mark used
  segment->usage[block] |= (1 << bit);
  --segment->freeCount;

  //We don't want the Explosion anymore
  delete ex;
#endif /* !defined(AB_OPENGL_14) */
}

<commit_msg>Remove unused variable a in ExplosionPoolSegment constructor.<commit_after>/**
 * @file
 * @author Jason Lingle
 *
 * @brief Implementation of explosion_pool.hxx
 */

#include <GL/gl.h>
#include <vector>
#include <deque>
#include <cmath>
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstring>

#include "explosion_pool.hxx"
#include "explosion.hxx"
#include "old_style_explosion.hxx"
#include "src/globals.hxx"
#include "src/opto_flags.hxx"
#include "src/fasttrig.hxx"
#include "src/sim/game_field.hxx"
#include "src/graphics/vec.hxx"
#include "src/graphics/matops.hxx"
#include "src/graphics/glhelp.hxx"
#include "src/graphics/shader.hxx"
#include "src/graphics/shader_loader.hxx"
#include "src/graphics/cmn_shaders.hxx"
#include "src/camera/effects_handler.hxx"

//Our debugging with FPE exceptions leads to problems with
//the use of uninitialised values in the arrays, so we'll need
//to temporarily disable the exceptions during update
#if !defined(WIN32) && defined(DEBUG)
#include </usr/include/fenv.h>
#endif

using namespace std;

#define MAX_EXPLOSIONS_DRAWN 3000

static int numExDrawn;

static GLuint vao, vbo;

struct ExplosionUniform {
  float ex, ey;
  float elapsedTime, sizeAt1Sec, density;
  unsigned id;
  vec4 colour;
};

#ifndef AB_OPENGL_14
namespace shader {
  #define VERTEX_TYPE shader::Vert2
  #define UNIFORM_TYPE ::ExplosionUniform
  DELAY_SHADER(simpleExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static simpleEx);

  DELAY_SHADER(sparkExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static spark);

  DELAY_SHADER(bigSparkExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static bigSpark);

  DELAY_SHADER(sparkleExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static sparkle);

  DELAY_SHADER(incursionExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static incursion);

  DELAY_SHADER(flameExplosion)
    sizeof(VERTEX_TYPE),
    VATTRIB(vertex), NULL,
    true,
    UNIFLOAT(ex), UNIFLOAT(ey),
    UNIFLOAT(elapsedTime), UNIFLOAT(sizeAt1Sec), UNIFLOAT(density),
    UNIFORM(id), UNIFORM(colour), NULL
  END_DELAY_SHADER(static flame);
}

static const Shader* shaders[6];
#endif /* AB_OPENGL_14 */

ExplosionPoolSegment::ExplosionPoolSegment() {
  freeCount=EXPLOSIONS_PER_SEGMENT;
  for (unsigned int i=0; i<sizeof(usage)/sizeof(unsigned int); ++i)
    usage[i]=0;
  //Set everything in the time stripe to infinity
  float infinity=INFINITY;
  for (unsigned i=0; i<lenof(timeStripe); i+=2) timeStripe[i]=infinity;
}

ExplosionPoolSegment::~ExplosionPoolSegment() {
}

inline void ExplosionPoolSegment::update(float et) noth {
  //First, update sizes
  //We don't care whether anything is in use,
  //because it'd take longer to check than
  //to just do the calculations
  float* ptr=coordStripe;
  float* end=ptr+EXPLOSIONS_PER_SEGMENT*EX_VLEN;
  while (ptr<end) {
    *ptr += (*(ptr+1))*et;
    ptr += 2;
  }

  //Now go through times.
  //If any time is too high, unset the usage bit
  unsigned int* usage=this->usage;
  unsigned int mask=1;
  GLfloat (*colours)[4]=this->colours;
  ptr=timeStripe;
  end=ptr+EXPLOSIONS_PER_SEGMENT*EX_TLEN;
  while (ptr<end) {
    //This line triggers a warning from Valgrind
    //That is OK, this was designed to crunch
    //through uninitialized values
    *ptr-=et;
    if (*ptr < 0) {
      //The time has expired, mark free
      *usage &= ~mask;
      ++freeCount;
      //Make ptr infinite
      float a=0;
      *ptr = 1/a;
    }
    (*colours)[3] = (*ptr / *(ptr+1));
    mask<<=1;
    //If we are 0, we have gone through
    //all 64 or 32 bits
    if (mask==0) {
      ++usage;
      mask=1;
    }
    ptr+=2;
    ++colours;
  }
}

#define GETX(i) coordStripe[EX_X_OFF + ((i)*EX_VLEN)]
#define GETY(i) coordStripe[EX_Y_OFF + ((i)*EX_VLEN)]
#define GETET(i) timeStripe[EX_ET_OFF + ((i)*EX_TLEN)]
#define GETLT(i) timeStripe[EX_LT_OFF + ((i)*EX_TLEN)]

ExplosionPool::ExplosionPool()
{
  static bool hasVAO=false;
#ifndef AB_OPENGL_14
  if (!hasVAO && !headless) {
    static const shader::Vert2 vertices[4] = {
      {{{-1,+1}}},
      {{{-1,-1}}},
      {{{+1,+1}}},
      {{{+1,-1}}},
    };

    vao=newVAO();
    glBindVertexArray(vao);
    vbo=newVBO();
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    shader::spark->setupVBO();

    shaders[Explosion::Simple   ] = shader::simpleEx .operator->();
    shaders[Explosion::Spark    ] = shader::spark    .operator->();
    shaders[Explosion::BigSpark ] = shader::bigSpark .operator->();
    shaders[Explosion::Sparkle  ] = shader::sparkle  .operator->();
    shaders[Explosion::Incursion] = shader::incursion.operator->();
    shaders[Explosion::Flame    ] = shader::flame    .operator->();
  }
#endif /* AB_OPENGL_14 */
}

void ExplosionPoolSegment::draw() noth {
#ifndef AB_OPENGL_14
  ExplosionUniform uni;
  //We can afford to be a bit more sane because this is called less often
  //and the majority of the grunt work is handled by GL
  for (unsigned int i=0; i<EXPLOSIONS_PER_SEGMENT; ++i) {
    if (usage[i/sizeof(unsigned int)/8] & (1 << (i%(sizeof(unsigned int)*8)))) {
      if (++numExDrawn >= MAX_EXPLOSIONS_DRAWN && (rand()&1)) continue;
      uni.ex = coordStripe[i*EX_VLEN + EX_X_OFF];
      uni.ey = coordStripe[i*EX_VLEN + EX_Y_OFF];
      uni.elapsedTime = (timeStripe[i*EX_TLEN + EX_LT_OFF] - timeStripe[i*EX_TLEN + EX_ET_OFF])/1000;
      uni.sizeAt1Sec = sizes[i];
      uni.density = densities[i];
      GLfloat red=colours[i][0], green=colours[i][1], blue=colours[i][2], alpha=colours[i][3];
      //Somewhat realistic (looking) blackbody radiation:
      //Blue and green fade out earlier
      blue *= (alpha>0.25? (alpha-0.25f)/0.75f : 0);
      green *= alpha;
      uni.colour = Vec4(red,green,blue,alpha);
      uni.id=i+1;
      shaders[types[i]]->activate(&uni);
      #ifndef AB_OPENGL_21
      glDrawArrays(GL_POINTS, 0, 1); //The actual vertex is ignored
      #else
      glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
      #endif
    }
  }
#endif /* AB_OPENGL_14 */
}

ExplosionPool::~ExplosionPool() {
  for (unsigned int i=0; i<segments.size(); ++i)
    delete segments[i];
}

void ExplosionPool::update(float et) noth {
  #if defined(DEBUG) && !defined(WIN32)
  assert(-1 != fedisableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID));
  #endif

  for (unsigned i=0; i<hungryExplosions.size(); ++i)
    if (!--hungryExplosions[i].framesLeft)
      hungryExplosions.erase(hungryExplosions.begin() + (i--));

  for (unsigned int i=0; i<segments.size(); ++i)
    segments[i]->update(et);

  ++segmentGCCounter;
  //Disabled for now. It may have been causeing performance issues, since
  //the buffers are naturally rolled through.
  if (segmentGCCounter==0 && false) {
    //Kill any segment that is completely empty, other than the first
    for (unsigned int i=1; i<segments.size(); ++i) {
      for (unsigned int j=0; j<sizeof(segments[i]->usage)/sizeof(unsigned int); ++j)
        if (segments[i]->usage[j]) goto used;

      //Unused if we get here
      delete segments[i];
      segments.erase(segments.begin() + i);
      --i;
      continue;

      used:;
    }
  }

  #if defined(DEBUG) && !defined(WIN32)
  assert(-1 != feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID));
  #endif
}

void ExplosionPool::draw() noth {
#ifndef AB_OPENGL_14
  BEGINGP("ExplosionPool")
  numExDrawn=0;
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  for (unsigned int i=0; i<segments.size(); ++i)
    segments[i]->draw();
  ENDGP
#endif /* AB_OPENGL_14 */
}

/* I put these in separate functions for profiling.
 * Anyway, even in debug mode where they are not inlined,
 * three function calls shouldn't be too much of a penalty.
 */
#ifdef PROFILE
#define inline
#endif
inline void ExplosionPool::findFreeSegment(ExplosionPoolSegment*& segment, int& block, int& bit, int& index,
                                           vector<ExplosionPoolSegment*>& segments) noth {
  for (unsigned int i=0; i<segments.size(); ++i) {
    if (segments[i]->freeCount) {
      for (unsigned int j=0; j<sizeof(segments[i]->usage)/sizeof(unsigned int); ++j) {
        if (~segments[i]->usage[j]) {
          segment=segments[i];
          block=j;
          for (unsigned int k=0; k<sizeof(unsigned int)*8; ++k) {
            if (! (segment->usage[block] & (1 << k)) ) {
              bit=k;
              index=bit + block*sizeof(unsigned int)*8;
              return;
            }
          }
        }
      }
    }
  }

  //Not found, allocate new segment
  segments.push_back(segment=new ExplosionPoolSegment);
  block=0;
  index=0;
  bit=0;
}

void ExplosionPool::add(Explosion* ex) noth {
#ifdef AB_OPENGL_14
  delete ex;
  return;
#else
  if (headless) {
    delete ex;
    return;
  }

  ex->getField()->effects->explode(ex);

  if (ex->type == Explosion::Invisible) {
    delete ex;
    return;
  }

  //See if it is to be dropped
  for (unsigned i=0; i<hungryExplosions.size(); ++i) {
    if (hungryExplosions[i].type == ex->type
    &&  hungryExplosions[i].minX <= ex->x
    &&  hungryExplosions[i].maxX >  ex->x
    &&  hungryExplosions[i].minY <= ex->y
    &&  hungryExplosions[i].maxY >  ex->y) {
      //Drop
      delete ex;
      return;
    }
  }

  if (ex->hungry) {
    HungryExplosion he = {ex->type, ex->x-0.05f, ex->x+0.05f, ex->y-0.05f, ex->y+0.5f, 8};
    hungryExplosions.push_back(he);
  }

  /* Possibly redirect to old-style explosion */
  if (ex->type == Explosion::BigSpark
  &&  conf["shaders"][isLSDModeForced()? "lsd" :
                      (const char*)conf["conf"]["graphics"]["shader_profile"]]["redirect_big_spark_explosion"]) {
    ex->field->add(new OldStyleExplosion(ex));
    delete ex;
    return;
  }

  //Find a free item
  ExplosionPoolSegment* segment;
  int block, bit, index;
  findFreeSegment(segment, block, bit, index, segments);

  //Copy parms
  float* coords=segment->coordStripe+index*EX_VLEN;
  *(coords+EX_X_OFF)=ex->x;
  *(coords+EX_Y_OFF)=ex->y;
  *(coords+EX_VX_OFF)=ex->vx;
  *(coords+EX_VY_OFF)=ex->vy;
  float* times=segment->timeStripe+index*EX_TLEN;
  *(times+EX_ET_OFF)=ex->lifetime;
  *(times+EX_LT_OFF)=ex->lifetime;

  segment->colours[index][0]=ex->colour[0];
  segment->colours[index][1]=ex->colour[1];
  segment->colours[index][2]=ex->colour[2];
  segment->colours[index][3]=1; //full alpha at beginning

  segment->types[index] = ex->type;
  segment->sizes[index] = ex->sizeAt1Sec;
  segment->densities[index] = ex->density;

  //Mark used
  segment->usage[block] |= (1 << bit);
  --segment->freeCount;

  //We don't want the Explosion anymore
  delete ex;
#endif /* !defined(AB_OPENGL_14) */
}

<|endoftext|>


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

#include <string>
#include <unordered_set>

#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
#include "test/core/util/test_config.h"

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <gtest/gtest.h>

namespace grpc_core {

namespace {

class SessionTracker;

struct SessionExDataId {
  SessionTracker* tracker;
  long id;
};

class SessionTracker {
 public:
  SessionTracker() { ssl_context_ = SSL_CTX_new(TLSv1_2_method()); }

  ~SessionTracker() { SSL_CTX_free(ssl_context_); }

  tsi::SslSessionPtr NewSession(long id) {
    static int ex_data_id = SSL_SESSION_get_ex_new_index(
        0, nullptr, nullptr, nullptr, DestroyExData);
    GPR_ASSERT(ex_data_id != -1);
    // OpenSSL and different version of BoringSSL don't agree on API
    // so try both.
    tsi::SslSessionPtr session = NewSessionInternal(SSL_SESSION_new);
    SessionExDataId* data = new SessionExDataId{this, id};
    int result = SSL_SESSION_set_ex_data(session.get(), ex_data_id, data);
    EXPECT_EQ(result, 1);
    alive_sessions_.insert(id);
    return session;
  }

  bool IsAlive(long id) const {
    return alive_sessions_.find(id) != alive_sessions_.end();
  }

  size_t AliveCount() const { return alive_sessions_.size(); }

 private:
  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)()) {
    return tsi::SslSessionPtr(cb());
  }

  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)(const SSL_CTX*)) {
    return tsi::SslSessionPtr(cb(ssl_context_));
  }

  static void DestroyExData(void* parent, void* ptr, CRYPTO_EX_DATA* ad,
                            int index, long argl, void* argp) {
    SessionExDataId* data = static_cast<SessionExDataId*>(ptr);
    data->tracker->alive_sessions_.erase(data->id);
    delete data;
  }

  SSL_CTX* ssl_context_;
  std::unordered_set<long> alive_sessions_;
};

TEST(SslSessionCacheTest, InitialState) {
  SessionTracker tracker;
  // Verify session initial state.
  {
    tsi::SslSessionPtr tmp_sess = tracker.NewSession(1);
    EXPECT_EQ(tmp_sess->references, 1);
    EXPECT_TRUE(tracker.IsAlive(1));
    EXPECT_EQ(tracker.AliveCount(), 1);
  }
  EXPECT_FALSE(tracker.IsAlive(1));
  EXPECT_EQ(tracker.AliveCount(), 0);
}

TEST(SslSessionCacheTest, LruCache) {
  SessionTracker tracker;
  {
    RefCountedPtr<tsi::SslSessionLRUCache> cache =
        tsi::SslSessionLRUCache::Create(3);
    tsi::SslSessionPtr sess2 = tracker.NewSession(2);
    SSL_SESSION* sess2_ptr = sess2.get();
    cache->Put("first.dropbox.com", std::move(sess2));
    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess2_ptr);
    EXPECT_TRUE(tracker.IsAlive(2));
    EXPECT_EQ(tracker.AliveCount(), 1);
    // Putting element with the same key destroys old session.
    tsi::SslSessionPtr sess3 = tracker.NewSession(3);
    SSL_SESSION* sess3_ptr = sess3.get();
    cache->Put("first.dropbox.com", std::move(sess3));
    EXPECT_FALSE(tracker.IsAlive(2));
    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess3_ptr);
    EXPECT_TRUE(tracker.IsAlive(3));
    EXPECT_EQ(tracker.AliveCount(), 1);
    // Putting three more elements discards current one.
    for (long id = 4; id < 7; id++) {
      EXPECT_TRUE(tracker.IsAlive(3));
      std::string domain = std::to_string(id) + ".random.domain";
      cache->Put(domain.c_str(), tracker.NewSession(id));
    }
    EXPECT_EQ(cache->Size(), 3);
    EXPECT_FALSE(tracker.IsAlive(3));
    EXPECT_EQ(tracker.AliveCount(), 3);
    // Accessing element moves it into front of the queue.
    EXPECT_TRUE(cache->Get("4.random.domain"));
    EXPECT_TRUE(tracker.IsAlive(4));
    EXPECT_TRUE(tracker.IsAlive(5));
    EXPECT_TRUE(tracker.IsAlive(6));
    // One element has to be evicted from cache->
    cache->Put("7.random.domain", tracker.NewSession(7));
    EXPECT_TRUE(tracker.IsAlive(4));
    EXPECT_FALSE(tracker.IsAlive(5));
    EXPECT_TRUE(tracker.IsAlive(6));
    EXPECT_TRUE(tracker.IsAlive(7));
    EXPECT_EQ(tracker.AliveCount(), 3);
  }
  // Cache destructor destroys all sessions.
  EXPECT_EQ(tracker.AliveCount(), 0);
}

}  // namespace
}  // namespace grpc_core

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  grpc_test_init(argc, argv);
  grpc_init();
  int ret = RUN_ALL_TESTS();
  grpc_shutdown();
  return ret;
}
<commit_msg>Do not reach into BoringSSL internals.<commit_after>/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <string>
#include <unordered_set>

#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
#include "test/core/util/test_config.h"

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <gtest/gtest.h>

namespace grpc_core {

namespace {

class SessionTracker;

struct SessionExDataId {
  SessionTracker* tracker;
  long id;
};

class SessionTracker {
 public:
  SessionTracker() { ssl_context_ = SSL_CTX_new(TLSv1_2_method()); }

  ~SessionTracker() { SSL_CTX_free(ssl_context_); }

  tsi::SslSessionPtr NewSession(long id) {
    static int ex_data_id = SSL_SESSION_get_ex_new_index(
        0, nullptr, nullptr, nullptr, DestroyExData);
    GPR_ASSERT(ex_data_id != -1);
    // OpenSSL and different version of BoringSSL don't agree on API
    // so try both.
    tsi::SslSessionPtr session = NewSessionInternal(SSL_SESSION_new);
    SessionExDataId* data = new SessionExDataId{this, id};
    int result = SSL_SESSION_set_ex_data(session.get(), ex_data_id, data);
    EXPECT_EQ(result, 1);
    alive_sessions_.insert(id);
    return session;
  }

  bool IsAlive(long id) const {
    return alive_sessions_.find(id) != alive_sessions_.end();
  }

  size_t AliveCount() const { return alive_sessions_.size(); }

 private:
  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)()) {
    return tsi::SslSessionPtr(cb());
  }

  tsi::SslSessionPtr NewSessionInternal(SSL_SESSION* (*cb)(const SSL_CTX*)) {
    return tsi::SslSessionPtr(cb(ssl_context_));
  }

  static void DestroyExData(void* parent, void* ptr, CRYPTO_EX_DATA* ad,
                            int index, long argl, void* argp) {
    SessionExDataId* data = static_cast<SessionExDataId*>(ptr);
    data->tracker->alive_sessions_.erase(data->id);
    delete data;
  }

  SSL_CTX* ssl_context_;
  std::unordered_set<long> alive_sessions_;
};

TEST(SslSessionCacheTest, InitialState) {
  SessionTracker tracker;
  // Verify session initial state.
  {
    tsi::SslSessionPtr tmp_sess = tracker.NewSession(1);
    EXPECT_TRUE(tracker.IsAlive(1));
    EXPECT_EQ(tracker.AliveCount(), 1);
  }
  EXPECT_FALSE(tracker.IsAlive(1));
  EXPECT_EQ(tracker.AliveCount(), 0);
}

TEST(SslSessionCacheTest, LruCache) {
  SessionTracker tracker;
  {
    RefCountedPtr<tsi::SslSessionLRUCache> cache =
        tsi::SslSessionLRUCache::Create(3);
    tsi::SslSessionPtr sess2 = tracker.NewSession(2);
    SSL_SESSION* sess2_ptr = sess2.get();
    cache->Put("first.dropbox.com", std::move(sess2));
    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess2_ptr);
    EXPECT_TRUE(tracker.IsAlive(2));
    EXPECT_EQ(tracker.AliveCount(), 1);
    // Putting element with the same key destroys old session.
    tsi::SslSessionPtr sess3 = tracker.NewSession(3);
    SSL_SESSION* sess3_ptr = sess3.get();
    cache->Put("first.dropbox.com", std::move(sess3));
    EXPECT_FALSE(tracker.IsAlive(2));
    EXPECT_EQ(cache->Get("first.dropbox.com").get(), sess3_ptr);
    EXPECT_TRUE(tracker.IsAlive(3));
    EXPECT_EQ(tracker.AliveCount(), 1);
    // Putting three more elements discards current one.
    for (long id = 4; id < 7; id++) {
      EXPECT_TRUE(tracker.IsAlive(3));
      std::string domain = std::to_string(id) + ".random.domain";
      cache->Put(domain.c_str(), tracker.NewSession(id));
    }
    EXPECT_EQ(cache->Size(), 3);
    EXPECT_FALSE(tracker.IsAlive(3));
    EXPECT_EQ(tracker.AliveCount(), 3);
    // Accessing element moves it into front of the queue.
    EXPECT_TRUE(cache->Get("4.random.domain"));
    EXPECT_TRUE(tracker.IsAlive(4));
    EXPECT_TRUE(tracker.IsAlive(5));
    EXPECT_TRUE(tracker.IsAlive(6));
    // One element has to be evicted from cache->
    cache->Put("7.random.domain", tracker.NewSession(7));
    EXPECT_TRUE(tracker.IsAlive(4));
    EXPECT_FALSE(tracker.IsAlive(5));
    EXPECT_TRUE(tracker.IsAlive(6));
    EXPECT_TRUE(tracker.IsAlive(7));
    EXPECT_EQ(tracker.AliveCount(), 3);
  }
  // Cache destructor destroys all sessions.
  EXPECT_EQ(tracker.AliveCount(), 0);
}

}  // namespace
}  // namespace grpc_core

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  grpc_test_init(argc, argv);
  grpc_init();
  int ret = RUN_ALL_TESTS();
  grpc_shutdown();
  return ret;
}
<|endoftext|>


<commit_before>/*
 * Summary: C++ interface for memcached server
 *
 * Copy: See Copyright for the status of this software.
 *
 * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
 *          Patrick Galbraith <patg@patg.net>
 */

/**
 * @file memcached.hpp
 * @brief Libmemcached C++ interface
 */

#ifndef LIBMEMCACHEDPP_H
#define LIBMEMCACHEDPP_H

#include <libmemcached/memcached.h>

#include <string.h>

#include <string>
#include <vector>
#include <map>

namespace memcache
{

/**
 * This is the core memcached library (if later, other objects
 * are needed, they will be created from this class).
 */
class Memcache
{
public:

  Memcache()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcache(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  Memcache(const Memcache &rhs)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
  }

  ~Memcache()
  {
    memcached_free(&memc);
  }

  /**
   * Get the internal memcached_st *
   */
  memcached_st &getImpl()
  {
    return memc;
  }

  /**
   * Get the internal memcached_st *
   */
  const memcached_st &getImpl() const
  {
    return memc;
  }

  /**
   * Return an error string for the given return structure.
   *
   * @param[in] rc a memcached_return structure
   * @return error string corresponding to given return code in the library.
   */
  const std::string getError(memcached_return rc) const
  {
    /* first parameter to strerror is unused */
    return memcached_strerror(NULL, rc);
  }

  /**
   * Fetches an individual value from the server.
   *
   * @param[in] key key of object to fetch
   * @param[out] ret_val store returned object in this vector
   * @return true on success; false on failure
   */
  bool fetch(std::string &key,
             std::vector<char> &ret_val)
  {
    char ret_key[MEMCACHED_MAX_KEY];
    size_t value_length= 0;
    size_t key_length= 0;
    memcached_return rc;
    uint32_t flags= 0;
    char *value= memcached_fetch(&memc, ret_key, &key_length,
                                 &value_length, &flags, &rc);
    if (value && ret_val.empty())
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
      key.assign(ret_key);
      return true;
    }
    return false;
  }

  std::vector<char> &get(const std::string &key,
                         std::vector<char> &ret_val)
  {
    uint32_t flags= 0;
    memcached_return rc;
    size_t value_length= 0;

    if (key.empty())
    {
      return ret_val;
    }
    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               &value_length, &flags, &rc);
    if (value != NULL && ret_val.empty())
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
    }
    return ret_val;
  }

  std::vector<char> &getByKey(const std::string &master_key,
                              const std::string &key,
                              std::vector<char> &ret_val)
  {
    uint32_t flags= 0;
    memcached_return rc;
    size_t value_length= 0;

    if (master_key.empty() || key.empty())
    {
      return ret_val;
    }
    char *value= memcached_get_by_key(&memc,
                                      master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      &value_length, &flags, &rc);
    if (value)
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
    }
    return ret_val;
  }

  bool mget(std::vector<std::string> &keys)
  {
    std::vector<const char *> real_keys;
    std::vector<size_t> key_len;
    /*
     * Construct an array which will contain the length
     * of each of the strings in the input vector. Also, to
     * interface with the memcached C API, we need to convert
     * the vector of std::string's to a vector of char *.
     */
    real_keys.reserve(keys.size());
    key_len.reserve(keys.size());

    std::vector<std::string>::iterator it= keys.begin();

    while (it != keys.end())
    {
      real_keys.push_back(const_cast<char *>((*it).c_str()));
      key_len.push_back((*it).length());
      ++it;
    }

    /*
     * If the std::vector of keys is empty then we cannot
     * call memcached_mget as we will get undefined behavior.
     */
    if (! real_keys.empty())
    {
      memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
                                          real_keys.size());
      return (rc == MEMCACHED_SUCCESS);
    }

    return false;
  }

  bool set(const std::string &key,
           const std::vector<char> &value,
           time_t expiration,
           uint32_t flags)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_set(&memc,
                                       key.c_str(), key.length(),
                                       &value[0], value.size(),
                                       expiration, flags);
    return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
  }

  bool setAll(std::vector<std::string> &keys,
              std::vector< std::vector<char> *> &values,
              time_t expiration,
              uint32_t flags)
  {
    if (keys.size() != values.size())
    {
      return false;
    }
    bool retval= true;
    std::vector<std::string>::iterator key_it= keys.begin();
    std::vector< std::vector<char> *>::iterator val_it= values.begin();
    while (key_it != keys.end())
    {
      retval= set((*key_it), *(*val_it), expiration, flags);
      if (retval == false)
      {
        return retval;
      }
      ++key_it;
      ++val_it;
    }
    return retval;
  }

  bool setAll(std::map<const std::string, std::vector<char> > key_value_map,
              time_t expiration,
              uint32_t flags)
  {
    if (key_value_map.empty())
    {
      return false;
    }
    bool retval= true;
    std::map<const std::string, std::vector<char> >::iterator it=
      key_value_map.begin();
    while (it != key_value_map.end())
    {
      retval= set(it->first, it->second, expiration, flags);
      if (retval == false)
      {
        return false;
      }
      ++it;
    }
    return true;
  }

  bool setByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value,
                time_t expiration,
                uint32_t flags)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              &value[0], value.size(),
                                              expiration,
                                              flags);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string &key, unsigned int offset, uint64_t *value)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const std::string &key, unsigned int offset, uint64_t *value)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_decrement(&memc, key.c_str(),
                                             key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_add(&memc, key.c_str(), key.length(),
                                       &value[0], value.size(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool addByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_add_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              &value[0],
                                              value.size(),
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
                                           &value[0], value.size(),
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replaceByKey(const std::string &master_key,
                    const std::string &key,
                    const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_replace_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  &value[0],
                                                  value.size(),
                                                  0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                           &value[0], value.size(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prependByKey(const std::string &master_key,
                    const std::string &key,
                    const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_prepend_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  &value[0],
                                                  value.size(),
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_append(&memc,
                                          key.c_str(),
                                          key.length(),
                                          &value[0],
                                          value.size(),
                                          0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool appendByKey(const std::string &master_key,
                   const std::string &key,
                   const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 &value[0],
                                                 value.size(),
                                                 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const std::string &key,
           const std::vector<char> &value,
           uint64_t cas_arg)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
                                       &value[0], value.size(),
                                       0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool casByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value,
                uint64_t cas_arg)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              &value[0],
                                              value.size(),
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool remove(const std::string &key)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool removeByKey(const std::string &master_key,
                   const std::string &key)
  {
    if (master_key.empty() || key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_delete_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool flush(time_t expiration)
  {
    memcached_return rc= memcached_flush(&memc, expiration);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool fetchExecute(memcached_execute_function *callback,
                    void *context,
                    unsigned int num_of_callbacks)
  {
    memcached_return rc= memcached_fetch_execute(&memc,
                                                 callback,
                                                 context,
                                                 num_of_callbacks);
    return (rc == MEMCACHED_SUCCESS);
  }

  /**
   * Get the library version string.
   * @return std::string containing a copy of the library version string.
   */
  const std::string libVersion() const
  {
    const char *ver= memcached_lib_version();
    const std::string version(ver);
    return version;
  }

private:

  memcached_st memc;
  memcached_result_st result;
};

}

#endif /* LIBMEMCACHEDPP_H */
<commit_msg>Corrected setAll methods to take std::map parameter by reference instead of by value.<commit_after>/*
 * Summary: C++ interface for memcached server
 *
 * Copy: See Copyright for the status of this software.
 *
 * Authors: Padraig O'Sullivan <osullivan.padraig@gmail.com>
 *          Patrick Galbraith <patg@patg.net>
 */

/**
 * @file memcached.hpp
 * @brief Libmemcached C++ interface
 */

#ifndef LIBMEMCACHEDPP_H
#define LIBMEMCACHEDPP_H

#include <libmemcached/memcached.h>

#include <string.h>

#include <string>
#include <vector>
#include <map>

namespace memcache
{

/**
 * This is the core memcached library (if later, other objects
 * are needed, they will be created from this class).
 */
class Memcache
{
public:

  Memcache()
    :
      memc(),
      result()
  {
    memcached_create(&memc);
  }

  Memcache(memcached_st *clone)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, clone);
  }

  Memcache(const Memcache &rhs)
    :
      memc(),
      result()
  {
    memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
  }

  ~Memcache()
  {
    memcached_free(&memc);
  }

  /**
   * Get the internal memcached_st *
   */
  memcached_st &getImpl()
  {
    return memc;
  }

  /**
   * Get the internal memcached_st *
   */
  const memcached_st &getImpl() const
  {
    return memc;
  }

  /**
   * Return an error string for the given return structure.
   *
   * @param[in] rc a memcached_return structure
   * @return error string corresponding to given return code in the library.
   */
  const std::string getError(memcached_return rc) const
  {
    /* first parameter to strerror is unused */
    return memcached_strerror(NULL, rc);
  }

  /**
   * Fetches an individual value from the server.
   *
   * @param[in] key key of object to fetch
   * @param[out] ret_val store returned object in this vector
   * @return true on success; false on failure
   */
  bool fetch(std::string &key,
             std::vector<char> &ret_val)
  {
    char ret_key[MEMCACHED_MAX_KEY];
    size_t value_length= 0;
    size_t key_length= 0;
    memcached_return rc;
    uint32_t flags= 0;
    char *value= memcached_fetch(&memc, ret_key, &key_length,
                                 &value_length, &flags, &rc);
    if (value && ret_val.empty())
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
      key.assign(ret_key);
      return true;
    }
    return false;
  }

  std::vector<char> &get(const std::string &key,
                         std::vector<char> &ret_val)
  {
    uint32_t flags= 0;
    memcached_return rc;
    size_t value_length= 0;

    if (key.empty())
    {
      return ret_val;
    }
    char *value= memcached_get(&memc, key.c_str(), key.length(),
                               &value_length, &flags, &rc);
    if (value != NULL && ret_val.empty())
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
    }
    return ret_val;
  }

  std::vector<char> &getByKey(const std::string &master_key,
                              const std::string &key,
                              std::vector<char> &ret_val)
  {
    uint32_t flags= 0;
    memcached_return rc;
    size_t value_length= 0;

    if (master_key.empty() || key.empty())
    {
      return ret_val;
    }
    char *value= memcached_get_by_key(&memc,
                                      master_key.c_str(), master_key.length(),
                                      key.c_str(), key.length(),
                                      &value_length, &flags, &rc);
    if (value)
    {
      ret_val.reserve(value_length);
      ret_val.assign(value, value + value_length);
    }
    return ret_val;
  }

  bool mget(std::vector<std::string> &keys)
  {
    std::vector<const char *> real_keys;
    std::vector<size_t> key_len;
    /*
     * Construct an array which will contain the length
     * of each of the strings in the input vector. Also, to
     * interface with the memcached C API, we need to convert
     * the vector of std::string's to a vector of char *.
     */
    real_keys.reserve(keys.size());
    key_len.reserve(keys.size());

    std::vector<std::string>::iterator it= keys.begin();

    while (it != keys.end())
    {
      real_keys.push_back(const_cast<char *>((*it).c_str()));
      key_len.push_back((*it).length());
      ++it;
    }

    /*
     * If the std::vector of keys is empty then we cannot
     * call memcached_mget as we will get undefined behavior.
     */
    if (! real_keys.empty())
    {
      memcached_return rc= memcached_mget(&memc, &real_keys[0], &key_len[0],
                                          real_keys.size());
      return (rc == MEMCACHED_SUCCESS);
    }

    return false;
  }

  bool set(const std::string &key,
           const std::vector<char> &value,
           time_t expiration,
           uint32_t flags)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_set(&memc,
                                       key.c_str(), key.length(),
                                       &value[0], value.size(),
                                       expiration, flags);
    return (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_BUFFERED);
  }

  bool setAll(std::vector<std::string> &keys,
              std::vector< std::vector<char> *> &values,
              time_t expiration,
              uint32_t flags)
  {
    if (keys.size() != values.size())
    {
      return false;
    }
    bool retval= true;
    std::vector<std::string>::iterator key_it= keys.begin();
    std::vector< std::vector<char> *>::iterator val_it= values.begin();
    while (key_it != keys.end())
    {
      retval= set((*key_it), *(*val_it), expiration, flags);
      if (retval == false)
      {
        return retval;
      }
      ++key_it;
      ++val_it;
    }
    return retval;
  }

  bool setAll(std::map<const std::string, std::vector<char> > &key_value_map,
              time_t expiration,
              uint32_t flags)
  {
    if (key_value_map.empty())
    {
      return false;
    }
    bool retval= true;
    std::map<const std::string, std::vector<char> >::iterator it=
      key_value_map.begin();
    while (it != key_value_map.end())
    {
      retval= set(it->first, it->second, expiration, flags);
      if (retval == false)
      {
        return false;
      }
      ++it;
    }
    return true;
  }

  bool setByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value,
                time_t expiration,
                uint32_t flags)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(), key.length(),
                                              &value[0], value.size(),
                                              expiration,
                                              flags);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool increment(const std::string &key, unsigned int offset, uint64_t *value)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool decrement(const std::string &key, unsigned int offset, uint64_t *value)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_decrement(&memc, key.c_str(),
                                             key.length(),
                                             offset, value);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool add(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_add(&memc, key.c_str(), key.length(),
                                       &value[0], value.size(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool addByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_add_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              &value[0],
                                              value.size(),
                                              0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replace(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
                                           &value[0], value.size(),
                                           0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool replaceByKey(const std::string &master_key,
                    const std::string &key,
                    const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_replace_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  &value[0],
                                                  value.size(),
                                                  0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prepend(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
                                           &value[0], value.size(), 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool prependByKey(const std::string &master_key,
                    const std::string &key,
                    const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_prepend_by_key(&memc,
                                                  master_key.c_str(),
                                                  master_key.length(),
                                                  key.c_str(),
                                                  key.length(),
                                                  &value[0],
                                                  value.size(),
                                                  0,
                                                  0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool append(const std::string &key, const std::vector<char> &value)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_append(&memc,
                                          key.c_str(),
                                          key.length(),
                                          &value[0],
                                          value.size(),
                                          0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool appendByKey(const std::string &master_key,
                   const std::string &key,
                   const std::vector<char> &value)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_append_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 &value[0],
                                                 value.size(),
                                                 0, 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool cas(const std::string &key,
           const std::vector<char> &value,
           uint64_t cas_arg)
  {
    if (key.empty() || value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
                                       &value[0], value.size(),
                                       0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool casByKey(const std::string &master_key,
                const std::string &key,
                const std::vector<char> &value,
                uint64_t cas_arg)
  {
    if (master_key.empty() ||
        key.empty() ||
        value.empty())
    {
      return false;
    }
    memcached_return rc= memcached_cas_by_key(&memc,
                                              master_key.c_str(),
                                              master_key.length(),
                                              key.c_str(),
                                              key.length(),
                                              &value[0],
                                              value.size(),
                                              0, 0, cas_arg);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool remove(const std::string &key)
  {
    if (key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool removeByKey(const std::string &master_key,
                   const std::string &key)
  {
    if (master_key.empty() || key.empty())
    {
      return false;
    }
    memcached_return rc= memcached_delete_by_key(&memc,
                                                 master_key.c_str(),
                                                 master_key.length(),
                                                 key.c_str(),
                                                 key.length(),
                                                 0);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool flush(time_t expiration)
  {
    memcached_return rc= memcached_flush(&memc, expiration);
    return (rc == MEMCACHED_SUCCESS);
  }

  bool fetchExecute(memcached_execute_function *callback,
                    void *context,
                    unsigned int num_of_callbacks)
  {
    memcached_return rc= memcached_fetch_execute(&memc,
                                                 callback,
                                                 context,
                                                 num_of_callbacks);
    return (rc == MEMCACHED_SUCCESS);
  }

  /**
   * Get the library version string.
   * @return std::string containing a copy of the library version string.
   */
  const std::string libVersion() const
  {
    const char *ver= memcached_lib_version();
    const std::string version(ver);
    return version;
  }

private:

  memcached_st memc;
  memcached_result_st result;
};

}

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


<commit_before>/* <x0/HttpError.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/http/HttpError.h>
#include <x0/Defines.h>

namespace x0 {

class http_error_category_impl :
	public std::error_category
{
private:
	std::string codes_[600];

	void set(HttpError ec, const std::string& message)
	{
		codes_[static_cast<int>(ec)] = message;
	}

	void initialize_codes()
	{
		for (std::size_t i = 0; i < sizeof(codes_) / sizeof(*codes_); ++i)
			codes_[i] = "Undefined";

		set(HttpError::ContinueRequest, "Continue");
		set(HttpError::SwitchingProtocols, "Switching Protocols");
		set(HttpError::Processing, "Processing");

		set(HttpError::Ok, "Ok");
		set(HttpError::Created, "Created");
		set(HttpError::Accepted, "Accepted");
		set(HttpError::NonAuthoriativeInformation, "Non Authoriative Information");
		set(HttpError::NoContent, "No Content");
		set(HttpError::ResetContent, "Reset Content");
		set(HttpError::PartialContent, "Partial Content");

		set(HttpError::MultipleChoices, "Multiple Choices");
		set(HttpError::MovedPermanently, "Moved Permanently");
		set(HttpError::MovedTemporarily, "Moved Temporarily");
		set(HttpError::NotModified, "Not Modified");

		set(HttpError::BadRequest, "Bad Request");
		set(HttpError::Unauthorized, "Unauthorized");
		set(HttpError::Forbidden, "Forbidden");
		set(HttpError::NotFound, "Not Found");
		set(HttpError::MethodNotAllowed, "Method Not Allowed");
		set(HttpError::NotAcceptable, "Not Acceptable");
		set(HttpError::ProxyAuthenticationRequired, "Proxy Authentication Required");
		set(HttpError::RequestTimeout, "Request Timeout");
		set(HttpError::Conflict, "Conflict");
		set(HttpError::Gone, "Gone");
		set(HttpError::LengthRequired, "Length Required");
		set(HttpError::PreconditionFailed, "Precondition Failed");
		set(HttpError::RequestEntityTooLarge, "Request Entity Too Large");
		set(HttpError::RequestUriTooLong, "Request URI Too Long");
		set(HttpError::UnsupportedMediaType, "Unsupported Media Type");
		set(HttpError::RequestedRangeNotSatisfiable, "Requested Range Not Satisfiable");
		set(HttpError::ExpectationFailed, "Expectation Failed");
		set(HttpError::ThereAreTooManyConnectionsFromYourIP, "There Are Too Many Connections From Your IP");
		set(HttpError::UnprocessableEntity, "Unprocessable Entity");
		set(HttpError::Locked, "Locked");
		set(HttpError::FailedDependency, "Failed Dependency");
		set(HttpError::UnorderedCollection, "Unordered Collection");
		set(HttpError::UpgradeRequired, "Upgrade Required");

		set(HttpError::InternalServerError, "Internal Server Error");
		set(HttpError::NotImplemented, "Not Implemented");
		set(HttpError::BadGateway, "Bad Gateway");
		set(HttpError::ServiceUnavailable, "Service Unavailable");
		set(HttpError::GatewayTimedout, "Gateway Timedout");
		set(HttpError::HttpVersionNotSupported, "HTTP Version Not Supported");
		set(HttpError::InsufficientStorage, "Insufficient Storage");
	}

public:
	http_error_category_impl()
	{
		initialize_codes();
	}

	virtual const char *name() const
	{
		return "http";
	}

	virtual std::string message(int ec) const
	{
		return codes_[ec];
	}
};

http_error_category_impl http_category_impl_;

const std::error_category& http_category() throw()
{
	return http_category_impl_;
}

} // namespace x0
<commit_msg>[http] HttpError: added missing strings for new status codes<commit_after>/* <x0/HttpError.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2010 Christian Parpart <trapni@gentoo.org>
 */

#include <x0/http/HttpError.h>
#include <x0/Defines.h>

namespace x0 {

class http_error_category_impl :
	public std::error_category
{
private:
	std::string codes_[600];

	void set(HttpError ec, const std::string& message)
	{
		codes_[static_cast<int>(ec)] = message;
	}

	void initialize_codes()
	{
		for (std::size_t i = 0; i < sizeof(codes_) / sizeof(*codes_); ++i)
			codes_[i] = "Undefined";

		set(HttpError::ContinueRequest, "Continue");
		set(HttpError::SwitchingProtocols, "Switching Protocols");
		set(HttpError::Processing, "Processing");

		set(HttpError::Ok, "Ok");
		set(HttpError::Created, "Created");
		set(HttpError::Accepted, "Accepted");
		set(HttpError::NonAuthoriativeInformation, "Non Authoriative Information");
		set(HttpError::NoContent, "No Content");
		set(HttpError::ResetContent, "Reset Content");
		set(HttpError::PartialContent, "Partial Content");

		set(HttpError::MultipleChoices, "Multiple Choices");
		set(HttpError::MovedPermanently, "Moved Permanently");
		set(HttpError::MovedTemporarily, "Moved Temporarily");
		set(HttpError::NotModified, "Not Modified");

		set(HttpError::BadRequest, "Bad Request");
		set(HttpError::Unauthorized, "Unauthorized");
		set(HttpError::Forbidden, "Forbidden");
		set(HttpError::NotFound, "Not Found");
		set(HttpError::MethodNotAllowed, "Method Not Allowed");
		set(HttpError::NotAcceptable, "Not Acceptable");
		set(HttpError::ProxyAuthenticationRequired, "Proxy Authentication Required");
		set(HttpError::RequestTimeout, "Request Timeout");
		set(HttpError::Conflict, "Conflict");
		set(HttpError::Gone, "Gone");
		set(HttpError::LengthRequired, "Length Required");
		set(HttpError::PreconditionFailed, "Precondition Failed");
		set(HttpError::RequestEntityTooLarge, "Request Entity Too Large");
		set(HttpError::RequestUriTooLong, "Request URI Too Long");
		set(HttpError::UnsupportedMediaType, "Unsupported Media Type");
		set(HttpError::RequestedRangeNotSatisfiable, "Requested Range Not Satisfiable");
		set(HttpError::ExpectationFailed, "Expectation Failed");
		set(HttpError::ThereAreTooManyConnectionsFromYourIP, "There Are Too Many Connections From Your IP");
		set(HttpError::UnprocessableEntity, "Unprocessable Entity");
		set(HttpError::Locked, "Locked");
		set(HttpError::FailedDependency, "Failed Dependency");
		set(HttpError::UnorderedCollection, "Unordered Collection");
		set(HttpError::UpgradeRequired, "Upgrade Required");

		set(HttpError::InternalServerError, "Internal Server Error");
		set(HttpError::NotImplemented, "Not Implemented");
		set(HttpError::BadGateway, "Bad Gateway");
		set(HttpError::ServiceUnavailable, "Service Unavailable");
		set(HttpError::GatewayTimedout, "Gateway Timedout");
		set(HttpError::HttpVersionNotSupported, "HTTP Version Not Supported");
		set(HttpError::InsufficientStorage, "Insufficient Storage");

		set(HttpError::VariantAlsoNegotiates, "Variant Also Negotiates");
		set(HttpError::LoopDetected, "Loop Detected");
		set(HttpError::BandwidthExceeded, "Bandwidth Exceeded");
		set(HttpError::NotExtended, "Not Extended");
		set(HttpError::NetworkAuthenticationRequired, "Network Authentication Required");
	}

public:
	http_error_category_impl()
	{
		initialize_codes();
	}

	virtual const char *name() const
	{
		return "http";
	}

	virtual std::string message(int ec) const
	{
		return codes_[ec];
	}
};

http_error_category_impl http_category_impl_;

const std::error_category& http_category() throw()
{
	return http_category_impl_;
}

} // namespace x0
<|endoftext|>


<commit_before>#ifndef DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH
#define DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH

#include <dune/fem/common/localmatrix.hh>

namespace Dune
{

namespace Functionals
{

namespace Solver
{

template< class MatrixImp, class VectorImp >
class FEMAssembler
{
public:
  typedef MatrixImp
    MatrixType;

  typedef VectorImp
    VectorType;

  typedef typename VectorType::field_type
    FieldType;

  typedef Dune::Functionals::Common::LocalMatrix< FieldType >
    LocalMatrixType;

public:
  template< class Operator >
  static void assembleMatrix( const Operator& op, MatrixType& m )
  {
    typedef typename Operator::DiscreteFunctionSpaceType
      DFSType;
    typedef typename DFSType::BaseFunctionSetType
      BFSType;
    typedef typename DFSType::IteratorType
      ItType;
    typedef typename ItType::Entity
      EntityType;

    const DFSType& space = op.space();
    // check that number of dofs in space is equal to matrix size
    // assert()
    ItType it = space.begin();
    for( ; it != space.end(); ++it )
    {
      const EntityType &en = *it;
      const BFSType& bfs = space.baseFunctionSet( en );
      LocalMatrixType localMatrix( bfs.numBaseFunctions(), bfs.numBaseFunctions() );
      localMatrix = op.applyLocal( en );

      addToMatrix( space, localMatrix, en, m );
    }
  }

  // @todo implementation
  template< class Operator >
  static void assembleVector( const Operator& op, VectorType& vec )
  {

  }

  /// \todo merge later with assembleMatrix
  /// \todo implement a PrecompiledConstraints class which wraps an existing
  ///       Constraints class for efficiency at the cost of one grid walk
  template< class ConstrainedDFS >
  static void applyMatrixConstraints( const ConstrainedDFS& cSpace,
                                      MatrixType& m )
  {
    typedef typename ConstrainedDFS::ConstraintsType
      ConstraintsType;
    typedef typename ConstrainedDFS::DiscreteFunctionSpaceType
      DFSType;
    typedef typename ConstraintsType::LocalConstraintsType
      LocalConstraintsType;
    typedef typename DFSType::BaseFunctionSetType
      BFSType;
    typedef typename DFSType::IteratorType
      ItType;
    typedef typename ItType::Entity
      EntityType;

    const ConstraintsType& constraints = cSpace.constraints();

    // check that number of dofs in space is equal to matrix size
    // assert()

    ItType it = cSpace.space().begin();
    ItType end = cSpace.space().end();
    for( ; it != end; ++it )
    {
      const EntityType& en = *it;

      const LocalConstraintsType localConstraints = constraints.local( en );

      setLocalConstraintsInMatrix( cSpace, localConstraints, en, m );
    }

  }

  // @todo implementation
  template< class ConstrainedDFS >
  static void applyVectorConstraints( const ConstrainedDFS& cSpace,
                                      VectorType& vec )
  {

  }

public:
  /// \todo move to matrixContainer factory
  template< class DFSType,
            class Entity >
  static void addToMatrix( const DFSType& space,
                           const LocalMatrixType& localMatrix,
                           const Entity& en,
                           MatrixType &m )
  {
    for( unsigned int i = 0; i < localMatrix.N(); i++ )
    {
      for( unsigned int j = 0; j < localMatrix.M(); j++ )
      {
        const int globalI = space.mapToGlobal( en, i );
        const int globalJ = space.mapToGlobal( en, j );

        m[globalI][globalJ] = localMatrix.get( i, j );
      }
    }
  }

  /// \todo move to Constraints class
  template< class ConstrainedDFS,
            class Entity >
  static void setLocalConstraintsInMatrix( const ConstrainedDFS& cSpace,
                                           const typename ConstrainedDFS::ConstraintsType::LocalConstraintsType& localConstraints,
                                           const Entity& en,
                                           MatrixType &m )
  {

    for( unsigned int i = 0; i < localConstraints.rowDofsSize(); i++ )
    {
      for( unsigned int j = 0; j < localConstraints.columnDofsSize(); j++ )
      {
        m[localConstraints.rowDofs(i)][localConstraints.columnDofs(j)]
          = localConstraints.localMatrix(i,j);
      }
    }
  }

}; // end of class FEMAssembler

} // end of namespace Solver

} // end of namespace Functionals

} // end of namespace Dune

#endif /* end of include guard: DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH */
<commit_msg>added applyVectorConstraints()<commit_after>#ifndef DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH
#define DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH

#include <dune/fem/common/localmatrix.hh>

namespace Dune
{

namespace Functionals
{

namespace Solver
{

template< class MatrixImp, class VectorImp >
class FEMAssembler
{
public:
  typedef MatrixImp
    MatrixType;

  typedef VectorImp
    VectorType;

  typedef typename VectorType::field_type
    FieldType;

  typedef Dune::Functionals::Common::LocalMatrix< FieldType >
    LocalMatrixType;

public:
  template< class Operator >
  static void assembleMatrix( const Operator& op, MatrixType& m )
  {
    typedef typename Operator::DiscreteFunctionSpaceType
      DFSType;
    typedef typename DFSType::BaseFunctionSetType
      BFSType;
    typedef typename DFSType::IteratorType
      ItType;
    typedef typename ItType::Entity
      EntityType;

    const DFSType& space = op.space();
    // check that number of dofs in space is equal to matrix size
    // assert()
    ItType it = space.begin();
    for( ; it != space.end(); ++it )
    {
      const EntityType &en = *it;
      const BFSType& bfs = space.baseFunctionSet( en );
      LocalMatrixType localMatrix( bfs.numBaseFunctions(), bfs.numBaseFunctions() );
      localMatrix = op.applyLocal( en );

      addToMatrix( space, localMatrix, en, m );
    }
  }

  // @todo implementation
  template< class Operator >
  static void assembleVector( const Operator& op, VectorType& vec )
  {

  }

  /// \todo merge later with assembleMatrix
  /// \todo implement a PrecompiledConstraints class which wraps an existing
  ///       Constraints class for efficiency at the cost of one grid walk
  template< class ConstrainedDFS >
  static void applyMatrixConstraints( const ConstrainedDFS& cSpace,
                                      MatrixType& m )
  {
    typedef typename ConstrainedDFS::ConstraintsType
      ConstraintsType;
    typedef typename ConstrainedDFS::DiscreteFunctionSpaceType
      DFSType;
    typedef typename ConstraintsType::LocalConstraintsType
      LocalConstraintsType;
    typedef typename DFSType::IteratorType
      ItType;
    typedef typename ItType::Entity
      EntityType;

    const ConstraintsType& constraints = cSpace.constraints();

    // check that number of dofs in space is equal to matrix size
    // assert()

    ItType it  = cSpace.space().begin();
    ItType end = cSpace.space().end();

    for( ; it != end; ++it )
    {
      const EntityType& en = *it;

      const LocalConstraintsType localConstraints = constraints.local( en );

      setLocalConstraintsInMatrix( cSpace, localConstraints, en, m );
    }

  }

  // @todo implementation
  template< class ConstrainedDFS >
  static void applyVectorConstraints( const ConstrainedDFS& cSpace,
                                      VectorType& vec )
  {
    typedef typename ConstrainedDFS::ConstraintsType
      ConstraintsType;
    typedef typename ConstrainedDFS::DiscreteFunctionSpaceType
      DFSType;
    typedef typename ConstraintsType::LocalConstraintsType
      LocalConstraintsType;
    typedef typename DFSType::IteratorType
      ItType;
    typedef typename ItType::Entity
      EntityType;

    const ConstraintsType & constraints = cSpace.constraints();

    ItType it  = cSpace.space().begin();
    ItType end = cSpace.space().end();

    for( ; it != end; ++it )
    {
      const EntityType& en = *it;

      const LocalConstraintsType localConstraints = constraints.local( en );

      for (unsigned int i = 0; i < localConstraints.rowDofsSize(); ++i) {
        vec[localConstraints.rowDofs(i)] = 0;
      }
    }
  }

public:
  /// \todo move to matrixContainer factory
  template< class DFSType,
            class Entity >
  static void addToMatrix( const DFSType& space,
                           const LocalMatrixType& localMatrix,
                           const Entity& en,
                           MatrixType &m )
  {
    for( unsigned int i = 0; i < localMatrix.N(); i++ )
    {
      for( unsigned int j = 0; j < localMatrix.M(); j++ )
      {
        const int globalI = space.mapToGlobal( en, i );
        const int globalJ = space.mapToGlobal( en, j );

        m[globalI][globalJ] = localMatrix.get( i, j );
      }
    }
  }

  /// \todo move to Constraints class
  template< class ConstrainedDFS,
            class Entity >
  static void setLocalConstraintsInMatrix( const ConstrainedDFS& cSpace,
                                           const typename ConstrainedDFS::ConstraintsType::LocalConstraintsType& localConstraints,
                                           const Entity& en,
                                           MatrixType &m )
  {

    for( unsigned int i = 0; i < localConstraints.rowDofsSize(); i++ )
    {
      for( unsigned int j = 0; j < localConstraints.columnDofsSize(); j++ )
      {
        m[localConstraints.rowDofs(i)][localConstraints.columnDofs(j)]
          = localConstraints.localMatrix(i,j);
      }
    }
  }

}; // end of class FEMAssembler

} // end of namespace Solver

} // end of namespace Functionals

} // end of namespace Dune

#endif /* end of include guard: DUNE_FEM_FUNCTIONALS_SOLVER_FEMASSEMBLER_HH */
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_TYPENAMES_HH
#define DUNE_STUFF_TYPENAMES_HH

#include "color.hh"

#include <complex>
#include <memory>
#include <type_traits>

#include <dune/common/version.hh>
// static_assert/AlwaysFalse redirect to avoid warnings
#if DUNE_VERSION_NEWER(DUNE_COMMON,2,4) //post 2.3 release
# include <dune/common/typetraits.hh>
#else
# include <dune/common/static_assert.hh>
#endif

/** use this to define Typename specializations in the GLOBAL namespace ONLY **/
#define STUFF_TYPENAME(NAME) \
  namespace Dune{namespace Stuff{namespace Common { \
    template <> \
    struct Typename<NAME> { \
        static const char* value() { \
            return #NAME;  \
        } \
    }; \
  }}}

namespace Dune {
namespace Stuff {
namespace Common {

inline std::string demangleTypename(const std::string& mangled_name)
{
    #ifdef __GNUC__
    return abi::__cxa_demangle(mangled_name.c_str(), nullptr, nullptr, nullptr);
    #else // ifdef __GNUC__
    return mangled_name;
    #endif // ifdef __GNUC__
}

//! demangles typeid
template< class T >
std::string demangledTypeId(T& obj) {
  return demangleTypename(typeid(obj).name());
} // demangledTypeId

//! create output for demangled typeid
template< class T >
void realTypeId(T& obj, std::string name = "", size_t maxlevel = 10000) {
  std::cout << name
            << (name == "" ? "" : "'s type is ")
            << highlightTemplate(demangledTypeId(obj), maxlevel)
            << std::endl;
}

//! an extensible mechanism to assign "cleartext" names to types
template <typename T>
struct Typename {
    static std::string value() {
        #if defined(__GNUC__) && defined(__GXX_RTTI)
            return demangleTypename(typeid(T).name());
        #else
            return "unknown";
        #endif
    }
};

template < class T>
std::string getTypename(const T&) {
  return Typename<T>::value();
}

template <class T, class Ptr = void>
struct is_smart_ptr {
    static const bool value = false;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::unique_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::shared_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::weak_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template < class T, class = void >
struct PtrCaller
{
    static T& call(T& ptr) {
        return ptr;
    }
};

template < class T >
struct PtrCaller<T, typename std::enable_if<is_smart_ptr<T>::value || std::is_pointer<T>::value>::type>
{
    static typename T::element_type& call(T& ptr) {
        return *ptr;
    }
};

//! workaround for gcc 4.7 missing underlying type, via https://stackoverflow.com/questions/9343329/how-to-know-underlying-type-of-class-enum/10956467#10956467
template <class T>
struct underlying_type {
#if __GNUC__ == 4 && (__GNUC_MINOR__ < 7)
      typedef typename std::conditional<
          T( -1 ) < T( 0 ),
          typename std::make_signed< T >::type,
          typename std::make_unsigned< T >::type
          >::type type;
#else
  typedef typename std::underlying_type<T>::type type;
#endif
};

//! gcc < 4.8 fires a static-assert if std::hash< T > () isn't implemented
#if __GNUC__ == 4 && (__GNUC_MINOR__ < 8)
  template <typename>
  struct is_hashable : std::false_type {};
#else
  //! implementation from https://gcc.gnu.org/ml/libstdc++/2013-03/msg00027.html
  template <typename, typename = void>
  struct is_hashable : std::false_type {};

  template <typename T>
  struct is_hashable< T, typename std::enable_if< !!sizeof( std::declval< std::hash< T > >()( std::declval< T >() )) >::type >
    : std::true_type {};
#endif

} // namespace Common
} // namespace Stuff
} // namespace Dune

/**
  * \brief Helper macro to be used before DSC_has_typedef.
  *
  *        Taken from
  *        http://stackoverflow.com/questions/7834226/detecting-typedef-at-compile-time-template-metaprogramming
  */
#define DSC_has_typedef_initialize_once(tpdef) \
  template< typename T_local > \
  struct DSC_has_typedef_helper_ ## tpdef \
  { \
    template< typename TT_local > \
    struct void_ { typedef void type; }; \
  \
    template< typename TT_local, typename = void > \
    struct helper { static const bool value = false; }; \
  \
    template< typename TT_local > \
    struct helper< TT_local, typename void_< typename TT_local:: tpdef >::type > { static const bool value = true; }; \
  \
    static const bool value = helper< T_local >::value; \
  };

/**
  * \brief Macro to statically check a type for a typedef.
  *
  *        To check if a type Foo defines a typedef Bar, put this code somewhere, where a generated helper struct
  *        may be defined (obviously only once for each typedef name!):
\code
DSC_has_typedef_initialize_once(Bar)
\endcode
  *        You can then check for Bar (this will give you a static const bool):
\code
DSC_has_typedef(Bar)< Foo >::value
\endcode
  */
#define DSC_has_typedef(tpdf) \
  DSC_has_typedef_helper_ ## tpdf

/**
  * \brief Helper macro to be used before DSC_has_static_member.
  *
  *        Taken from http://stackoverflow.com/questions/11927032/sfinae-check-for-static-member-using-decltype
  */
#define DSC_has_static_member_initialize_once(mmbr) \
  template< class T_local > \
  struct DSC_has_static_member_helper_ ## mmbr \
  { \
    template< class TT_local, class = typename std::enable_if< !std::is_member_pointer< decltype(&TT_local:: mmbr) >::value>::type > \
    static std::true_type helper(int); \
  \
    template< class > \
    static std::false_type helper(...); \
  \
    static const bool value = decltype(helper< T_local >(0))::value; \
  };

/**
  * \brief Macro to statically check a class or struct for a static member.
  *
  *        To check if a class or struct Foo has a static member bar, put this code somewhere, where a generated helper
  *        struct may be defined (obviously only once for each member name!):
\code
DSC_has_static_member_initialize_once(bar)
\endcode
  *        You can then check for bar (this will give you a static const bool):
\code
DSC_has_static_member(bar)< Foo >::value
\endcode
  */
#define DSC_has_static_member(mmbr) \
  DSC_has_static_member_helper_ ## mmbr

STUFF_TYPENAME(int)
STUFF_TYPENAME(double)
STUFF_TYPENAME(float)
STUFF_TYPENAME(long)
STUFF_TYPENAME(unsigned int)
STUFF_TYPENAME(unsigned long)
STUFF_TYPENAME(char)

namespace Dune {
namespace Stuff {
namespace Common {

namespace internal {
  template< class Tt >
  struct is_complex_helper
  {
    DSC_has_typedef_initialize_once(value_type)

    static const bool is_candidate = DSC_has_typedef(value_type)< Tt >::value;
  }; // class is_complex_helper
} // namespace internal

template< class T, bool candidate = internal::is_complex_helper< T >::is_candidate >
struct is_complex
  : public std::is_base_of< std::complex< typename T::value_type >, T >
{};

template< class T >
struct is_complex< T, false >
  : public std::false_type
{};

template< class VecType >
struct VectorAbstraction;

template< class VectorType >
struct is_vector
{
  static const bool value = VectorAbstraction< VectorType >::is_vector;
};

} // namespace Common
} // namespace Stuff
} // namespace Dune
#endif // DUNE_STUFF_TYPENAMES_HH
<commit_msg>[common.type_utils] add missing include<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_TYPENAMES_HH
#define DUNE_STUFF_TYPENAMES_HH

#include "color.hh"

#include <complex>
#include <memory>
#include <type_traits>

#include <dune/common/version.hh>
// static_assert/AlwaysFalse redirect to avoid warnings
#if DUNE_VERSION_NEWER(DUNE_COMMON,2,4) //post 2.3 release
# include <dune/common/typetraits.hh>
#else
# include <dune/common/static_assert.hh>
#endif

/** use this to define Typename specializations in the GLOBAL namespace ONLY **/
#define STUFF_TYPENAME(NAME) \
  namespace Dune{namespace Stuff{namespace Common { \
    template <> \
    struct Typename<NAME> { \
        static const char* value() { \
            return #NAME;  \
        } \
    }; \
  }}}

namespace Dune {
namespace Stuff {
namespace Common {

inline std::string demangleTypename(const std::string& mangled_name)
{
    #ifdef __GNUC__
    return abi::__cxa_demangle(mangled_name.c_str(), nullptr, nullptr, nullptr);
    #else // ifdef __GNUC__
    return mangled_name;
    #endif // ifdef __GNUC__
}

//! demangles typeid
template< class T >
std::string demangledTypeId(T& obj) {
  return demangleTypename(typeid(obj).name());
} // demangledTypeId

//! create output for demangled typeid
template< class T >
void realTypeId(T& obj, std::string name = "", size_t maxlevel = 10000) {
  std::cout << name
            << (name == "" ? "" : "'s type is ")
            << highlightTemplate(demangledTypeId(obj), maxlevel)
            << std::endl;
}

//! an extensible mechanism to assign "cleartext" names to types
template <typename T>
struct Typename {
    static std::string value() {
        #if defined(__GNUC__) && defined(__GXX_RTTI)
            return demangleTypename(typeid(T).name());
        #else
            return "unknown";
        #endif
    }
};

template < class T>
std::string getTypename(const T&) {
  return Typename<T>::value();
}

template <class T, class Ptr = void>
struct is_smart_ptr {
    static const bool value = false;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::unique_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::shared_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template <class T>
struct is_smart_ptr<T, typename std::enable_if<std::is_same<std::weak_ptr<typename T::element_type>, T>::value>::type> {
    static const bool value = true;
    typedef T type;
};

template < class T, class = void >
struct PtrCaller
{
    static T& call(T& ptr) {
        return ptr;
    }
};

template < class T >
struct PtrCaller<T, typename std::enable_if<is_smart_ptr<T>::value || std::is_pointer<T>::value>::type>
{
    static typename T::element_type& call(T& ptr) {
        return *ptr;
    }
};

//! workaround for gcc 4.7 missing underlying type, via https://stackoverflow.com/questions/9343329/how-to-know-underlying-type-of-class-enum/10956467#10956467
template <class T>
struct underlying_type {
#if __GNUC__ == 4 && (__GNUC_MINOR__ < 7)
      typedef typename std::conditional<
          T( -1 ) < T( 0 ),
          typename std::make_signed< T >::type,
          typename std::make_unsigned< T >::type
          >::type type;
#else
  typedef typename std::underlying_type<T>::type type;
#endif
};

//! gcc < 4.8 fires a static-assert if std::hash< T > () isn't implemented
#if __GNUC__ == 4 && (__GNUC_MINOR__ < 8)
  template <typename>
  struct is_hashable : std::false_type {};
#else
  //! implementation from https://gcc.gnu.org/ml/libstdc++/2013-03/msg00027.html
  template <typename, typename = void>
  struct is_hashable : std::false_type {};

  template <typename T>
  struct is_hashable< T, typename std::enable_if< !!sizeof( std::declval< std::hash< T > >()( std::declval< T >() )) >::type >
    : std::true_type {};
#endif

} // namespace Common
} // namespace Stuff
} // namespace Dune

/**
  * \brief Helper macro to be used before DSC_has_typedef.
  *
  *        Taken from
  *        http://stackoverflow.com/questions/7834226/detecting-typedef-at-compile-time-template-metaprogramming
  */
#define DSC_has_typedef_initialize_once(tpdef) \
  template< typename T_local > \
  struct DSC_has_typedef_helper_ ## tpdef \
  { \
    template< typename TT_local > \
    struct void_ { typedef void type; }; \
  \
    template< typename TT_local, typename = void > \
    struct helper { static const bool value = false; }; \
  \
    template< typename TT_local > \
    struct helper< TT_local, typename void_< typename TT_local:: tpdef >::type > { static const bool value = true; }; \
  \
    static const bool value = helper< T_local >::value; \
  };

/**
  * \brief Macro to statically check a type for a typedef.
  *
  *        To check if a type Foo defines a typedef Bar, put this code somewhere, where a generated helper struct
  *        may be defined (obviously only once for each typedef name!):
\code
DSC_has_typedef_initialize_once(Bar)
\endcode
  *        You can then check for Bar (this will give you a static const bool):
\code
DSC_has_typedef(Bar)< Foo >::value
\endcode
  */
#define DSC_has_typedef(tpdf) \
  DSC_has_typedef_helper_ ## tpdf

/**
  * \brief Helper macro to be used before DSC_has_static_member.
  *
  *        Taken from http://stackoverflow.com/questions/11927032/sfinae-check-for-static-member-using-decltype
  */
#define DSC_has_static_member_initialize_once(mmbr) \
  template< class T_local > \
  struct DSC_has_static_member_helper_ ## mmbr \
  { \
    template< class TT_local, class = typename std::enable_if< !std::is_member_pointer< decltype(&TT_local:: mmbr) >::value>::type > \
    static std::true_type helper(int); \
  \
    template< class > \
    static std::false_type helper(...); \
  \
    static const bool value = decltype(helper< T_local >(0))::value; \
  };

/**
  * \brief Macro to statically check a class or struct for a static member.
  *
  *        To check if a class or struct Foo has a static member bar, put this code somewhere, where a generated helper
  *        struct may be defined (obviously only once for each member name!):
\code
DSC_has_static_member_initialize_once(bar)
\endcode
  *        You can then check for bar (this will give you a static const bool):
\code
DSC_has_static_member(bar)< Foo >::value
\endcode
  */
#define DSC_has_static_member(mmbr) \
  DSC_has_static_member_helper_ ## mmbr

STUFF_TYPENAME(int)
STUFF_TYPENAME(double)
STUFF_TYPENAME(float)
STUFF_TYPENAME(long)
STUFF_TYPENAME(unsigned int)
STUFF_TYPENAME(unsigned long)
STUFF_TYPENAME(char)

namespace Dune {
namespace Stuff {
namespace Common {

namespace internal {
  template< class Tt >
  struct is_complex_helper
  {
    DSC_has_typedef_initialize_once(value_type)

    static const bool is_candidate = DSC_has_typedef(value_type)< Tt >::value;
  }; // class is_complex_helper
} // namespace internal

template< class T, bool candidate = internal::is_complex_helper< T >::is_candidate >
struct is_complex
  : public std::is_base_of< std::complex< typename T::value_type >, T >
{};

template< class T >
struct is_complex< T, false >
  : public std::false_type
{};

// forward, include is below
template< class VecType >
struct VectorAbstraction;

template< class VectorType >
struct is_vector
{
  static const bool value = VectorAbstraction< VectorType >::is_vector;
};

} // namespace Common
} // namespace Stuff
} // namespace Dune

#include <dune/stuff/common/vector.hh>

#endif // DUNE_STUFF_TYPENAMES_HH
<|endoftext|>