<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include <main.h>
#include <iostream>
#include <GL/glew.h>
#include <Eigen/OpenGLSupport>
#include <GL/glut.h>
using namespace Eigen;

#define VERIFY_MATRIX(CODE,REF) { \
    glLoadIdentity(); \
    CODE; \
    Matrix4f m; m.setZero(); \
    glGet(GL_MODELVIEW_MATRIX, m); \
    if(!(REF).cast<float>().isApprox(m)) { \
      std::cerr << "Expected:\n" << ((REF).cast<float>()) << "\n" << "got\n" << m << "\n\n"; \
    } \
    VERIFY_IS_APPROX((REF).cast<float>(), m); \
  }

#define VERIFY_UNIFORM(NAME,TYPE) { \
    TYPE value; value.setRandom(); \
    TYPE data; \
    int loc = glGetUniformLocation(prg_id, #NAME); \
    VERIFY((loc!=-1) && "uniform not found"); \
    glUniform(loc,value); \
    glGetUniformfv(prg_id,loc,data.data()); \
    if(!value.isApprox(data)) { \
      std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
    } \
    VERIFY_IS_APPROX(value, data); \
  }

#define VERIFY_UNIFORMi(NAME,TYPE) { \
    TYPE value; value.setRandom(); \
    TYPE data; \
    int loc = glGetUniformLocation(prg_id, #NAME); \
    VERIFY((loc!=-1) && "uniform not found"); \
    glUniform(loc,value); \
    glGetUniformiv(prg_id,loc,(GLint*)data.data()); \
    if(!value.isApprox(data)) { \
      std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
    } \
    VERIFY_IS_APPROX(value, data); \
  }

void printInfoLog(GLuint objectID)
{
    int infologLength, charsWritten;
    GLchar *infoLog;
    glGetProgramiv(objectID,GL_INFO_LOG_LENGTH, &infologLength);
    if(infologLength > 0)
    {
        infoLog = new GLchar[infologLength];
        glGetProgramInfoLog(objectID, infologLength, &charsWritten, infoLog);
        if (charsWritten>0)
          std::cerr << "Shader info : \n" << infoLog << std::endl;
        delete[] infoLog;
    }
}

GLint createShader(const char* vtx, const char* frg)
{
  GLint prg_id = glCreateProgram();
  GLint vtx_id = glCreateShader(GL_VERTEX_SHADER);
  GLint frg_id = glCreateShader(GL_FRAGMENT_SHADER);
  GLint ok;

  glShaderSource(vtx_id, 1, &vtx, 0);
  glCompileShader(vtx_id);
  glGetShaderiv(vtx_id,GL_COMPILE_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "vtx compilation failed\n";
  }

  glShaderSource(frg_id, 1, &frg, 0);
  glCompileShader(frg_id);
  glGetShaderiv(frg_id,GL_COMPILE_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "frg compilation failed\n";
  }

  glAttachShader(prg_id, vtx_id);
  glAttachShader(prg_id, frg_id);
  glLinkProgram(prg_id);
  glGetProgramiv(prg_id,GL_LINK_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "linking failed\n";
  }
  printInfoLog(prg_id);

  glUseProgram(prg_id);
  return prg_id;
}

void test_openglsupport()
{
  int argc = 0;
  glutInit(&argc, 0);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowPosition (0,0);
  glutInitWindowSize(10, 10);

  if(glutCreateWindow("Eigen") <= 0)
  {
    std::cerr << "Error: Unable to create GLUT Window.\n";
    exit(1);
  }

  glewExperimental = GL_TRUE;
  if(glewInit() != GLEW_OK)
  {
    std::cerr << "Warning: Failed to initialize GLEW\n";
  }

  Vector3f v3f;
  Matrix3f rot;
  glBegin(GL_POINTS);

  glVertex(v3f);
  glVertex(2*v3f+v3f);
  glVertex(rot*v3f);

  glEnd();

  // 4x4 matrices
  Matrix4f mf44; mf44.setRandom();
  VERIFY_MATRIX(glLoadMatrix(mf44), mf44);
  VERIFY_MATRIX(glMultMatrix(mf44), mf44);
  Matrix4d md44; md44.setRandom();
  VERIFY_MATRIX(glLoadMatrix(md44), md44);
  VERIFY_MATRIX(glMultMatrix(md44), md44);

  // Quaternion
  Quaterniond qd(AngleAxisd(ei_random<double>(), Vector3d::Random()));
  VERIFY_MATRIX(glRotate(qd), Projective3d(qd).matrix());

  Quaternionf qf(AngleAxisf(ei_random<double>(), Vector3f::Random()));
  VERIFY_MATRIX(glRotate(qf), Projective3f(qf).matrix());

  // 3D Transform
  Transform<float,3,AffineCompact> acf3; acf3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(acf3), Projective3f(acf3).matrix());
  VERIFY_MATRIX(glMultMatrix(acf3), Projective3f(acf3).matrix());

  Transform<float,3,Affine> af3(acf3);
  VERIFY_MATRIX(glLoadMatrix(af3), Projective3f(af3).matrix());
  VERIFY_MATRIX(glMultMatrix(af3), Projective3f(af3).matrix());

  Transform<float,3,Projective> pf3; pf3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(pf3), Projective3f(pf3).matrix());
  VERIFY_MATRIX(glMultMatrix(pf3), Projective3f(pf3).matrix());

  Transform<double,3,AffineCompact> acd3; acd3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(acd3), Projective3d(acd3).matrix());
  VERIFY_MATRIX(glMultMatrix(acd3), Projective3d(acd3).matrix());

  Transform<double,3,Affine> ad3(acd3);
  VERIFY_MATRIX(glLoadMatrix(ad3), Projective3d(ad3).matrix());
  VERIFY_MATRIX(glMultMatrix(ad3), Projective3d(ad3).matrix());

  Transform<double,3,Projective> pd3; pd3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(pd3), Projective3d(pd3).matrix());
  VERIFY_MATRIX(glMultMatrix(pd3), Projective3d(pd3).matrix());

  // translations (2D and 3D)
  {
    Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 0;
    VERIFY_MATRIX(glTranslate(vf2), Projective3f(Translation3f(vf23)).matrix());
    Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 0;
    VERIFY_MATRIX(glTranslate(vd2), Projective3d(Translation3d(vd23)).matrix());

    Vector3f vf3; vf3.setRandom();
    VERIFY_MATRIX(glTranslate(vf3), Projective3f(Translation3f(vf3)).matrix());
    Vector3d vd3; vd3.setRandom();
    VERIFY_MATRIX(glTranslate(vd3), Projective3d(Translation3d(vd3)).matrix());

    Translation<float,3> tf3; tf3.vector().setRandom();
    VERIFY_MATRIX(glTranslate(tf3), Projective3f(tf3).matrix());

    Translation<double,3> td3;  td3.vector().setRandom();
    VERIFY_MATRIX(glTranslate(td3), Projective3d(td3).matrix());
  }

  // scaling (2D and 3D)
  {
    Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 1;
    VERIFY_MATRIX(glScale(vf2), Projective3f(Scaling(vf23)).matrix());
    Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 1;
    VERIFY_MATRIX(glScale(vd2), Projective3d(Scaling(vd23)).matrix());

    Vector3f vf3; vf3.setRandom();
    VERIFY_MATRIX(glScale(vf3), Projective3f(Scaling(vf3)).matrix());
    Vector3d vd3; vd3.setRandom();
    VERIFY_MATRIX(glScale(vd3), Projective3d(Scaling(vd3)).matrix());

    UniformScaling<float> usf(ei_random<float>());
    VERIFY_MATRIX(glScale(usf), Projective3f(usf).matrix());

    UniformScaling<double> usd(ei_random<double>());
    VERIFY_MATRIX(glScale(usd), Projective3d(usd).matrix());
  }

  // uniform
  {
    const char* vtx = "void main(void) { gl_Position = gl_Vertex; }\n";

    if(GLEW_VERSION_2_0)
    {
      const char* frg = ""
        "uniform vec2 v2f;\n"
        "uniform vec3 v3f;\n"
        "uniform vec4 v4f;\n"
        "uniform ivec2 v2i;\n"
        "uniform ivec3 v3i;\n"
        "uniform ivec4 v4i;\n"
        "uniform mat2 m2f;\n"
        "uniform mat3 m3f;\n"
        "uniform mat4 m4f;\n"
        "void main(void) { gl_FragColor = vec4(v2f[0]+v3f[0]+v4f[0])+vec4(v2i[0]+v3i[0]+v4i[0])+vec4(m2f[0][0]+m3f[0][0]+m4f[0][0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      VERIFY_UNIFORM(v2f, Vector2f);
      VERIFY_UNIFORM(v3f, Vector3f);
      VERIFY_UNIFORM(v4f, Vector4f);
      VERIFY_UNIFORMi(v2i, Vector2i);
      VERIFY_UNIFORMi(v3i, Vector3i);
      VERIFY_UNIFORMi(v4i, Vector4i);
      VERIFY_UNIFORM(m2f, Matrix2f);
      VERIFY_UNIFORM(m3f, Matrix3f);
      VERIFY_UNIFORM(m4f, Matrix4f);
    }
    else
      std::cerr << "Warning: opengl 2.0 was not tested\n";

    if(GLEW_VERSION_2_1)
    {
      const char* frg = "#version 120\n"
        "uniform mat2x3 m23f;\n"
        "uniform mat3x2 m32f;\n"
        "uniform mat2x4 m24f;\n"
        "uniform mat4x2 m42f;\n"
        "uniform mat3x4 m34f;\n"
        "uniform mat4x3 m43f;\n"
        "void main(void) { gl_FragColor = vec4(m23f[0][0]+m32f[0][0]+m24f[0][0]+m42f[0][0]+m34f[0][0]+m43f[0][0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      typedef Matrix<float,2,3> Matrix23f;
      typedef Matrix<float,3,2> Matrix32f;
      typedef Matrix<float,2,4> Matrix24f;
      typedef Matrix<float,4,2> Matrix42f;
      typedef Matrix<float,3,4> Matrix34f;
      typedef Matrix<float,4,3> Matrix43f;

      VERIFY_UNIFORM(m23f, Matrix23f);
      VERIFY_UNIFORM(m32f, Matrix32f);
      VERIFY_UNIFORM(m24f, Matrix24f);
      VERIFY_UNIFORM(m42f, Matrix42f);
      VERIFY_UNIFORM(m34f, Matrix34f);
      VERIFY_UNIFORM(m43f, Matrix43f);
    }
    else
      std::cerr << "Warning: opengl 2.1 was not tested\n";

    if(GLEW_VERSION_3_0)
    {
      const char* frg = "#version 150\n"
        "uniform uvec2 v2ui;\n"
        "uniform uvec3 v3ui;\n"
        "uniform uvec4 v4ui;\n"
        "out vec4 data;\n"
        "void main(void) { data = vec4(v2ui[0]+v3ui[0]+v4ui[0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      typedef Matrix<unsigned int,2,1> Vector2ui;
      typedef Matrix<unsigned int,3,1> Vector3ui;
      typedef Matrix<unsigned int,4,1> Vector4ui;

      VERIFY_UNIFORMi(v2ui, Vector2ui);
//       VERIFY_UNIFORMi(v3ui, Vector3ui);
//       VERIFY_UNIFORMi(v4ui, Vector4ui);
    }
    else
      std::cerr << "Warning: opengl 3.0 was not tested\n";
  }

}
<commit_msg>uncomment commented line for debug<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include <main.h>
#include <iostream>
#include <GL/glew.h>
#include <Eigen/OpenGLSupport>
#include <GL/glut.h>
using namespace Eigen;

#define VERIFY_MATRIX(CODE,REF) { \
    glLoadIdentity(); \
    CODE; \
    Matrix4f m; m.setZero(); \
    glGet(GL_MODELVIEW_MATRIX, m); \
    if(!(REF).cast<float>().isApprox(m)) { \
      std::cerr << "Expected:\n" << ((REF).cast<float>()) << "\n" << "got\n" << m << "\n\n"; \
    } \
    VERIFY_IS_APPROX((REF).cast<float>(), m); \
  }

#define VERIFY_UNIFORM(NAME,TYPE) { \
    TYPE value; value.setRandom(); \
    TYPE data; \
    int loc = glGetUniformLocation(prg_id, #NAME); \
    VERIFY((loc!=-1) && "uniform not found"); \
    glUniform(loc,value); \
    glGetUniformfv(prg_id,loc,data.data()); \
    if(!value.isApprox(data)) { \
      std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
    } \
    VERIFY_IS_APPROX(value, data); \
  }

#define VERIFY_UNIFORMi(NAME,TYPE) { \
    TYPE value; value.setRandom(); \
    TYPE data; \
    int loc = glGetUniformLocation(prg_id, #NAME); \
    VERIFY((loc!=-1) && "uniform not found"); \
    glUniform(loc,value); \
    glGetUniformiv(prg_id,loc,(GLint*)data.data()); \
    if(!value.isApprox(data)) { \
      std::cerr << "Expected:\n" << value << "\n" << "got\n" << data << "\n\n"; \
    } \
    VERIFY_IS_APPROX(value, data); \
  }

void printInfoLog(GLuint objectID)
{
    int infologLength, charsWritten;
    GLchar *infoLog;
    glGetProgramiv(objectID,GL_INFO_LOG_LENGTH, &infologLength);
    if(infologLength > 0)
    {
        infoLog = new GLchar[infologLength];
        glGetProgramInfoLog(objectID, infologLength, &charsWritten, infoLog);
        if (charsWritten>0)
          std::cerr << "Shader info : \n" << infoLog << std::endl;
        delete[] infoLog;
    }
}

GLint createShader(const char* vtx, const char* frg)
{
  GLint prg_id = glCreateProgram();
  GLint vtx_id = glCreateShader(GL_VERTEX_SHADER);
  GLint frg_id = glCreateShader(GL_FRAGMENT_SHADER);
  GLint ok;

  glShaderSource(vtx_id, 1, &vtx, 0);
  glCompileShader(vtx_id);
  glGetShaderiv(vtx_id,GL_COMPILE_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "vtx compilation failed\n";
  }

  glShaderSource(frg_id, 1, &frg, 0);
  glCompileShader(frg_id);
  glGetShaderiv(frg_id,GL_COMPILE_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "frg compilation failed\n";
  }

  glAttachShader(prg_id, vtx_id);
  glAttachShader(prg_id, frg_id);
  glLinkProgram(prg_id);
  glGetProgramiv(prg_id,GL_LINK_STATUS,&ok);
  if(!ok)
  {
    std::cerr << "linking failed\n";
  }
  printInfoLog(prg_id);

  glUseProgram(prg_id);
  return prg_id;
}

void test_openglsupport()
{
  int argc = 0;
  glutInit(&argc, 0);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowPosition (0,0);
  glutInitWindowSize(10, 10);

  if(glutCreateWindow("Eigen") <= 0)
  {
    std::cerr << "Error: Unable to create GLUT Window.\n";
    exit(1);
  }

  glewExperimental = GL_TRUE;
  if(glewInit() != GLEW_OK)
  {
    std::cerr << "Warning: Failed to initialize GLEW\n";
  }

  Vector3f v3f;
  Matrix3f rot;
  glBegin(GL_POINTS);

  glVertex(v3f);
  glVertex(2*v3f+v3f);
  glVertex(rot*v3f);

  glEnd();

  // 4x4 matrices
  Matrix4f mf44; mf44.setRandom();
  VERIFY_MATRIX(glLoadMatrix(mf44), mf44);
  VERIFY_MATRIX(glMultMatrix(mf44), mf44);
  Matrix4d md44; md44.setRandom();
  VERIFY_MATRIX(glLoadMatrix(md44), md44);
  VERIFY_MATRIX(glMultMatrix(md44), md44);

  // Quaternion
  Quaterniond qd(AngleAxisd(ei_random<double>(), Vector3d::Random()));
  VERIFY_MATRIX(glRotate(qd), Projective3d(qd).matrix());

  Quaternionf qf(AngleAxisf(ei_random<double>(), Vector3f::Random()));
  VERIFY_MATRIX(glRotate(qf), Projective3f(qf).matrix());

  // 3D Transform
  Transform<float,3,AffineCompact> acf3; acf3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(acf3), Projective3f(acf3).matrix());
  VERIFY_MATRIX(glMultMatrix(acf3), Projective3f(acf3).matrix());

  Transform<float,3,Affine> af3(acf3);
  VERIFY_MATRIX(glLoadMatrix(af3), Projective3f(af3).matrix());
  VERIFY_MATRIX(glMultMatrix(af3), Projective3f(af3).matrix());

  Transform<float,3,Projective> pf3; pf3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(pf3), Projective3f(pf3).matrix());
  VERIFY_MATRIX(glMultMatrix(pf3), Projective3f(pf3).matrix());

  Transform<double,3,AffineCompact> acd3; acd3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(acd3), Projective3d(acd3).matrix());
  VERIFY_MATRIX(glMultMatrix(acd3), Projective3d(acd3).matrix());

  Transform<double,3,Affine> ad3(acd3);
  VERIFY_MATRIX(glLoadMatrix(ad3), Projective3d(ad3).matrix());
  VERIFY_MATRIX(glMultMatrix(ad3), Projective3d(ad3).matrix());

  Transform<double,3,Projective> pd3; pd3.matrix().setRandom();
  VERIFY_MATRIX(glLoadMatrix(pd3), Projective3d(pd3).matrix());
  VERIFY_MATRIX(glMultMatrix(pd3), Projective3d(pd3).matrix());

  // translations (2D and 3D)
  {
    Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 0;
    VERIFY_MATRIX(glTranslate(vf2), Projective3f(Translation3f(vf23)).matrix());
    Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 0;
    VERIFY_MATRIX(glTranslate(vd2), Projective3d(Translation3d(vd23)).matrix());

    Vector3f vf3; vf3.setRandom();
    VERIFY_MATRIX(glTranslate(vf3), Projective3f(Translation3f(vf3)).matrix());
    Vector3d vd3; vd3.setRandom();
    VERIFY_MATRIX(glTranslate(vd3), Projective3d(Translation3d(vd3)).matrix());

    Translation<float,3> tf3; tf3.vector().setRandom();
    VERIFY_MATRIX(glTranslate(tf3), Projective3f(tf3).matrix());

    Translation<double,3> td3;  td3.vector().setRandom();
    VERIFY_MATRIX(glTranslate(td3), Projective3d(td3).matrix());
  }

  // scaling (2D and 3D)
  {
    Vector2f vf2; vf2.setRandom(); Vector3f vf23; vf23 << vf2, 1;
    VERIFY_MATRIX(glScale(vf2), Projective3f(Scaling(vf23)).matrix());
    Vector2d vd2; vd2.setRandom(); Vector3d vd23; vd23 << vd2, 1;
    VERIFY_MATRIX(glScale(vd2), Projective3d(Scaling(vd23)).matrix());

    Vector3f vf3; vf3.setRandom();
    VERIFY_MATRIX(glScale(vf3), Projective3f(Scaling(vf3)).matrix());
    Vector3d vd3; vd3.setRandom();
    VERIFY_MATRIX(glScale(vd3), Projective3d(Scaling(vd3)).matrix());

    UniformScaling<float> usf(ei_random<float>());
    VERIFY_MATRIX(glScale(usf), Projective3f(usf).matrix());

    UniformScaling<double> usd(ei_random<double>());
    VERIFY_MATRIX(glScale(usd), Projective3d(usd).matrix());
  }

  // uniform
  {
    const char* vtx = "void main(void) { gl_Position = gl_Vertex; }\n";

    if(GLEW_VERSION_2_0)
    {
      const char* frg = ""
        "uniform vec2 v2f;\n"
        "uniform vec3 v3f;\n"
        "uniform vec4 v4f;\n"
        "uniform ivec2 v2i;\n"
        "uniform ivec3 v3i;\n"
        "uniform ivec4 v4i;\n"
        "uniform mat2 m2f;\n"
        "uniform mat3 m3f;\n"
        "uniform mat4 m4f;\n"
        "void main(void) { gl_FragColor = vec4(v2f[0]+v3f[0]+v4f[0])+vec4(v2i[0]+v3i[0]+v4i[0])+vec4(m2f[0][0]+m3f[0][0]+m4f[0][0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      VERIFY_UNIFORM(v2f, Vector2f);
      VERIFY_UNIFORM(v3f, Vector3f);
      VERIFY_UNIFORM(v4f, Vector4f);
      VERIFY_UNIFORMi(v2i, Vector2i);
      VERIFY_UNIFORMi(v3i, Vector3i);
      VERIFY_UNIFORMi(v4i, Vector4i);
      VERIFY_UNIFORM(m2f, Matrix2f);
      VERIFY_UNIFORM(m3f, Matrix3f);
      VERIFY_UNIFORM(m4f, Matrix4f);
    }
    else
      std::cerr << "Warning: opengl 2.0 was not tested\n";

    if(GLEW_VERSION_2_1)
    {
      const char* frg = "#version 120\n"
        "uniform mat2x3 m23f;\n"
        "uniform mat3x2 m32f;\n"
        "uniform mat2x4 m24f;\n"
        "uniform mat4x2 m42f;\n"
        "uniform mat3x4 m34f;\n"
        "uniform mat4x3 m43f;\n"
        "void main(void) { gl_FragColor = vec4(m23f[0][0]+m32f[0][0]+m24f[0][0]+m42f[0][0]+m34f[0][0]+m43f[0][0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      typedef Matrix<float,2,3> Matrix23f;
      typedef Matrix<float,3,2> Matrix32f;
      typedef Matrix<float,2,4> Matrix24f;
      typedef Matrix<float,4,2> Matrix42f;
      typedef Matrix<float,3,4> Matrix34f;
      typedef Matrix<float,4,3> Matrix43f;

      VERIFY_UNIFORM(m23f, Matrix23f);
      VERIFY_UNIFORM(m32f, Matrix32f);
      VERIFY_UNIFORM(m24f, Matrix24f);
      VERIFY_UNIFORM(m42f, Matrix42f);
      VERIFY_UNIFORM(m34f, Matrix34f);
      VERIFY_UNIFORM(m43f, Matrix43f);
    }
    else
      std::cerr << "Warning: opengl 2.1 was not tested\n";

    if(GLEW_VERSION_3_0)
    {
      const char* frg = "#version 150\n"
        "uniform uvec2 v2ui;\n"
        "uniform uvec3 v3ui;\n"
        "uniform uvec4 v4ui;\n"
        "out vec4 data;\n"
        "void main(void) { data = vec4(v2ui[0]+v3ui[0]+v4ui[0]); }\n";

      GLint prg_id = createShader(vtx,frg);

      typedef Matrix<unsigned int,2,1> Vector2ui;
      typedef Matrix<unsigned int,3,1> Vector3ui;
      typedef Matrix<unsigned int,4,1> Vector4ui;

      VERIFY_UNIFORMi(v2ui, Vector2ui);
      VERIFY_UNIFORMi(v3ui, Vector3ui);
      VERIFY_UNIFORMi(v4ui, Vector4ui);
    }
    else
      std::cerr << "Warning: opengl 3.0 was not tested\n";
  }

}
<|endoftext|>


<commit_before>#include "qleveldb.h"
#include "qleveldbbatch.h"
#include "global.h"
#include <qqmlinfo.h>
#include <qqmlengine.h>
#include <QJsonDocument>
#include <QQmlEngine>

static QHash<QString, QWeakPointer<leveldb::DB> > leveldbInstances;
static QMultiHash<QString, QLevelDB*> qLeveldbInstances;
/*!
  \qmltype LevelDB
  \inqmlmodule QtLevelDB
  \brief Low level API to access LevelDB database.

*/
QLevelDB::QLevelDB(QObject *parent)
    : QObject(parent)
    , m_batch(nullptr)
    , m_initialized(false)
    , m_opened(false)
    , m_status(Status::Undefined)
    , m_statusText("")
{
}

QLevelDB::~QLevelDB()
{
    reset();
}

void QLevelDB::classBegin()
{
}

void QLevelDB::componentComplete()
{
    openDatabase(m_source.toLocalFile());
    m_initialized = true;
}

/*!
  \qmlproperty boolean LevelDB::opened
  \readonly
  \brief show when the database is ready to do operations
*/
bool QLevelDB::opened() const
{
    return m_opened;
}

/*!
  \qmlproperty url LevelDB::source
  \brief url that points to the leveldb database folder.

  For now it's only possible to use local file paths.
*/
QUrl QLevelDB::source() const
{
    return m_source;
}

/*!
  \qmlproperty enumeration LevelDB::status
  \brief This property holds information error in case the database is unable to load.
  \table
  \header
    \li {2, 1} \e {LevelDB::Status} is an enumeration:
  \header
    \li Type
    \li Description
  \row
    \li Layer.Undefined (default)
    \li Database is in a unkown state(probably unintialized)
  \row
    \li Layout.Ok
    \li Operation runs ok
  \row
    \li Layout.NotFound
    \li A value is not found for a Key, during get()
  \row
    \li Layout.InvalidArgument
    \li TODO
  \row
    \li Layout.IOError
    \li TODO
  \endtable
*/
QLevelDB::Status QLevelDB::status() const
{
    return m_status;
}

/*!
  \qmlproperty string LevelDB::statusText
  \brief String information about an error when it occurs
*/
QString QLevelDB::statusText() const
{
    return m_statusText;
}

void QLevelDB::setSource(QUrl source)
{

    if (m_source != source){
        m_source = source;
        emit sourceChanged();
        if (m_initialized)
            openDatabase(source.toLocalFile());
    }
}

QLevelDBOptions *QLevelDB::options()
{
    leveldb::WriteOptions options;
    return &m_options;
}

/*!
  \qmlmethod QLevelDBBatch* QLevelDB::batch()
  \brief Return an batch item to do batch operations

   The rayCast method is only useful with physics is enabled.
*/
QLevelDBBatch* QLevelDB::batch()
{
    if (m_batch)
        m_batch->deleteLater();
    m_batch = new QLevelDBBatch(m_levelDB, this);
    connect(m_batch, &QLevelDBBatch::batchWritten, this, &QLevelDB::onBatchWritten);
    return m_batch;
}

/*!
 * \qmlmethod bool QLevelDB::del(QString key)
*/
bool QLevelDB::del(QString key)
{
    leveldb::WriteOptions options;
    leveldb::Status status = m_levelDB.data()->Delete(options, leveldb::Slice(key.toStdString()));

    return status.ok();
}

bool QLevelDB::put(QString key, QVariant value)
{
    QVariant oldValue = get(key);
    //avoid inifine loops
    if(oldValue == value)
        return true;
    leveldb::WriteOptions options;
    QString json = variantToJson(value);
    if (m_opened && m_levelDB){
        leveldb::Status status = m_levelDB->Put(options,
                                                leveldb::Slice(key.toStdString()),
                                                leveldb::Slice(json.toStdString()));
        if(status.ok()){
            dispatchPropertyChange(key, value);
        }
        return status.ok();
    }
    return false;
}

bool QLevelDB::putSync(QString key, QVariant value)
{
    QVariant oldValue = get(key);
    //avoid inifine loops
    if(oldValue == value)
        return true;
    leveldb::WriteOptions options;
    QString json = variantToJson(value);
    options.sync = true;
    if (m_opened && m_levelDB){
        leveldb::Status status = m_levelDB->Put(options,
                                                leveldb::Slice(key.toStdString()),
                                                leveldb::Slice(json.toStdString()));
        if(status.ok()){
            dispatchPropertyChange(key, value);
        }
        return status.ok();
    }
    return false;
}

QVariant QLevelDB::get(QString key, QVariant defaultValue)
{
    leveldb::ReadOptions options;
    std::string value = "";
    if (m_opened && !m_levelDB.isNull()){
        leveldb::Status status = m_levelDB.data()->Get(options,
                                                leveldb::Slice(key.toStdString()),
                                                &value);
        if (status.ok())
            return jsonToVariant(QString::fromStdString(value));
    }
    return defaultValue;
}

bool QLevelDB::destroyDB(QUrl path)
{
    if (!path.isLocalFile())
        return Status::InvalidArgument;
    if(m_source == path){
        reset();
    }
    leveldb::Options options;
    leveldb::Status status = leveldb::DestroyDB(path.toLocalFile().toStdString(), options);
    return status.ok();
}

bool QLevelDB::repairDB(QUrl path)
{
    if (!path.isLocalFile())
        return Status::InvalidArgument;
    leveldb::Options options;
    leveldb::Status status = leveldb::RepairDB(path.toLocalFile().toStdString(), options);
    return status.ok();
}

void QLevelDB::setStatus(QLevelDB::Status status)
{
    if (m_status != status){
        m_status = status;
        emit statusChanged();
    }
}

void QLevelDB::setStatusText(QString text)
{
    if (m_statusText != text){
        m_statusText = text;
        emit statusTextChanged();
    }
}

void QLevelDB::setOpened(bool opened)
{
    if (m_opened != opened){
        m_opened = opened;
        emit openedChanged();
    }
}

bool QLevelDB::openDatabase(QString localPath)
{
    reset();

    if (leveldbInstances.contains(localPath) && !leveldbInstances[localPath].isNull()){
        //if there is an instance running, just grab the db
            m_levelDB = leveldbInstances[localPath].toStrongRef();
            setOpened(true);
            setStatus(Ok);
            setStatusText("ok");
    }else {
        //else create a DB object
        leveldb::DB *db;
        leveldb::Options options = m_options.leveldbOptions();
        leveldb::Status status = leveldb::DB::Open(options,
                                                   localPath.toStdString(),
                                                   &db);
        if(status.ok()){
            m_levelDB.reset(db);
            leveldbInstances.insert(localPath, m_levelDB.toWeakRef());
        }
        setOpened(status.ok());
        setStatusText(QString::fromStdString(status.ToString()));
        Status code = parseStatusCode(status);
        setStatus(code);
    }
    if (m_opened){
        qLeveldbInstances.insertMulti(localPath, this);
    }
    return m_opened;
}

void QLevelDB::reset()
{
    m_levelDB.clear();
    QWeakPointer<leveldb::DB> pointer = leveldbInstances[m_source.toLocalFile()];
    if (pointer.isNull())
        leveldbInstances.remove(m_source.toLocalFile());

    for (auto key : qLeveldbInstances.keys()){
        qLeveldbInstances.remove(key, this);
    }
    setStatus(Status::Undefined);
    setOpened(false);
    setStatusText(QString());
}

void QLevelDB::onBatchWritten(QSet<QString> keys)
{
    for (auto key : keys){
        dispatchPropertyChange(key, get(key, QVariant()));
    }
}

QLevelDB::Status QLevelDB::parseStatusCode(leveldb::Status &status)
{
    if (status.ok())
        return Status::Ok;
    if (status.IsCorruption())
        return Status::Corruption;
    if (status.IsIOError())
        return Status::IOError;
    if (status.IsNotFound())
        return Status::NotFound;
    return Status::Undefined;
}

void QLevelDB::dispatchPropertyChange(QString key, QVariant value)
{
    QString local = m_source.toLocalFile();
    QMultiHash<QString, QLevelDB*>::iterator i = qLeveldbInstances.find(local);
    while (i != qLeveldbInstances.end() && i.key() == local) {
       emit i.value()->propertyChanged(key, value);
        ++i;
    }
}

<commit_msg>create database directories in path if don't exist<commit_after>#include "qleveldb.h"
#include "qleveldbbatch.h"
#include "global.h"
#include <qqmlinfo.h>
#include <qqmlengine.h>
#include <QJsonDocument>
#include <QQmlEngine>

static QHash<QString, QWeakPointer<leveldb::DB> > leveldbInstances;
static QMultiHash<QString, QLevelDB*> qLeveldbInstances;
/*!
  \qmltype LevelDB
  \inqmlmodule QtLevelDB
  \brief Low level API to access LevelDB database.

*/
QLevelDB::QLevelDB(QObject *parent)
    : QObject(parent)
    , m_batch(nullptr)
    , m_initialized(false)
    , m_opened(false)
    , m_status(Status::Undefined)
    , m_statusText("")
{
}

QLevelDB::~QLevelDB()
{
    reset();
}

void QLevelDB::classBegin()
{
}

void QLevelDB::componentComplete()
{
    openDatabase(m_source.toLocalFile());
    m_initialized = true;
}

/*!
  \qmlproperty boolean LevelDB::opened
  \readonly
  \brief show when the database is ready to do operations
*/
bool QLevelDB::opened() const
{
    return m_opened;
}

/*!
  \qmlproperty url LevelDB::source
  \brief url that points to the leveldb database folder.

  For now it's only possible to use local file paths.
*/
QUrl QLevelDB::source() const
{
    return m_source;
}

/*!
  \qmlproperty enumeration LevelDB::status
  \brief This property holds information error in case the database is unable to load.
  \table
  \header
    \li {2, 1} \e {LevelDB::Status} is an enumeration:
  \header
    \li Type
    \li Description
  \row
    \li Layer.Undefined (default)
    \li Database is in a unkown state(probably unintialized)
  \row
    \li Layout.Ok
    \li Operation runs ok
  \row
    \li Layout.NotFound
    \li A value is not found for a Key, during get()
  \row
    \li Layout.InvalidArgument
    \li TODO
  \row
    \li Layout.IOError
    \li TODO
  \endtable
*/
QLevelDB::Status QLevelDB::status() const
{
    return m_status;
}

/*!
  \qmlproperty string LevelDB::statusText
  \brief String information about an error when it occurs
*/
QString QLevelDB::statusText() const
{
    return m_statusText;
}

void QLevelDB::setSource(QUrl source)
{

    if (m_source != source){
        m_source = source;
        emit sourceChanged();
        if (m_initialized)
            openDatabase(source.toLocalFile());
    }
}

QLevelDBOptions *QLevelDB::options()
{
    leveldb::WriteOptions options;
    return &m_options;
}

/*!
  \qmlmethod QLevelDBBatch* QLevelDB::batch()
  \brief Return an batch item to do batch operations

   The rayCast method is only useful with physics is enabled.
*/
QLevelDBBatch* QLevelDB::batch()
{
    if (m_batch)
        m_batch->deleteLater();
    m_batch = new QLevelDBBatch(m_levelDB, this);
    connect(m_batch, &QLevelDBBatch::batchWritten, this, &QLevelDB::onBatchWritten);
    return m_batch;
}

/*!
 * \qmlmethod bool QLevelDB::del(QString key)
*/
bool QLevelDB::del(QString key)
{
    leveldb::WriteOptions options;
    leveldb::Status status = m_levelDB.data()->Delete(options, leveldb::Slice(key.toStdString()));

    return status.ok();
}

bool QLevelDB::put(QString key, QVariant value)
{
    QVariant oldValue = get(key);
    //avoid inifine loops
    if(oldValue == value)
        return true;
    leveldb::WriteOptions options;
    QString json = variantToJson(value);
    if (m_opened && m_levelDB){
        leveldb::Status status = m_levelDB->Put(options,
                                                leveldb::Slice(key.toStdString()),
                                                leveldb::Slice(json.toStdString()));
        if(status.ok()){
            dispatchPropertyChange(key, value);
        }
        return status.ok();
    }
    return false;
}

bool QLevelDB::putSync(QString key, QVariant value)
{
    QVariant oldValue = get(key);
    //avoid inifine loops
    if(oldValue == value)
        return true;
    leveldb::WriteOptions options;
    QString json = variantToJson(value);
    options.sync = true;
    if (m_opened && m_levelDB){
        leveldb::Status status = m_levelDB->Put(options,
                                                leveldb::Slice(key.toStdString()),
                                                leveldb::Slice(json.toStdString()));
        if(status.ok()){
            dispatchPropertyChange(key, value);
        }
        return status.ok();
    }
    return false;
}

QVariant QLevelDB::get(QString key, QVariant defaultValue)
{
    leveldb::ReadOptions options;
    std::string value = "";
    if (m_opened && !m_levelDB.isNull()){
        leveldb::Status status = m_levelDB.data()->Get(options,
                                                leveldb::Slice(key.toStdString()),
                                                &value);
        if (status.ok())
            return jsonToVariant(QString::fromStdString(value));
    }
    return defaultValue;
}

bool QLevelDB::destroyDB(QUrl path)
{
    if (!path.isLocalFile())
        return Status::InvalidArgument;
    if(m_source == path){
        reset();
    }
    leveldb::Options options;
    leveldb::Status status = leveldb::DestroyDB(path.toLocalFile().toStdString(), options);
    return status.ok();
}

bool QLevelDB::repairDB(QUrl path)
{
    if (!path.isLocalFile())
        return Status::InvalidArgument;
    leveldb::Options options;
    leveldb::Status status = leveldb::RepairDB(path.toLocalFile().toStdString(), options);
    return status.ok();
}

void QLevelDB::setStatus(QLevelDB::Status status)
{
    if (m_status != status){
        m_status = status;
        emit statusChanged();
    }
}

void QLevelDB::setStatusText(QString text)
{
    if (m_statusText != text){
        m_statusText = text;
        emit statusTextChanged();
    }
}

void QLevelDB::setOpened(bool opened)
{
    if (m_opened != opened){
        m_opened = opened;
        emit openedChanged();
    }
}

bool QLevelDB::openDatabase(QString localPath)
{
    reset();

    if (leveldbInstances.contains(localPath) && !leveldbInstances[localPath].isNull()){
        //if there is an instance running, just grab the db
            m_levelDB = leveldbInstances[localPath].toStrongRef();
            setOpened(true);
            setStatus(Ok);
            setStatusText("ok");
    }else {
        //create directories in path
        QFileInfo fileInfo(localPath);
        if(!fileInfo.dir().exists()){
            fileInfo.dir().mkpath(fileInfo.dir().absolutePath());
        }
        //else create a DB object
        leveldb::DB *db;
        leveldb::Options options = m_options.leveldbOptions();
        leveldb::Status status = leveldb::DB::Open(options,
                                                   localPath.toStdString(),
                                                   &db);
        if(status.ok()){
            m_levelDB.reset(db);
            leveldbInstances.insert(localPath, m_levelDB.toWeakRef());
        }
        setOpened(status.ok());
        setStatusText(QString::fromStdString(status.ToString()));
        Status code = parseStatusCode(status);
        setStatus(code);
    }
    if (m_opened){
        qLeveldbInstances.insertMulti(localPath, this);
    }
    return m_opened;
}

void QLevelDB::reset()
{
    m_levelDB.clear();
    QWeakPointer<leveldb::DB> pointer = leveldbInstances[m_source.toLocalFile()];
    if (pointer.isNull())
        leveldbInstances.remove(m_source.toLocalFile());

    for (auto key : qLeveldbInstances.keys()){
        qLeveldbInstances.remove(key, this);
    }
    setStatus(Status::Undefined);
    setOpened(false);
    setStatusText(QString());
}

void QLevelDB::onBatchWritten(QSet<QString> keys)
{
    for (auto key : keys){
        dispatchPropertyChange(key, get(key, QVariant()));
    }
}

QLevelDB::Status QLevelDB::parseStatusCode(leveldb::Status &status)
{
    if (status.ok())
        return Status::Ok;
    if (status.IsCorruption())
        return Status::Corruption;
    if (status.IsIOError())
        return Status::IOError;
    if (status.IsNotFound())
        return Status::NotFound;
    return Status::Undefined;
}

void QLevelDB::dispatchPropertyChange(QString key, QVariant value)
{
    QString local = m_source.toLocalFile();
    QMultiHash<QString, QLevelDB*>::iterator i = qLeveldbInstances.find(local);
    while (i != qLeveldbInstances.end() && i.key() == local) {
       emit i.value()->propertyChanged(key, value);
        ++i;
    }
}

<|endoftext|>


<commit_before>/**
 * Extract features and score statistics from nvest file, optionally merging with
 * those from the previous iteration.
 * Developed during the 2nd MT marathon.
 **/

#include <iostream>
#include <string>
#include <vector>

#include <getopt.h>
#include <boost/scoped_ptr.hpp>

#include "Data.h"
#include "Scorer.h"
#include "ScorerFactory.h"
#include "Timer.h"
#include "Util.h"

using namespace std;
using namespace MosesTuning;

namespace {

void usage()
{
  cerr << "usage: extractor [options])" << endl;
  cerr << "[--sctype|-s] the scorer type (default BLEU)" << endl;
  cerr << "[--scconfig|-c] configuration string passed to scorer" << endl;
  cerr << "\tThis is of the form NAME1:VAL1,NAME2:VAL2 etc " << endl;
  cerr << "[--reference|-r] comma separated list of reference files" << endl;
  cerr << "[--binary|-b] use binary output format (default to text )" << endl;
  cerr << "[--nbest|-n] the nbest file" << endl;
  cerr << "[--scfile|-S] the scorer data output file" << endl;
  cerr << "[--ffile|-F] the feature data output file" << endl;
  cerr << "[--prev-ffile|-E] comma separated list of previous feature data" << endl;
  cerr << "[--prev-scfile|-R] comma separated list of previous scorer data" << endl;
  cerr << "[--factors|-f] list of factors passed to the scorer (e.g. 0|2)" << endl;
  cerr << "[--filter|-l] filter command used to preprocess the sentences" << endl;
  cerr << "[--allow-duplicates|-d] omit the duplicate removal step" << endl;
  cerr << "[-v] verbose level" << endl;
  cerr << "[--help|-h] print this message and exit" << endl;
  exit(1);
}

static struct option long_options[] = {
  {"sctype", required_argument, 0, 's'},
  {"scconfig", required_argument,0, 'c'},
  {"factors", required_argument,0, 'f'},
  {"filter", required_argument,0, 'l'},
  {"reference", required_argument, 0, 'r'},
  {"binary", no_argument, 0, 'b'},
  {"nbest", required_argument, 0, 'n'},
  {"scfile", required_argument, 0, 'S'},
  {"ffile", required_argument, 0, 'F'},
  {"prev-scfile", required_argument, 0, 'R'},
  {"prev-ffile", required_argument, 0, 'E'},
  {"verbose", required_argument, 0, 'v'},
  {"help", no_argument, 0, 'h'},
  {"allow-duplicates", no_argument, 0, 'd'},
  {0, 0, 0, 0}
};

// Command line options used in extractor.
struct ProgramOption {
  string scorerType;
  string scorerConfig;
  string scorerFactors;
  string scorerFilter;
  string referenceFile;
  string nbestFile;
  string scoreDataFile;
  string featureDataFile;
  string prevScoreDataFile;
  string prevFeatureDataFile;
  bool binmode;
  bool allowDuplicates;
  int verbosity;

  ProgramOption()
      : scorerType("BLEU"),
        scorerConfig(""),
        scorerFactors(""),
        scorerFilter(""),
        referenceFile(""),
        nbestFile(""),
        scoreDataFile("statscore.data"),
        featureDataFile("features.data"),
        prevScoreDataFile(""),
        prevFeatureDataFile(""),
        binmode(false),
        allowDuplicates(false),
        verbosity(0) { }
};

void ParseCommandOptions(int argc, char** argv, ProgramOption* opt) {
  int c;
  int option_index;

  while ((c = getopt_long(argc, argv, "s:r:f:l:n:S:F:R:E:v:hb", long_options, &option_index)) != -1) {
    switch (c) {
      case 's':
        opt->scorerType = string(optarg);
        break;
      case 'c':
        opt->scorerConfig = string(optarg);
        break;
      case 'f':
        opt->scorerFactors = string(optarg);
        break;
      case 'l':
        opt->scorerFilter = string(optarg);
        break;
      case 'r':
        opt->referenceFile = string(optarg);
        break;
      case 'b':
        opt->binmode = true;
        break;
      case 'n':
        opt->nbestFile = string(optarg);
        break;
      case 'S':
        opt->scoreDataFile = string(optarg);
        break;
      case 'F':
        opt->featureDataFile = string(optarg);
        break;
      case 'E':
        opt->prevFeatureDataFile = string(optarg);
        break;
      case 'R':
        opt->prevScoreDataFile = string(optarg);
        break;
      case 'v':
        opt->verbosity = atoi(optarg);
        break;
      case 'd':
        opt->allowDuplicates = true;
        break;
      default:
        usage();
    }
  }
}

} // anonymous namespace

int main(int argc, char** argv)
{
  ResetUserTime();

  ProgramOption option;
  ParseCommandOptions(argc, argv, &option);

  try {
    // check whether score statistics file is specified
    if (option.scoreDataFile.length() == 0) {
      throw runtime_error("Error: output score statistics file is not specified");
    }

    // check wheter feature file is specified
    if (option.featureDataFile.length() == 0) {
      throw runtime_error("Error: output feature file is not specified");
    }

    // check whether reference file is specified when nbest is specified
    if ((option.nbestFile.length() > 0 && option.referenceFile.length() == 0)) {
      throw runtime_error("Error: reference file is not specified; you can not score the nbest");
    }

    vector<string> nbestFiles;
    if (option.nbestFile.length() > 0) {
      Tokenize(option.nbestFile.c_str(), ',', &nbestFiles);
    }

    vector<string> referenceFiles;
    if (option.referenceFile.length() > 0) {
      Tokenize(option.referenceFile.c_str(), ',', &referenceFiles);
    }

    vector<string> prevScoreDataFiles;
    if (option.prevScoreDataFile.length() > 0) {
      Tokenize(option.prevScoreDataFile.c_str(), ',', &prevScoreDataFiles);
    }

    vector<string> prevFeatureDataFiles;
    if (option.prevFeatureDataFile.length() > 0) {
      Tokenize(option.prevFeatureDataFile.c_str(), ',', &prevFeatureDataFiles);
    }

    if (prevScoreDataFiles.size() != prevFeatureDataFiles.size()) {
      throw runtime_error("Error: there is a different number of previous score and feature files");
    }

    if (option.binmode) {
      cerr << "Binary write mode is selected" << endl;
    } else {
      cerr << "Binary write mode is NOT selected" << endl;
    }

    TRACE_ERR("Scorer type: " << option.scorerType << endl);

    boost::scoped_ptr<Scorer> scorer(
        ScorerFactory::getScorer(option.scorerType, option.scorerConfig));

    // set Factors and Filter used to preprocess the sentences
    scorer->setFactors(option.scorerFactors);
    scorer->setFilter(option.scorerFilter);

    // load references
    if (referenceFiles.size() > 0)
      scorer->setReferenceFiles(referenceFiles);

    PrintUserTime("References loaded");

    Data data(scorer.get());

    // load old data
    for (size_t i = 0; i < prevScoreDataFiles.size(); i++) {
      data.load(prevFeatureDataFiles.at(i), prevScoreDataFiles.at(i));
    }

    PrintUserTime("Previous data loaded");

    // computing score statistics of each nbest file
    for (size_t i = 0; i < nbestFiles.size(); i++) {
      data.loadNBest(nbestFiles.at(i));
    }

    PrintUserTime("Nbest entries loaded and scored");

    //ADDED_BY_TS
    if (!option.allowDuplicates) {
      data.removeDuplicates();
    }
    //END_ADDED

    data.save(option.featureDataFile, option.scoreDataFile, option.binmode);
    PrintUserTime("Stopping...");

    return EXIT_SUCCESS;
  } catch (const exception& e) {
    cerr << "Exception: " << e.what() << endl;
    return EXIT_FAILURE;
  }
}
<commit_msg>enable single character option<commit_after>/**
 * Extract features and score statistics from nvest file, optionally merging with
 * those from the previous iteration.
 * Developed during the 2nd MT marathon.
 **/

#include <iostream>
#include <string>
#include <vector>

#include <getopt.h>
#include <boost/scoped_ptr.hpp>

#include "Data.h"
#include "Scorer.h"
#include "ScorerFactory.h"
#include "Timer.h"
#include "Util.h"

using namespace std;
using namespace MosesTuning;

namespace {

void usage()
{
  cerr << "usage: extractor [options])" << endl;
  cerr << "[--sctype|-s] the scorer type (default BLEU)" << endl;
  cerr << "[--scconfig|-c] configuration string passed to scorer" << endl;
  cerr << "\tThis is of the form NAME1:VAL1,NAME2:VAL2 etc " << endl;
  cerr << "[--reference|-r] comma separated list of reference files" << endl;
  cerr << "[--binary|-b] use binary output format (default to text )" << endl;
  cerr << "[--nbest|-n] the nbest file" << endl;
  cerr << "[--scfile|-S] the scorer data output file" << endl;
  cerr << "[--ffile|-F] the feature data output file" << endl;
  cerr << "[--prev-ffile|-E] comma separated list of previous feature data" << endl;
  cerr << "[--prev-scfile|-R] comma separated list of previous scorer data" << endl;
  cerr << "[--factors|-f] list of factors passed to the scorer (e.g. 0|2)" << endl;
  cerr << "[--filter|-l] filter command used to preprocess the sentences" << endl;
  cerr << "[--allow-duplicates|-d] omit the duplicate removal step" << endl;
  cerr << "[-v] verbose level" << endl;
  cerr << "[--help|-h] print this message and exit" << endl;
  exit(1);
}

static struct option long_options[] = {
  {"sctype", required_argument, 0, 's'},
  {"scconfig", required_argument,0, 'c'},
  {"factors", required_argument,0, 'f'},
  {"filter", required_argument,0, 'l'},
  {"reference", required_argument, 0, 'r'},
  {"binary", no_argument, 0, 'b'},
  {"nbest", required_argument, 0, 'n'},
  {"scfile", required_argument, 0, 'S'},
  {"ffile", required_argument, 0, 'F'},
  {"prev-scfile", required_argument, 0, 'R'},
  {"prev-ffile", required_argument, 0, 'E'},
  {"verbose", required_argument, 0, 'v'},
  {"help", no_argument, 0, 'h'},
  {"allow-duplicates", no_argument, 0, 'd'},
  {0, 0, 0, 0}
};

// Command line options used in extractor.
struct ProgramOption {
  string scorerType;
  string scorerConfig;
  string scorerFactors;
  string scorerFilter;
  string referenceFile;
  string nbestFile;
  string scoreDataFile;
  string featureDataFile;
  string prevScoreDataFile;
  string prevFeatureDataFile;
  bool binmode;
  bool allowDuplicates;
  int verbosity;

  ProgramOption()
      : scorerType("BLEU"),
        scorerConfig(""),
        scorerFactors(""),
        scorerFilter(""),
        referenceFile(""),
        nbestFile(""),
        scoreDataFile("statscore.data"),
        featureDataFile("features.data"),
        prevScoreDataFile(""),
        prevFeatureDataFile(""),
        binmode(false),
        allowDuplicates(false),
        verbosity(0) { }
};

void ParseCommandOptions(int argc, char** argv, ProgramOption* opt) {
  int c;
  int option_index;

  while ((c = getopt_long(argc, argv, "s:r:f:l:n:S:F:R:E:v:hbd", long_options, &option_index)) != -1) {
    switch (c) {
      case 's':
        opt->scorerType = string(optarg);
        break;
      case 'c':
        opt->scorerConfig = string(optarg);
        break;
      case 'f':
        opt->scorerFactors = string(optarg);
        break;
      case 'l':
        opt->scorerFilter = string(optarg);
        break;
      case 'r':
        opt->referenceFile = string(optarg);
        break;
      case 'b':
        opt->binmode = true;
        break;
      case 'n':
        opt->nbestFile = string(optarg);
        break;
      case 'S':
        opt->scoreDataFile = string(optarg);
        break;
      case 'F':
        opt->featureDataFile = string(optarg);
        break;
      case 'E':
        opt->prevFeatureDataFile = string(optarg);
        break;
      case 'R':
        opt->prevScoreDataFile = string(optarg);
        break;
      case 'v':
        opt->verbosity = atoi(optarg);
        break;
      case 'd':
        opt->allowDuplicates = true;
        break;
      default:
        usage();
    }
  }
}

} // anonymous namespace

int main(int argc, char** argv)
{
  ResetUserTime();

  ProgramOption option;
  ParseCommandOptions(argc, argv, &option);

  try {
    // check whether score statistics file is specified
    if (option.scoreDataFile.length() == 0) {
      throw runtime_error("Error: output score statistics file is not specified");
    }

    // check wheter feature file is specified
    if (option.featureDataFile.length() == 0) {
      throw runtime_error("Error: output feature file is not specified");
    }

    // check whether reference file is specified when nbest is specified
    if ((option.nbestFile.length() > 0 && option.referenceFile.length() == 0)) {
      throw runtime_error("Error: reference file is not specified; you can not score the nbest");
    }

    vector<string> nbestFiles;
    if (option.nbestFile.length() > 0) {
      Tokenize(option.nbestFile.c_str(), ',', &nbestFiles);
    }

    vector<string> referenceFiles;
    if (option.referenceFile.length() > 0) {
      Tokenize(option.referenceFile.c_str(), ',', &referenceFiles);
    }

    vector<string> prevScoreDataFiles;
    if (option.prevScoreDataFile.length() > 0) {
      Tokenize(option.prevScoreDataFile.c_str(), ',', &prevScoreDataFiles);
    }

    vector<string> prevFeatureDataFiles;
    if (option.prevFeatureDataFile.length() > 0) {
      Tokenize(option.prevFeatureDataFile.c_str(), ',', &prevFeatureDataFiles);
    }

    if (prevScoreDataFiles.size() != prevFeatureDataFiles.size()) {
      throw runtime_error("Error: there is a different number of previous score and feature files");
    }

    if (option.binmode) {
      cerr << "Binary write mode is selected" << endl;
    } else {
      cerr << "Binary write mode is NOT selected" << endl;
    }

    TRACE_ERR("Scorer type: " << option.scorerType << endl);

    boost::scoped_ptr<Scorer> scorer(
        ScorerFactory::getScorer(option.scorerType, option.scorerConfig));

    // set Factors and Filter used to preprocess the sentences
    scorer->setFactors(option.scorerFactors);
    scorer->setFilter(option.scorerFilter);

    // load references
    if (referenceFiles.size() > 0)
      scorer->setReferenceFiles(referenceFiles);

    PrintUserTime("References loaded");

    Data data(scorer.get());

    // load old data
    for (size_t i = 0; i < prevScoreDataFiles.size(); i++) {
      data.load(prevFeatureDataFiles.at(i), prevScoreDataFiles.at(i));
    }

    PrintUserTime("Previous data loaded");

    // computing score statistics of each nbest file
    for (size_t i = 0; i < nbestFiles.size(); i++) {
      data.loadNBest(nbestFiles.at(i));
    }

    PrintUserTime("Nbest entries loaded and scored");

    //ADDED_BY_TS
    if (!option.allowDuplicates) {
      data.removeDuplicates();
    }
    //END_ADDED

    data.save(option.featureDataFile, option.scoreDataFile, option.binmode);
    PrintUserTime("Stopping...");

    return EXIT_SUCCESS;
  } catch (const exception& e) {
    cerr << "Exception: " << e.what() << endl;
    return EXIT_FAILURE;
  }
}
<|endoftext|>


<commit_before>// Time:  O(min(m, n)^2 * max(m, n) * log(max(m, n)))
// Space: O(max(m, n))

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        if (matrix.empty()) {
            return 0;
        }

        const int m = min(matrix.size(), matrix[0].size());
        const int n = max(matrix.size(), matrix[0].size());
        int result = numeric_limits<int>::min();

        for (int i = 0; i < m; ++i) {
            vector<int> sums(n, 0);
            for (int j = i; j < m; ++j) {
                for (int k = 0; k < n; ++k) {
                    sums[k] += (n == matrix.size()) ? matrix[k][j] : matrix[j][k];
                }

                // Find the max subarray no more than K.
                set<int> accu_sum_set;
                accu_sum_set.emplace(0);
                int accu_sum = 0;
                for (int sum : sums) {
                    accu_sum += sum;
                    auto it = accu_sum_set.lower_bound(accu_sum - k);
                    if (it != accu_sum_set.end()) {
                        result = max(result, accu_sum - *it);
                    }
                    accu_sum_set.emplace(accu_sum);
                }
            }
        }

        return result;
    }
};
<commit_msg>Update max-sum-of-sub-matrix-no-larger-than-k.cpp<commit_after>// Time:  O(min(m, n)^2 * max(m, n) * log(max(m, n)))
// Space: O(max(m, n))

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int k) {
        if (matrix.empty()) {
            return 0;
        }

        const int m = min(matrix.size(), matrix[0].size());
        const int n = max(matrix.size(), matrix[0].size());
        int result = numeric_limits<int>::min();

        for (int i = 0; i < m; ++i) {
            vector<int> sums(n, 0);
            for (int j = i; j < m; ++j) {
                for (int l = 0; l < n; ++l) {
                    sums[l] += (n == matrix.size()) ? matrix[l][j] : matrix[j][l];
                }

                // Find the max subarray no more than K.
                set<int> accu_sum_set;
                accu_sum_set.emplace(0);
                int accu_sum = 0;
                for (int sum : sums) {
                    accu_sum += sum;
                    auto it = accu_sum_set.lower_bound(accu_sum - k);
                    if (it != accu_sum_set.end()) {
                        result = max(result, accu_sum - *it);
                    }
                    accu_sum_set.emplace(accu_sum);
                }
            }
        }

        return result;
    }
};
<|endoftext|>


<commit_before>#include "blockstore.h"

#include <stdexcept>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <thread>

namespace util {

IBlockStore& BlockStoreManager::instance(size_t blockSize) noexcept {
	assert(blockSize > sizeof(void*) && blockSize % 4 == 0);
	auto& p = stores[blockSize];
	if (p.get() == nullptr)
		p = createInstance(blockSize);
	return *p;
}

void BlockStoreManager::deleteAllInstances() noexcept {
	stores.clear();
}

std::unique_ptr<IBlockStore> BlockStoreManager::createInstance(size_t blockSize) noexcept {
	if (blockSize == sizeof(MaxAtomic))
		return std::make_unique<AtomicBlockStore>();
	else
		return std::make_unique<BlockStore>(blockSize);
}

std::unordered_map<size_t, std::unique_ptr<IBlockStore>> BlockStoreManager::stores;

BlockStoreManager::iterator::iterator(const decltype(it)& it) noexcept : it(it) { }

bool BlockStoreManager::iterator::operator!=(const iterator& other) const noexcept {
	return it != other.it;
}

BlockStoreManager::iterator& BlockStoreManager::iterator::operator++() noexcept {
	++it; return *this;
}

BlockStoreManager::iterator::reference BlockStoreManager::iterator::operator*() const noexcept {
	return *it->second;
}

BlockStoreManager::iterator BlockStoreManager::begin() noexcept {
	return iterator(stores.begin());
}

BlockStoreManager::iterator BlockStoreManager::end() noexcept {
	return iterator(stores.end());
}

size_t FakeBlockGuard<0>::blockSize() noexcept {
	return 0;
}

void FakeBlockGuard<0>::load(void*) noexcept {
}

void FakeBlockGuard<0>::store(const void*) noexcept {
}

size_t FakeBlockGuard<1>::blockSize() noexcept {
	return 1;
}

void FakeBlockGuard<1>::load(void* v) noexcept {
	*static_cast<uint8_t*>(v) = static_cast<uint8_t>(key);
}

void FakeBlockGuard<1>::store(const void* v) noexcept {
	key = *static_cast<const uint8_t*>(v);
}

size_t FakeBlockGuard<2>::blockSize() noexcept {
	return 2;
}

void FakeBlockGuard<2>::load(void* v) noexcept {
	*static_cast<uint16_t*>(v) = static_cast<uint16_t>(key);
}

void FakeBlockGuard<2>::store(const void* v) noexcept {
	key = *static_cast<const uint16_t*>(v);
}

size_t FakeBlockGuard<4>::blockSize() noexcept {
	return 4;
}

void FakeBlockGuard<4>::load(void* v) noexcept {
	*static_cast<uint32_t*>(v) = static_cast<uint32_t>(key);
}

void FakeBlockGuard<4>::store(const void* v) noexcept {
	key = *static_cast<const uint32_t*>(v);
}

#ifdef _LP64
size_t FakeBlockGuard<8>::blockSize() noexcept {
	return 8;
}

void FakeBlockGuard<8>::load(void* v) noexcept {
	*static_cast<uint64_t*>(v) = key;
}

void FakeBlockGuard<8>::store(const void* v) noexcept {
	key = *static_cast<const uint64_t*>(v);
}
#endif

AtomicBlockGuard::AtomicBlockGuard(AtomicBlockStore& store) : _store(store) {
	assert(store.blockSize() == sizeof(MaxAtomic));
	key = _store.allocBlock();
}

AtomicBlockGuard::~AtomicBlockGuard() {
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void AtomicBlockGuard::load(void* v) noexcept {
	*static_cast<MaxAtomic*>(v) = static_cast<MaxAtomic*>(_store.mem)[key];
}

void AtomicBlockGuard::store(const void* v) noexcept {
	static_cast<MaxAtomic*>(_store.mem)[key] = *static_cast<const MaxAtomic*>(v);
}

size_t AtomicBlockGuard::blockSize() noexcept {
	return sizeof(MaxAtomic);
}

LockingBlockGuard::LockingBlockGuard(IBlockStore& store) : _store(store) {
	key = _store.allocBlock();
}

LockingBlockGuard::~LockingBlockGuard() {
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void LockingBlockGuard::load(void* v) noexcept {
	LockGuardLoad lock(_lock);
	_store.load(key, v);
}

void LockingBlockGuard::store(const void* v) noexcept {
	LockGuardStore lock(_lock);
	_store.store(key, v);
}

size_t LockingBlockGuard::blockSize() noexcept {
	return _store.blockSize();
}

LockingBlockGuard::LockGuardLoad::LockGuardLoad(std::atomic<uint8_t>& lock) noexcept : lock(lock) {
	uint8_t expected;
	while (expected = lock.load(std::memory_order_acquire) & 7, !std::atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(expected + 1), std::memory_order_release, std::memory_order_relaxed)) {
		std::this_thread::yield();
	}
}

LockingBlockGuard::LockGuardLoad::~LockGuardLoad() {
	uint8_t expected;
	while (expected = lock.load(std::memory_order_acquire), !std::atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(expected - 1), std::memory_order_release, std::memory_order_relaxed)) { }
}

LockingBlockGuard::LockGuardStore::LockGuardStore(std::atomic<uint8_t>& lock) noexcept : lock(lock) {
	uint8_t expected;
	while (expected = 0, !std::atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(0x80), std::memory_order_release, std::memory_order_relaxed)) {
		std::this_thread::yield();
	}
}

LockingBlockGuard::LockGuardStore::~LockGuardStore() {
	lock.store(0, std::memory_order_release);
}

SharedPtrBlockGuard::SharedPtrBlockGuard(AtomicBlockStore& store) : _store(store) {
	assert(store.blockSize() == sizeof(MaxAtomic));
	key = _store.allocBlock();
}

SharedPtrBlockGuard::~SharedPtrBlockGuard() {
	std::shared_ptr<size_t> init;
	static_cast<std::shared_ptr<size_t>*>(_store.mem)[key] = init;
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void SharedPtrBlockGuard::load(void* v) noexcept {
	*static_cast<std::shared_ptr<size_t>*>(v) = static_cast<std::shared_ptr<size_t>*>(_store.mem)[key];
}

void SharedPtrBlockGuard::store(const void* v) noexcept {
	static_cast<std::shared_ptr<size_t>*>(_store.mem)[key] = *static_cast<const std::shared_ptr<size_t>*>(v);
}

size_t SharedPtrBlockGuard::blockSize() noexcept {
	return sizeof(MaxAtomic);
}

AtomicBlockStore::~AtomicBlockStore() {
	freeMemory();
}

size_t AtomicBlockStore::blockSize() noexcept {
	return _blockSize;
}

size_t AtomicBlockStore::allocBlock() {
	if (_length == _capacity)
		setCapacity(_capacity ? _capacity * 2 : 1);

	return _length++;
}

void AtomicBlockStore::freeBlock(size_t) {
	throw std::logic_error("not implemented");
}

void AtomicBlockStore::load(size_t key, void* v) noexcept {
	assert(key < _length);
	*static_cast<MaxAtomic*>(v) = static_cast<MaxAtomic*>(mem)[key];
}

void AtomicBlockStore::store(size_t key, const void* v) noexcept {
	assert(key < _length);
	static_cast<MaxAtomic*>(mem)[key] = *static_cast<const MaxAtomic*>(v);
}

size_t AtomicBlockStore::length() noexcept {
	return _length;
}

size_t AtomicBlockStore::capacity() noexcept {
	return _capacity;
}

void AtomicBlockStore::setCapacity(size_t n) {
	if (n < _length)
		throw std::length_error("Capacity must be greater than or equal to length");

	if (n == _capacity)
		return;

	if (n == 0) {
		freeMemory();
		return;
	}

	auto newMem = realloc(mem, _blockSize * n);
	if (!newMem)
		throw new std::runtime_error("realloc() failed");

	mem = newMem;
	_capacity = n;

	zeroOutFreeTailMemory();
}

void AtomicBlockStore::freeMemory() noexcept {
	free(mem);
	mem = nullptr;
}

void AtomicBlockStore::zeroOutFreeTailMemory() noexcept {
	assert(_length <= _capacity);
	size_t freeTailBlockCount = _capacity - _length;
	memset(static_cast<uint8_t*>(mem) + _length * _blockSize, 0, freeTailBlockCount * _blockSize);
}

BlockStore::BlockStore(size_t blockSize) noexcept : _blockSize(blockSize) { }

BlockStore::~BlockStore() {
	freeMemory();
}

size_t BlockStore::blockSize() noexcept {
	return _blockSize;
}

size_t BlockStore::allocBlock() {
	if (_length == _capacity)
		setCapacity(_capacity ? _capacity * 2 : 1);

	return _length++;
}

void BlockStore::freeBlock(size_t) {
	throw std::logic_error("not implemented");
}

void BlockStore::load(size_t key, void* v) noexcept {
	assert(key < _length);
	memcpy(v, static_cast<uint8_t*>(mem) + _blockSize * key, _blockSize);
}

void BlockStore::store(size_t key, const void* v) noexcept {
	assert(key < _length);
	memcpy(static_cast<uint8_t*>(mem) + _blockSize * key, v, _blockSize);
}

size_t BlockStore::length() noexcept {
	return _length;
}

size_t BlockStore::capacity() noexcept {
	return _capacity;
}

void BlockStore::setCapacity(size_t n) {
	if (n < _length)
		throw std::length_error("Capacity must be greater than or equal to length");

	if (n == _capacity)
		return;

	if (n == 0) {
		freeMemory();
		return;
	}

	auto newMem = realloc(mem, _blockSize * n);
	if (!newMem)
		throw new std::runtime_error("realloc() failed");

	mem = newMem;
	_capacity = n;

	zeroOutFreeTailMemory();
}

void BlockStore::freeMemory() noexcept {
	free(mem);
	mem = nullptr;
}

void BlockStore::zeroOutFreeTailMemory() noexcept {
	assert(_length <= _capacity);
	size_t freeTailBlockCount = _capacity - _length;
	memset(static_cast<uint8_t*>(mem) + _length * _blockSize, 0, freeTailBlockCount * _blockSize);
}

} // namespace util
<commit_msg>Remove std:: from blockstore.cpp<commit_after>#include "blockstore.h"

#include <stdexcept>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <thread>

using namespace std;

namespace util {

IBlockStore& BlockStoreManager::instance(size_t blockSize) noexcept {
	assert(blockSize > sizeof(void*) && blockSize % 4 == 0);
	auto& p = stores[blockSize];
	if (p.get() == nullptr)
		p = createInstance(blockSize);
	return *p;
}

void BlockStoreManager::deleteAllInstances() noexcept {
	stores.clear();
}

unique_ptr<IBlockStore> BlockStoreManager::createInstance(size_t blockSize) noexcept {
	if (blockSize == sizeof(MaxAtomic))
		return make_unique<AtomicBlockStore>();
	else
		return make_unique<BlockStore>(blockSize);
}

unordered_map<size_t, unique_ptr<IBlockStore>> BlockStoreManager::stores;

BlockStoreManager::iterator::iterator(const decltype(it)& it) noexcept : it(it) { }

bool BlockStoreManager::iterator::operator!=(const iterator& other) const noexcept {
	return it != other.it;
}

BlockStoreManager::iterator& BlockStoreManager::iterator::operator++() noexcept {
	++it; return *this;
}

BlockStoreManager::iterator::reference BlockStoreManager::iterator::operator*() const noexcept {
	return *it->second;
}

BlockStoreManager::iterator BlockStoreManager::begin() noexcept {
	return iterator(stores.begin());
}

BlockStoreManager::iterator BlockStoreManager::end() noexcept {
	return iterator(stores.end());
}

size_t FakeBlockGuard<0>::blockSize() noexcept {
	return 0;
}

void FakeBlockGuard<0>::load(void*) noexcept {
}

void FakeBlockGuard<0>::store(const void*) noexcept {
}

size_t FakeBlockGuard<1>::blockSize() noexcept {
	return 1;
}

void FakeBlockGuard<1>::load(void* v) noexcept {
	*static_cast<uint8_t*>(v) = static_cast<uint8_t>(key);
}

void FakeBlockGuard<1>::store(const void* v) noexcept {
	key = *static_cast<const uint8_t*>(v);
}

size_t FakeBlockGuard<2>::blockSize() noexcept {
	return 2;
}

void FakeBlockGuard<2>::load(void* v) noexcept {
	*static_cast<uint16_t*>(v) = static_cast<uint16_t>(key);
}

void FakeBlockGuard<2>::store(const void* v) noexcept {
	key = *static_cast<const uint16_t*>(v);
}

size_t FakeBlockGuard<4>::blockSize() noexcept {
	return 4;
}

void FakeBlockGuard<4>::load(void* v) noexcept {
	*static_cast<uint32_t*>(v) = static_cast<uint32_t>(key);
}

void FakeBlockGuard<4>::store(const void* v) noexcept {
	key = *static_cast<const uint32_t*>(v);
}

#ifdef _LP64
size_t FakeBlockGuard<8>::blockSize() noexcept {
	return 8;
}

void FakeBlockGuard<8>::load(void* v) noexcept {
	*static_cast<uint64_t*>(v) = key;
}

void FakeBlockGuard<8>::store(const void* v) noexcept {
	key = *static_cast<const uint64_t*>(v);
}
#endif

AtomicBlockGuard::AtomicBlockGuard(AtomicBlockStore& store) : _store(store) {
	assert(store.blockSize() == sizeof(MaxAtomic));
	key = _store.allocBlock();
}

AtomicBlockGuard::~AtomicBlockGuard() {
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void AtomicBlockGuard::load(void* v) noexcept {
	*static_cast<MaxAtomic*>(v) = static_cast<MaxAtomic*>(_store.mem)[key];
}

void AtomicBlockGuard::store(const void* v) noexcept {
	static_cast<MaxAtomic*>(_store.mem)[key] = *static_cast<const MaxAtomic*>(v);
}

size_t AtomicBlockGuard::blockSize() noexcept {
	return sizeof(MaxAtomic);
}

LockingBlockGuard::LockingBlockGuard(IBlockStore& store) : _store(store) {
	key = _store.allocBlock();
}

LockingBlockGuard::~LockingBlockGuard() {
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void LockingBlockGuard::load(void* v) noexcept {
	LockGuardLoad lock(_lock);
	_store.load(key, v);
}

void LockingBlockGuard::store(const void* v) noexcept {
	LockGuardStore lock(_lock);
	_store.store(key, v);
}

size_t LockingBlockGuard::blockSize() noexcept {
	return _store.blockSize();
}

LockingBlockGuard::LockGuardLoad::LockGuardLoad(atomic<uint8_t>& lock) noexcept : lock(lock) {
	uint8_t expected;
	while (expected = lock.load(memory_order_acquire) & 7,
			!atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(expected + 1),
				memory_order_release, memory_order_relaxed)) {
		this_thread::yield();
	}
}

LockingBlockGuard::LockGuardLoad::~LockGuardLoad() {
	uint8_t expected;
	while (expected = lock.load(memory_order_acquire),
			!atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(expected - 1),
				memory_order_release, memory_order_relaxed)) { }
}

LockingBlockGuard::LockGuardStore::LockGuardStore(atomic<uint8_t>& lock) noexcept : lock(lock) {
	uint8_t expected;
	while (expected = 0, !atomic_compare_exchange_weak_explicit(&lock, &expected, static_cast<uint8_t>(0x80),
				memory_order_release, memory_order_relaxed)) {
		this_thread::yield();
	}
}

LockingBlockGuard::LockGuardStore::~LockGuardStore() {
	lock.store(0, memory_order_release);
}

SharedPtrBlockGuard::SharedPtrBlockGuard(AtomicBlockStore& store) : _store(store) {
	assert(store.blockSize() == sizeof(MaxAtomic));
	key = _store.allocBlock();
}

SharedPtrBlockGuard::~SharedPtrBlockGuard() {
	shared_ptr<size_t> init;
	static_cast<shared_ptr<size_t>*>(_store.mem)[key] = init;
	// _store.freeBlock(key); // TODO uncomment after it's implemented
}

void SharedPtrBlockGuard::load(void* v) noexcept {
	*static_cast<shared_ptr<size_t>*>(v) = static_cast<shared_ptr<size_t>*>(_store.mem)[key];
}

void SharedPtrBlockGuard::store(const void* v) noexcept {
	static_cast<shared_ptr<size_t>*>(_store.mem)[key] = *static_cast<const shared_ptr<size_t>*>(v);
}

size_t SharedPtrBlockGuard::blockSize() noexcept {
	return sizeof(MaxAtomic);
}

AtomicBlockStore::~AtomicBlockStore() {
	freeMemory();
}

size_t AtomicBlockStore::blockSize() noexcept {
	return _blockSize;
}

size_t AtomicBlockStore::allocBlock() {
	if (_length == _capacity)
		setCapacity(_capacity ? _capacity * 2 : 1);

	return _length++;
}

void AtomicBlockStore::freeBlock(size_t) {
	throw logic_error("not implemented");
}

void AtomicBlockStore::load(size_t key, void* v) noexcept {
	assert(key < _length);
	*static_cast<MaxAtomic*>(v) = static_cast<MaxAtomic*>(mem)[key];
}

void AtomicBlockStore::store(size_t key, const void* v) noexcept {
	assert(key < _length);
	static_cast<MaxAtomic*>(mem)[key] = *static_cast<const MaxAtomic*>(v);
}

size_t AtomicBlockStore::length() noexcept {
	return _length;
}

size_t AtomicBlockStore::capacity() noexcept {
	return _capacity;
}

void AtomicBlockStore::setCapacity(size_t n) {
	if (n < _length)
		throw length_error("Capacity must be greater than or equal to length");

	if (n == _capacity)
		return;

	if (n == 0) {
		freeMemory();
		return;
	}

	auto newMem = realloc(mem, _blockSize * n);
	if (!newMem)
		throw new runtime_error("realloc() failed");

	mem = newMem;
	_capacity = n;

	zeroOutFreeTailMemory();
}

void AtomicBlockStore::freeMemory() noexcept {
	free(mem);
	mem = nullptr;
}

void AtomicBlockStore::zeroOutFreeTailMemory() noexcept {
	assert(_length <= _capacity);
	size_t freeTailBlockCount = _capacity - _length;
	memset(static_cast<uint8_t*>(mem) + _length * _blockSize, 0, freeTailBlockCount * _blockSize);
}

BlockStore::BlockStore(size_t blockSize) noexcept : _blockSize(blockSize) { }

BlockStore::~BlockStore() {
	freeMemory();
}

size_t BlockStore::blockSize() noexcept {
	return _blockSize;
}

size_t BlockStore::allocBlock() {
	if (_length == _capacity)
		setCapacity(_capacity ? _capacity * 2 : 1);

	return _length++;
}

void BlockStore::freeBlock(size_t) {
	throw logic_error("not implemented");
}

void BlockStore::load(size_t key, void* v) noexcept {
	assert(key < _length);
	memcpy(v, static_cast<uint8_t*>(mem) + _blockSize * key, _blockSize);
}

void BlockStore::store(size_t key, const void* v) noexcept {
	assert(key < _length);
	memcpy(static_cast<uint8_t*>(mem) + _blockSize * key, v, _blockSize);
}

size_t BlockStore::length() noexcept {
	return _length;
}

size_t BlockStore::capacity() noexcept {
	return _capacity;
}

void BlockStore::setCapacity(size_t n) {
	if (n < _length)
		throw length_error("Capacity must be greater than or equal to length");

	if (n == _capacity)
		return;

	if (n == 0) {
		freeMemory();
		return;
	}

	auto newMem = realloc(mem, _blockSize * n);
	if (!newMem)
		throw new runtime_error("realloc() failed");

	mem = newMem;
	_capacity = n;

	zeroOutFreeTailMemory();
}

void BlockStore::freeMemory() noexcept {
	free(mem);
	mem = nullptr;
}

void BlockStore::zeroOutFreeTailMemory() noexcept {
	assert(_length <= _capacity);
	size_t freeTailBlockCount = _capacity - _length;
	memset(static_cast<uint8_t*>(mem) + _length * _blockSize, 0, freeTailBlockCount * _blockSize);
}

} // namespace util
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <string>
#include <cstdlib>
#include <cmath>
#include <boost/optional.hpp>
#include <nix/util/dataAccess.hpp>
#include <algorithm>

using namespace std;

namespace nix {
namespace util {

//TODO maybe a relaxed handling of units would be better, e.g. if none given, take the one from the dimension...
int positionToIndex(double position, const string &unit, const Dimension &dimension) {
    if (dimension.dimensionType() == nix::DimensionType::Sample) {
        SampledDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else if (dimension.dimensionType() == nix::DimensionType::Set) {
        SetDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else {
        RangeDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    }
}

size_t positionToIndex(double position, const string &unit, const SampledDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;
    if ((!dim_unit && unit.length() > 0) || (dim_unit && unit.length() == 0)) {
        throw nix::IncompatibleDimensions("Units of position and SampledDimension must both be given!", "nix::util::positionToIndex");
    }
    if ((dimension.offset() && position < *dimension.offset()) || (!dimension.offset() && position < 0.0)) {
        throw nix::OutOfBounds("Position is out of bounds in SampledDimension.", static_cast<int>(position));
    }
    if (dim_unit) {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    index = static_cast<size_t>(round(position * scaling / dimension.samplingInterval()));
    return index;
}

size_t positionToIndex(double position, const string &unit, const SetDimension &dimension) {
    size_t index;
    index = static_cast<size_t>(round(position));
    if (unit.length() > 0) {
        throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
    }
    if (static_cast<size_t>(index) < dimension.labels().size()){
        return index;
    } else {
        throw nix::OutOfBounds("Position is out of bounds in setDimension.", static_cast<int>(position));
    }
}

size_t positionToIndex(double position, const string &unit, const RangeDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;

    if ((!dim_unit && unit.length() > 0) || (dim_unit && unit.length() == 0)) {
        throw nix::IncompatibleDimensions("Units of position and RangeDimension must both be given!", "nix::util::positionToIndex");
    }
    if (dim_unit) {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    vector<double> ticks = dimension.ticks();
    if (position*scaling < *ticks.begin()) {
        return 0;
    } else if (position*scaling > *prev(ticks.end())) {
        return prev(ticks.end()) - ticks.begin();
    }
    vector<double>::iterator low = std::lower_bound (ticks.begin(), ticks.end(), position * scaling);
    if (*low == position) {
        return low - ticks.begin();
    }
    if (low != ticks.begin() && *low != position * scaling) {
        double diff_low, diff_before;
        diff_low = fabs(*low - position);
        diff_before = fabs(*(std::prev(low)) - position * scaling);
        if (diff_low < diff_before) {
            index = low - ticks.begin();
        } else {
            index = low - ticks.begin() - 1;
        }
        return index;
    } else {
        return low - ticks.begin();
    }
}

void getOffsetAndCount(const SimpleTag &tag, const DataArray &array, NDSize &offset, NDSize &count) {
    vector<double> position = tag.position();
    vector<double> extent = tag.extent();
    vector<string> units = tag.units();
    NDSize temp_offset(position.size());
    NDSize temp_count(position.size(), 1);

    if (array.dimensionCount() != position.size() || (extent.size() > 0 && extent.size() != array.dimensionCount())) {
        throw std::runtime_error("Dimensionality of position or extent vector does not match dimensionality of data!");
    }
    for (size_t i = 0; i < position.size(); ++i) {
        Dimension dim = array.getDimension(i+1);
        temp_offset[i] = positionToIndex(position[i], i > units.size() ? "" : units[i], dim);
        if (i < extent.size()) {
            temp_count[i] = 1 + positionToIndex(position[i] + extent[i], i > units.size() ? "" : units[i], dim) - temp_offset[i];
        }
    }
    offset = temp_offset;
    count = temp_count;
}

void getOffsetAndCount(const DataTag &tag, const DataArray &array, size_t index, NDSize &offsets, NDSize &counts) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    NDSize position_extent = positions.getDataExtent();
    NDSize extent_extent = extents.getDataExtent();
    size_t dimension_count = array.dimensionCount();

    if (index >= position_extent[0] || index >= extent_extent[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (position_extent[1] > dimension_count || extent_extent[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::getOffsetAndCount");
    }
    NDSize temp_offset = NDSize{static_cast<NDSize::value_type>(index), static_cast<NDSize::value_type>(0)};
    NDSize temp_count{static_cast<NDSize::value_type>(1), static_cast<NDSize::value_type>(dimension_count)};
    NDArray offset(positions.getDataType(), temp_count);
    NDArray extent(extents.getDataType(), temp_count);
    positions.getData(offset, temp_count, temp_offset);
    extents.getData(extent, temp_count, temp_offset);

    NDSize data_offset(dimension_count, static_cast<size_t>(0));
    NDSize data_count(dimension_count, static_cast<size_t>(0));

    for (size_t i = 0; i < offset.num_elements(); ++i) {
        Dimension dimension = array.getDimension(i+1);
        string unit = "";
        if (dimension.dimensionType() == nix::DimensionType::Sample) {
            SampledDimension dim;
            dim = dimension;
            unit = dim.unit() ? *dim.unit() : "";
        } else if (dimension.dimensionType() == nix::DimensionType::Range) {
            RangeDimension dim;
            dim = dimension;
            unit = dim.unit() ? *dim.unit() : "";
        }
        data_offset[i] = positionToIndex(offset.get<double>(i), unit, dimension);

        if (i < extent.num_elements()) {
            data_count[i] = 1 + positionToIndex(offset.get<double>(i) + extent.get<double>(i), unit, dimension) - data_offset[i];
        }
    }
    offsets = data_offset;
    counts = data_count;
}

bool positionInData(const DataArray &data, const NDSize &position) {
    NDSize data_size = data.getDataExtent();
    bool valid = true;

    if (!(data_size.size() == position.size())) {
        return false;
    }
    for (size_t i = 0; i < data_size.size(); i++) {
        valid &= position[i] < data_size[i];
    }
    return valid;
}

bool positionAndExtentInData(const DataArray &data, const NDSize &position, const NDSize &count) {
    NDSize pos = position + count;
    pos -= 1;
    return positionInData(data, pos);
}

NDArray retrieveData(const DataTag &tag, size_t position_index, size_t reference_index) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (position_index < 0 || position_index >= positions.getDataExtent()[0] ||
        (extents && position_index >= extents.getDataExtent()[0])) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (reference_index < 0 || !(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.getDataExtent()[1] > dimension_count ||
        (extents &&extents.getDataExtent()[1] > dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], position_index, offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("References data slice out of the extent of the DataArray!", 0);

NDArray retrieveData(const SimpleTag &tag, size_t reference_index) {
    vector<double> positions = tag.position();
    vector<double> extents = tag.extent();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (reference_index < 0 || !(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.size() != dimension_count || (extents.size() > 0 && extents.size() != dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("Referenced data slice out of the extent of the DataArray!", 0);
    }
    NDArray data(refs[reference_index].getDataType(), count);
    refs[reference_index].getData(data, count, offset);
    return data;
}

} // namespace util
} // namespace nix
<commit_msg>removed tautological warning<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <string>
#include <cstdlib>
#include <cmath>
#include <boost/optional.hpp>
#include <nix/util/dataAccess.hpp>
#include <algorithm>

using namespace std;

namespace nix {
namespace util {

//TODO maybe a relaxed handling of units would be better, e.g. if none given, take the one from the dimension...
int positionToIndex(double position, const string &unit, const Dimension &dimension) {
    if (dimension.dimensionType() == nix::DimensionType::Sample) {
        SampledDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else if (dimension.dimensionType() == nix::DimensionType::Set) {
        SetDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    } else {
        RangeDimension dim;
        dim = dimension;
        return positionToIndex(position, unit, dim);
    }
}

size_t positionToIndex(double position, const string &unit, const SampledDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;
    if ((!dim_unit && unit.length() > 0) || (dim_unit && unit.length() == 0)) {
        throw nix::IncompatibleDimensions("Units of position and SampledDimension must both be given!", "nix::util::positionToIndex");
    }
    if ((dimension.offset() && position < *dimension.offset()) || (!dimension.offset() && position < 0.0)) {
        throw nix::OutOfBounds("Position is out of bounds in SampledDimension.", static_cast<int>(position));
    }
    if (dim_unit) {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    index = static_cast<size_t>(round(position * scaling / dimension.samplingInterval()));
    return index;
}

size_t positionToIndex(double position, const string &unit, const SetDimension &dimension) {
    size_t index;
    index = static_cast<size_t>(round(position));
    if (unit.length() > 0) {
        throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
    }
    if (static_cast<size_t>(index) < dimension.labels().size()){
        return index;
    } else {
        throw nix::OutOfBounds("Position is out of bounds in setDimension.", static_cast<int>(position));
    }
}

size_t positionToIndex(double position, const string &unit, const RangeDimension &dimension) {
    size_t index;
    boost::optional<string> dim_unit = dimension.unit();
    double scaling = 1.0;

    if ((!dim_unit && unit.length() > 0) || (dim_unit && unit.length() == 0)) {
        throw nix::IncompatibleDimensions("Units of position and RangeDimension must both be given!", "nix::util::positionToIndex");
    }
    if (dim_unit) {
        try {
            scaling = util::getSIScaling(unit, *dim_unit);
        } catch (...) {
            throw nix::IncompatibleDimensions("Cannot apply a position with unit to a SetDimension", "nix::util::positionToIndex");
        }
    }
    vector<double> ticks = dimension.ticks();
    if (position*scaling < *ticks.begin()) {
        return 0;
    } else if (position*scaling > *prev(ticks.end())) {
        return prev(ticks.end()) - ticks.begin();
    }
    vector<double>::iterator low = std::lower_bound (ticks.begin(), ticks.end(), position * scaling);
    if (*low == position) {
        return low - ticks.begin();
    }
    if (low != ticks.begin() && *low != position * scaling) {
        double diff_low, diff_before;
        diff_low = fabs(*low - position);
        diff_before = fabs(*(std::prev(low)) - position * scaling);
        if (diff_low < diff_before) {
            index = low - ticks.begin();
        } else {
            index = low - ticks.begin() - 1;
        }
        return index;
    } else {
        return low - ticks.begin();
    }
}

void getOffsetAndCount(const SimpleTag &tag, const DataArray &array, NDSize &offset, NDSize &count) {
    vector<double> position = tag.position();
    vector<double> extent = tag.extent();
    vector<string> units = tag.units();
    NDSize temp_offset(position.size());
    NDSize temp_count(position.size(), 1);

    if (array.dimensionCount() != position.size() || (extent.size() > 0 && extent.size() != array.dimensionCount())) {
        throw std::runtime_error("Dimensionality of position or extent vector does not match dimensionality of data!");
    }
    for (size_t i = 0; i < position.size(); ++i) {
        Dimension dim = array.getDimension(i+1);
        temp_offset[i] = positionToIndex(position[i], i > units.size() ? "" : units[i], dim);
        if (i < extent.size()) {
            temp_count[i] = 1 + positionToIndex(position[i] + extent[i], i > units.size() ? "" : units[i], dim) - temp_offset[i];
        }
    }
    offset = temp_offset;
    count = temp_count;
}

void getOffsetAndCount(const DataTag &tag, const DataArray &array, size_t index, NDSize &offsets, NDSize &counts) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    NDSize position_extent = positions.getDataExtent();
    NDSize extent_extent = extents.getDataExtent();
    size_t dimension_count = array.dimensionCount();

    if (index >= position_extent[0] || index >= extent_extent[0]) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (position_extent[1] > dimension_count || extent_extent[1] > dimension_count) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::getOffsetAndCount");
    }
    NDSize temp_offset = NDSize{static_cast<NDSize::value_type>(index), static_cast<NDSize::value_type>(0)};
    NDSize temp_count{static_cast<NDSize::value_type>(1), static_cast<NDSize::value_type>(dimension_count)};
    NDArray offset(positions.getDataType(), temp_count);
    NDArray extent(extents.getDataType(), temp_count);
    positions.getData(offset, temp_count, temp_offset);
    extents.getData(extent, temp_count, temp_offset);

    NDSize data_offset(dimension_count, static_cast<size_t>(0));
    NDSize data_count(dimension_count, static_cast<size_t>(0));

    for (size_t i = 0; i < offset.num_elements(); ++i) {
        Dimension dimension = array.getDimension(i+1);
        string unit = "";
        if (dimension.dimensionType() == nix::DimensionType::Sample) {
            SampledDimension dim;
            dim = dimension;
            unit = dim.unit() ? *dim.unit() : "";
        } else if (dimension.dimensionType() == nix::DimensionType::Range) {
            RangeDimension dim;
            dim = dimension;
            unit = dim.unit() ? *dim.unit() : "";
        }
        data_offset[i] = positionToIndex(offset.get<double>(i), unit, dimension);

        if (i < extent.num_elements()) {
            data_count[i] = 1 + positionToIndex(offset.get<double>(i) + extent.get<double>(i), unit, dimension) - data_offset[i];
        }
    }
    offsets = data_offset;
    counts = data_count;
}

bool positionInData(const DataArray &data, const NDSize &position) {
    NDSize data_size = data.getDataExtent();
    bool valid = true;

    if (!(data_size.size() == position.size())) {
        return false;
    }
    for (size_t i = 0; i < data_size.size(); i++) {
        valid &= position[i] < data_size[i];
    }
    return valid;
}

bool positionAndExtentInData(const DataArray &data, const NDSize &position, const NDSize &count) {
    NDSize pos = position + count;
    pos -= 1;
    return positionInData(data, pos);
}

NDArray retrieveData(const DataTag &tag, size_t position_index, size_t reference_index) {
    DataArray positions = tag.positions();
    DataArray extents = tag.extents();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (position_index >= positions.getDataExtent()[0] ||
        (extents && position_index >= extents.getDataExtent()[0])) {
        throw nix::OutOfBounds("Index out of bounds of positions or extents!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.getDataExtent()[1] > dimension_count ||
        (extents &&extents.getDataExtent()[1] > dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], position_index, offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("References data slice out of the extent of the DataArray!", 0);
    }
    NDArray data(refs[reference_index].getDataType(), count);
    refs[reference_index].getData(data, count, offset);
    return data;
}

NDArray retrieveData(const SimpleTag &tag, size_t reference_index) {
    vector<double> positions = tag.position();
    vector<double> extents = tag.extent();
    vector<DataArray> refs = tag.references();
    if (refs.size() == 0) {
        throw nix::OutOfBounds("There are no references in this tag!", 0);
    }
    if (!(reference_index < tag.referenceCount())) {
        throw nix::OutOfBounds("Reference index out of bounds.", 0);
    }
    size_t dimension_count = refs[reference_index].dimensionCount();
    if (positions.size() != dimension_count || (extents.size() > 0 && extents.size() != dimension_count)) {
        throw nix::IncompatibleDimensions("Number of dimensions in position or extent do not match dimensionality of data","util::retrieveData");
    }

    NDSize offset, count;
    getOffsetAndCount(tag, refs[reference_index], offset, count);
    if (!positionAndExtentInData(refs[reference_index], offset, count)) {
        throw nix::OutOfBounds("Referenced data slice out of the extent of the DataArray!", 0);
    }
    NDArray data(refs[reference_index].getDataType(), count);
    refs[reference_index].getData(data, count, offset);
    return data;
}

} // namespace util
} // namespace nix
<|endoftext|>