<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// expression_test.cpp
//
// Identification: tests/expression/expression_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <iostream>
#include <sstream>
#include <queue>

#include "gtest/gtest.h"
#include "harness.h"

#include "backend/expression/abstract_expression.h"
#include "backend/common/types.h"
#include "backend/common/value_peeker.h"
#include "backend/storage/tuple.h"

#include "backend/expression/tuple_value_expression.h"
#include "backend/expression/comparison_expression.h"
#include "backend/expression/conjunction_expression.h"

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Expression Tests
//===--------------------------------------------------------------------===//

/*
   Description of test:

   1. This test defines a data structure for each expression type with
   unique fields.

   2. The test includes a helper to convert a std::queue of these structures
   into a tree of AbstractExpressions, using the expression factory via a
   json serialization.

   3. Using this utilities, the test defines several expressions (in
   std::queue) formats and asserts on the expected result.

   TODO: Unfortunately, the json_spirit serialization asserts when trying
   to read an int field from a value serialized as a string; need to figure
   out what's going on here .. and what the proper serialization method is.
 */

/*
 *  Abstract expression mock object
 */
class AE {
 public:
  AE(ExpressionType et, ValueType vt, int vs)
      : m_type(et),
        m_valueType(vt),
        m_valueSize(vs),
        left(nullptr),
        right(nullptr) {}

  virtual ~AE() {
    delete left;
    delete right;
  }

  virtual json_spirit::Object SerializeValue() {
    json_spirit::Object json;
    Serialize(json);
    return json;
  }

  // this is how java serializes..
  // note derived class data follows the serialization of children
  virtual void Serialize(json_spirit::Object &json) {
    json.push_back(json_spirit::Pair(
        "TYPE", json_spirit::Value(ExpressionTypeToString(m_type))));
    json.push_back(json_spirit::Pair(
        "VALUE_TYPE", json_spirit::Value(ValueTypeToString(m_valueType))));
    json.push_back(
        json_spirit::Pair("VALUE_SIZE", json_spirit::Value(m_valueSize)));

    if (left) json.push_back(json_spirit::Pair("LEFT", left->SerializeValue()));
    if (right)
      json.push_back(json_spirit::Pair("RIGHT", right->SerializeValue()));
  }

  ExpressionType m_type;  // TYPE
  ValueType m_valueType;  // VALUE_TYPE
  int m_valueSize;        // VALUE_SIZE

  // to build a tree
  AE *left;
  AE *right;
};

/*
 * constant value expression mock object
 */
class CV : public AE {
 public:
  CV(ExpressionType et, ValueType vt, int vs, int64_t v)
      : AE(et, vt, vs), m_jsontype(1), m_intValue(v) {
    m_stringValue = nullptr;
    m_doubleValue = 0.0;
  }

  CV(ExpressionType et, ValueType vt, int vs, char *v)
      : AE(et, vt, vs), m_jsontype(1), m_stringValue(strdup(v)) {
    m_intValue = 0;
    m_doubleValue = 0.0;
  }

  CV(ExpressionType et, ValueType vt, int vs, double v)
      : AE(et, vt, vs), m_jsontype(1), m_doubleValue(v) {
    m_stringValue = nullptr;
    m_intValue = 0;
  }

  ~CV() {}

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    if (m_jsontype == 0)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_stringValue)));
    else if (m_jsontype == 1)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_intValue)));
    else if (m_jsontype == 2)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_doubleValue)));
  }

  int m_jsontype;  // 0 = string, 1 = int64_t, 2 = double

  int64_t m_intValue;    // VALUE
  char *m_stringValue;   // VALUE
  double m_doubleValue;  // VALUE
};

/*
 * parameter value expression mock object
 */
class PV : public AE {
 public:
  PV(ExpressionType et, ValueType vt, int vs, int pi)
      : AE(et, vt, vs), m_paramIdx(pi) {}

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    json.push_back(
        json_spirit::Pair("PARAM_IDX", json_spirit::Value(m_paramIdx)));
  }

  int m_paramIdx;  // PARAM_IDX
};

/*
 * tuple value expression mock object
 */
class TV : public AE {
 public:
  TV(ExpressionType et, ValueType vt, int vs, int ci, const char *tn,
     const char *cn, const char *ca)
      : AE(et, vt, vs),
        m_columnIdx(ci),
        m_tableName(strdup(tn)),
        m_colName(strdup(cn)),
        m_colAlias(strdup(ca)) {}

  ~TV() {
    delete m_tableName;
    delete m_colName;
    delete m_colAlias;
  }

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    json.push_back(
        json_spirit::Pair("COLUMN_IDX", json_spirit::Value(m_columnIdx)));
    json.push_back(
        json_spirit::Pair("TABLE_NAME", json_spirit::Value(m_tableName)));
    json.push_back(
        json_spirit::Pair("COLUMN_NAME", json_spirit::Value(m_colName)));
    json.push_back(
        json_spirit::Pair("COLUMN_ALIAS", json_spirit::Value(m_colAlias)));
  }

  int m_columnIdx;    // COLUMN_IDX
  char *m_tableName;  // TABLE_NAME
  char *m_colName;    // COLUMN_NAME
  char *m_colAlias;   // COLUMN_ALIAS
};

/*
   helpers to build trivial left-associative trees
   that is (a, *, b, +, c) returns (a * b) + c
   and (a, +, b, * c) returns (a + b) * c
 */

AE *Join(AE *op, AE *left, AE *right) {
  op->left = left;
  op->right = right;
  return op;
}

AE *MakeTree(AE *tree, std::queue<AE *> &q) {
  if (!q.empty()) {
    AE *left, *right, *op;
    if (tree) {
      left = tree;
    } else {
      left = q.front();
      q.pop();
    }

    op = q.front();
    q.pop();
    right = q.front();
    q.pop();

    tree = MakeTree(Join(op, left, right), q);
  }
  return tree;
}

// boilerplate to turn the queue into a real AbstractExpression tree;
//   return the generated AE tree by reference to allow deletion (the queue
//   is emptied by the tree building process)
expression::AbstractExpression *ConvertToExpression(std::queue<AE *> &e) {
  AE *tree = MakeTree(nullptr, e);
  json_spirit::Object json = tree->SerializeValue();
  expression::AbstractExpression *exp =
      expression::AbstractExpression::CreateExpressionTree(json);
  delete tree;
  return exp;
}

/*
 * Show that simple addition works with the framework
 */
TEST(ExpressionTest, SimpleAddition) {
  std::queue<AE *> e;
  storage::Tuple junk;

  // 1 + 4
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)1));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)4));
  std::unique_ptr<expression::AbstractExpression> testexp(
      ConvertToExpression(e));

  Value result = testexp->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*testexp);

  EXPECT_EQ(ValuePeeker::PeekAsBigInt(result), 5LL);
}

/*
 * Show that the associative property is as expected
 */
TEST(ExpressionTest, SimpleMultiplication) {
  std::queue<AE *> e;
  storage::Tuple junk;

  // (1 + 4) * 5
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)1));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)4));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_MULTIPLY, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)5));

  std::unique_ptr<expression::AbstractExpression> e1(ConvertToExpression(e));
  Value r1 = e1->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*e1);
  EXPECT_EQ(ValuePeeker::PeekAsBigInt(r1), 25LL);

  // (2 * 5) + 3
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)2));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_MULTIPLY, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)5));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)3));

  std::unique_ptr<expression::AbstractExpression> e2(ConvertToExpression(e));
  Value r2 = e2->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*e2);
  EXPECT_EQ(ValuePeeker::PeekAsBigInt(r2), 13LL);
}

TEST(ExpressionTest, SimpleFilter) {
  // WHERE id = 20

  // EXPRESSION

  expression::TupleValueExpression *tup_val_exp =
      new expression::TupleValueExpression(0, 0);
  expression::ConstantValueExpression *const_val_exp =
      new expression::ConstantValueExpression(
          ValueFactory::GetIntegerValue(20));
  expression::ComparisonExpression<expression::CmpEq> *equal =
      new expression::ComparisonExpression<expression::CmpEq>(
          EXPRESSION_TYPE_COMPARE_EQUAL, tup_val_exp, const_val_exp);

  // TUPLE

  std::vector<catalog::Column> columns;

  catalog::Column column1(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "A", true);
  catalog::Column column2(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "B", true);
  columns.push_back(column1);
  columns.push_back(column2);
  catalog::Schema *schema(new catalog::Schema(columns));

  storage::Tuple *tuple(new storage::Tuple(schema, true));

  tuple->SetValue(0, ValueFactory::GetIntegerValue(20));
  tuple->SetValue(1, ValueFactory::GetIntegerValue(45));

  std::cout << (*equal);
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), true);

  tuple->SetValue(0, ValueFactory::GetIntegerValue(50));
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), false);

  // delete the root to destroy the full tree.
  delete equal;

  delete schema;
  delete tuple;
}

}  // End test namespace
}  // End peloton namespace
<commit_msg>TEST code in Expression_test.cpp<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// expression_test.cpp
//
// Identification: tests/expression/expression_test.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <iostream>
#include <sstream>
#include <queue>

#include "gtest/gtest.h"
#include "harness.h"

#include "backend/expression/abstract_expression.h"
#include "backend/common/types.h"
#include "backend/common/value_peeker.h"
#include "backend/storage/tuple.h"

#include "backend/expression/tuple_value_expression.h"
#include "backend/expression/comparison_expression.h"
#include "backend/expression/conjunction_expression.h"
#include "backend/expression/vector_expression.h"

namespace peloton {
namespace test {

//===--------------------------------------------------------------------===//
// Expression Tests
//===--------------------------------------------------------------------===//

/*
   Description of test:

   1. This test defines a data structure for each expression type with
   unique fields.

   2. The test includes a helper to convert a std::queue of these structures
   into a tree of AbstractExpressions, using the expression factory via a
   json serialization.

   3. Using this utilities, the test defines several expressions (in
   std::queue) formats and asserts on the expected result.

   TODO: Unfortunately, the json_spirit serialization asserts when trying
   to read an int field from a value serialized as a string; need to figure
   out what's going on here .. and what the proper serialization method is.
 */

/*
 *  Abstract expression mock object
 */
class AE {
 public:
  AE(ExpressionType et, ValueType vt, int vs)
      : m_type(et),
        m_valueType(vt),
        m_valueSize(vs),
        left(nullptr),
        right(nullptr) {}

  virtual ~AE() {
    delete left;
    delete right;
  }

  virtual json_spirit::Object SerializeValue() {
    json_spirit::Object json;
    Serialize(json);
    return json;
  }

  // this is how java serializes..
  // note derived class data follows the serialization of children
  virtual void Serialize(json_spirit::Object &json) {
    json.push_back(json_spirit::Pair(
        "TYPE", json_spirit::Value(ExpressionTypeToString(m_type))));
    json.push_back(json_spirit::Pair(
        "VALUE_TYPE", json_spirit::Value(ValueTypeToString(m_valueType))));
    json.push_back(
        json_spirit::Pair("VALUE_SIZE", json_spirit::Value(m_valueSize)));

    if (left) json.push_back(json_spirit::Pair("LEFT", left->SerializeValue()));
    if (right)
      json.push_back(json_spirit::Pair("RIGHT", right->SerializeValue()));
  }

  ExpressionType m_type;  // TYPE
  ValueType m_valueType;  // VALUE_TYPE
  int m_valueSize;        // VALUE_SIZE

  // to build a tree
  AE *left;
  AE *right;
};

/*
 * constant value expression mock object
 */
class CV : public AE {
 public:
  CV(ExpressionType et, ValueType vt, int vs, int64_t v)
      : AE(et, vt, vs), m_jsontype(1), m_intValue(v) {
    m_stringValue = nullptr;
    m_doubleValue = 0.0;
  }

  CV(ExpressionType et, ValueType vt, int vs, char *v)
      : AE(et, vt, vs), m_jsontype(1), m_stringValue(strdup(v)) {
    m_intValue = 0;
    m_doubleValue = 0.0;
  }

  CV(ExpressionType et, ValueType vt, int vs, double v)
      : AE(et, vt, vs), m_jsontype(1), m_doubleValue(v) {
    m_stringValue = nullptr;
    m_intValue = 0;
  }

  ~CV() {}

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    if (m_jsontype == 0)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_stringValue)));
    else if (m_jsontype == 1)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_intValue)));
    else if (m_jsontype == 2)
      json.push_back(
          json_spirit::Pair("VALUE", json_spirit::Value(m_doubleValue)));
  }

  int m_jsontype;  // 0 = string, 1 = int64_t, 2 = double

  int64_t m_intValue;    // VALUE
  char *m_stringValue;   // VALUE
  double m_doubleValue;  // VALUE
};

/*
 * parameter value expression mock object
 */
class PV : public AE {
 public:
  PV(ExpressionType et, ValueType vt, int vs, int pi)
      : AE(et, vt, vs), m_paramIdx(pi) {}

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    json.push_back(
        json_spirit::Pair("PARAM_IDX", json_spirit::Value(m_paramIdx)));
  }

  int m_paramIdx;  // PARAM_IDX
};

/*
 * tuple value expression mock object
 */
class TV : public AE {
 public:
  TV(ExpressionType et, ValueType vt, int vs, int ci, const char *tn,
     const char *cn, const char *ca)
      : AE(et, vt, vs),
        m_columnIdx(ci),
        m_tableName(strdup(tn)),
        m_colName(strdup(cn)),
        m_colAlias(strdup(ca)) {}

  ~TV() {
    delete m_tableName;
    delete m_colName;
    delete m_colAlias;
  }

  virtual void Serialize(json_spirit::Object &json) {
    AE::Serialize(json);
    json.push_back(
        json_spirit::Pair("COLUMN_IDX", json_spirit::Value(m_columnIdx)));
    json.push_back(
        json_spirit::Pair("TABLE_NAME", json_spirit::Value(m_tableName)));
    json.push_back(
        json_spirit::Pair("COLUMN_NAME", json_spirit::Value(m_colName)));
    json.push_back(
        json_spirit::Pair("COLUMN_ALIAS", json_spirit::Value(m_colAlias)));
  }

  int m_columnIdx;    // COLUMN_IDX
  char *m_tableName;  // TABLE_NAME
  char *m_colName;    // COLUMN_NAME
  char *m_colAlias;   // COLUMN_ALIAS
};

/*
   helpers to build trivial left-associative trees
   that is (a, *, b, +, c) returns (a * b) + c
   and (a, +, b, * c) returns (a + b) * c
 */

AE *Join(AE *op, AE *left, AE *right) {
  op->left = left;
  op->right = right;
  return op;
}

AE *MakeTree(AE *tree, std::queue<AE *> &q) {
  if (!q.empty()) {
    AE *left, *right, *op;
    if (tree) {
      left = tree;
    } else {
      left = q.front();
      q.pop();
    }

    op = q.front();
    q.pop();
    right = q.front();
    q.pop();

    tree = MakeTree(Join(op, left, right), q);
  }
  return tree;
}

// boilerplate to turn the queue into a real AbstractExpression tree;
//   return the generated AE tree by reference to allow deletion (the queue
//   is emptied by the tree building process)
expression::AbstractExpression *ConvertToExpression(std::queue<AE *> &e) {
  AE *tree = MakeTree(nullptr, e);
  json_spirit::Object json = tree->SerializeValue();
  expression::AbstractExpression *exp =
      expression::AbstractExpression::CreateExpressionTree(json);
  delete tree;
  return exp;
}

/*
 * Show that simple addition works with the framework
 */
TEST(ExpressionTest, SimpleAddition) {
  std::queue<AE *> e;
  storage::Tuple junk;

  // 1 + 4
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)1));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)4));
  std::unique_ptr<expression::AbstractExpression> testexp(
      ConvertToExpression(e));

  Value result = testexp->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*testexp);

  EXPECT_EQ(ValuePeeker::PeekAsBigInt(result), 5LL);
}

/*
 * Show that the associative property is as expected
 */
TEST(ExpressionTest, SimpleMultiplication) {
  std::queue<AE *> e;
  storage::Tuple junk;

  // (1 + 4) * 5
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)1));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)4));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_MULTIPLY, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)5));

  std::unique_ptr<expression::AbstractExpression> e1(ConvertToExpression(e));
  Value r1 = e1->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*e1);
  EXPECT_EQ(ValuePeeker::PeekAsBigInt(r1), 25LL);

  // (2 * 5) + 3
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)2));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_MULTIPLY, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)5));
  e.push(new AE(EXPRESSION_TYPE_OPERATOR_PLUS, VALUE_TYPE_TINYINT, 1));
  e.push(new CV(EXPRESSION_TYPE_VALUE_CONSTANT, VALUE_TYPE_TINYINT, 1,
                (int64_t)3));

  std::unique_ptr<expression::AbstractExpression> e2(ConvertToExpression(e));
  Value r2 = e2->Evaluate(&junk, nullptr, nullptr);
  std::cout << (*e2);
  EXPECT_EQ(ValuePeeker::PeekAsBigInt(r2), 13LL);
}

TEST(ExpressionTest, SimpleFilter) {
  // WHERE id = 20

  // EXPRESSION

  expression::TupleValueExpression *tup_val_exp =
      new expression::TupleValueExpression(0, 0);
  expression::ConstantValueExpression *const_val_exp =
      new expression::ConstantValueExpression(
          ValueFactory::GetIntegerValue(20));
  expression::ComparisonExpression<expression::CmpEq> *equal =
      new expression::ComparisonExpression<expression::CmpEq>(
          EXPRESSION_TYPE_COMPARE_EQUAL, tup_val_exp, const_val_exp);

  // TUPLE

  std::vector<catalog::Column> columns;

  catalog::Column column1(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "A", true);
  catalog::Column column2(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "B", true);
  columns.push_back(column1);
  columns.push_back(column2);
  catalog::Schema *schema(new catalog::Schema(columns));

  storage::Tuple *tuple(new storage::Tuple(schema, true));

  tuple->SetValue(0, ValueFactory::GetIntegerValue(20));
  tuple->SetValue(1, ValueFactory::GetIntegerValue(45));

  std::cout << (*equal);
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), true);

  tuple->SetValue(0, ValueFactory::GetIntegerValue(50));
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), false);

  // delete the root to destroy the full tree.
  delete equal;

  delete schema;
  delete tuple;
}

TEST(ExpressionTest, SimpleInFilter) {
  // WHERE id in (15, 20)

  // EXPRESSION

  expression::TupleValueExpression *tup_val_exp =
      new expression::TupleValueExpression(0, 0);
  expression::ConstantValueExpression *const_val_exp1 =
      new expression::ConstantValueExpression(
          ValueFactory::GetIntegerValue(15));
  expression::ConstantValueExpression *const_val_exp2 =
      new expression::ConstantValueExpression(
          ValueFactory::GetIntegerValue(20));

  std::vector<expression::AbstractExpression *> vec_const_exprs;
  vec_const_exprs.push_back(const_val_exp1);
  vec_const_exprs.push_back(const_val_exp2);

  expression::VectorExpression *vec_exp =
      new expression::VectorExpression(
    		  VALUE_TYPE_ARRAY, vec_const_exprs);

  expression::ComparisonExpression<expression::CmpIn> *equal =
      new expression::ComparisonExpression<expression::CmpIn>(
          EXPRESSION_TYPE_COMPARE_IN, tup_val_exp, vec_exp);

  // TUPLE

  std::vector<catalog::Column> columns;

  catalog::Column column1(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "A", true);
  catalog::Column column2(VALUE_TYPE_INTEGER, GetTypeSize(VALUE_TYPE_INTEGER),
                          "B", true);
  columns.push_back(column1);
  columns.push_back(column2);
  catalog::Schema *schema(new catalog::Schema(columns));

  storage::Tuple *tuple(new storage::Tuple(schema, true));

  tuple->SetValue(0, ValueFactory::GetIntegerValue(20));
  tuple->SetValue(1, ValueFactory::GetIntegerValue(45));

  //std::cout << (*equal);
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), true);

  tuple->SetValue(0, ValueFactory::GetIntegerValue(50));
  EXPECT_EQ(equal->Evaluate(tuple, NULL, NULL).IsTrue(), false);

  // delete the root to destroy the full tree.
  delete tup_val_exp;
  delete const_val_exp1;
  delete const_val_exp2;
  delete vec_exp;

  delete equal;

  delete schema;
  delete tuple;
}

}  // End test namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>/***************************************************************************
                          knarticlecollection.cpp  -  description
                             -------------------

    copyright            : (C) 2000 by Christian Thurner
    email                : cthurner@freepage.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <klocale.h>
#include <kmessagebox.h>

#include "knarticlecollection.h"
#include "utilities.h"

KNArticleCollection::KNArticleCollection(KNCollection *p)
	: KNCollection(p)
{
	lastID=0;
	len=0;
	siz=0;
	list=0;
	incr=50;
}

KNArticleCollection::~KNArticleCollection()
{
	clearList();
}

bool KNArticleCollection::resize(int s)
{
	KNArticle **bak=list;
	int nSize;

	if(s==0) nSize=siz+incr;
	else nSize=((s/incr)+1)*incr;

	list=(KNArticle**) realloc(list,sizeof(KNArticle*)*nSize);

  if(!list) {
		KMessageBox::error(0,i18n("Memory allocation failed!\nYou should close this application now\n, to avoid data loss."));
		list=bak;
		return false;
	}
	else {
		siz=nSize;
		//qDebug("size : %d\n",siz);
		return true;
	}
}

bool KNArticleCollection::append(KNArticle *a)
{
	if(len+1>siz)  //array too small
		if (!resize()) return false; //try to realloc

	if(a->id()==-1) a->setId(++lastID);
	list[len]=a;
	len++;

	return true;
}

void KNArticleCollection::clearList()
{
	if(list){
		for(int i=0; i<len; i++) delete list[i];
		free(list);
	}

	list=0; len=0; siz=0; lastID=0;
}

void KNArticleCollection::compactList()
{
	int newLen, nullStart=0, nullCnt=0, ptrStart=0, ptrCnt=0;

	for(int idx=0; idx<len; idx++) {
		if(list[idx]==0) {
			ptrStart=-1;
			ptrCnt=-1;
			nullStart=idx;
			nullCnt=1;
			for(int idx2=idx+1; idx2<len; idx2++) {
				if(list[idx2]==0) nullCnt++;
				else {
					ptrStart=idx2;
					ptrCnt=1;
					break;
				}
			}
			if(ptrStart!=-1) {
				for(int idx2=ptrStart+1; idx2<len; idx2++) {
					if(list[idx2]!=0) ptrCnt++;
					else break;
				}
			  memmove(&(list[nullStart]), &(list[ptrStart]), ptrCnt*sizeof(KNArticle*));
			  for(int idx2=nullStart+ptrCnt; idx2<nullStart+ptrCnt+nullCnt; idx2++)
			  	list[idx2]=0;
			  idx=nullStart+ptrCnt-1;
			  }
			else break;
		}
	}
	newLen=0;
	while(list[newLen]!=0) newLen++;
	len=newLen;
}

int KNArticleCollection::findId(int id)
{
	int start=0, end=len, mid=0, currentId=0;
	bool found=false;
	end=len;

  while (start!=end && !found) {
  	mid=(start+end)/2;
   	currentId=list[mid]->id();
    	if (currentId==id) found=true;
    	else
    		if (currentId < id)
      	start=mid+1;
    		else end=mid;
  }

 	if (found) return mid;
  else {
  	qDebug("ID %d not found!\n", id);
  	return -1;
  }

	/*int start=0, end=len, mid=0, currentId=0;
	bool found=false;

  while (start!=end && !found) {
  	mid=(start+end)/2;
   	while(mid<len && list[mid]==0) mid++;
   	if(mid==len || list[mid]==0) {
   		mid=(start+end)/2;
   	  while(mid>-1 && list[mid]==0) mid--;
   	}

   	if(mid==len || mid==-1 || list[mid]==0) {
   		found=false;
   		break;
   	}
   	else {
   		currentId=list[mid]->id();
   		if(currentId==id) found=true;
    	else if (currentId < id) start=mid+1;
    	else end=mid;
    }
	}

 	if (found) return list[mid];
  else {
  	qDebug("ID %d not found!\n", id);
  	return 0;
  }	*/
}

/*bool KNArticleCollection::setCurrent(KNArticle *a)
{
	if(a) {
		if(byId(a->id())!=0) {
			c_urrent=a;
			return true;
		}
		else {
			c_urrent=0;
			return false;
		}
	}
	else {
		c_urrent=0;
		return true;
	}
}  */

// ================================================================================

KNFile::KNFile(const QString& fname=QString::null)
 : QFile(fname), filePos(0), readBytes(0)
{
  buffer.resize(512);
  dataPtr=buffer.data();
  dataPtr[0]='\0';
}

KNFile::~KNFile()
{
}

const QCString& KNFile::readLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while(static_cast<unsigned int>(readBytes+1)==buffer.size()) {
      at(filePos);
      if(!increaseBuffer() ||
        (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        readBytes=1;
        break;
      }
    }
  } else
    readBytes=1;

  dataPtr[readBytes-1] = '\0';
  return buffer;
}

const QCString& KNFile::readLineWnewLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while(static_cast<unsigned int>(readBytes+1)==buffer.size()){
      at(filePos);
      if(!increaseBuffer() ||
        (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        dataPtr[0] = '\0';
        break;
      }
    }
  }
  else dataPtr[0] = '\0';

  return buffer;
}

bool KNFile::increaseBuffer()
{
  if(buffer.resize(2*buffer.size())) {;
    dataPtr=buffer.data();
    dataPtr[0]='\0';
    qDebug("KNFile::increaseBuffer() : buffer doubled");
    return true;
  }
  else return false;
}

<commit_msg>fixed a bug in KNFile that caused a crash in KNGroup::loadHeaders()<commit_after>/***************************************************************************
                          knarticlecollection.cpp  -  description
                             -------------------

    copyright            : (C) 2000 by Christian Thurner
    email                : cthurner@freepage.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <klocale.h>
#include <kmessagebox.h>

#include "knarticlecollection.h"
#include "utilities.h"

KNArticleCollection::KNArticleCollection(KNCollection *p)
	: KNCollection(p)
{
	lastID=0;
	len=0;
	siz=0;
	list=0;
	incr=50;
}

KNArticleCollection::~KNArticleCollection()
{
	clearList();
}

bool KNArticleCollection::resize(int s)
{
	KNArticle **bak=list;
	int nSize;

	if(s==0) nSize=siz+incr;
	else nSize=((s/incr)+1)*incr;

	list=(KNArticle**) realloc(list,sizeof(KNArticle*)*nSize);

  if(!list) {
		KMessageBox::error(0,i18n("Memory allocation failed!\nYou should close this application now\n, to avoid data loss."));
		list=bak;
		return false;
	}
	else {
		siz=nSize;
		//qDebug("size : %d\n",siz);
		return true;
	}
}

bool KNArticleCollection::append(KNArticle *a)
{
	if(len+1>siz)  //array too small
		if (!resize()) return false; //try to realloc

	if(a->id()==-1) a->setId(++lastID);
	list[len]=a;
	len++;

	return true;
}

void KNArticleCollection::clearList()
{
	if(list){
		for(int i=0; i<len; i++) delete list[i];
		free(list);
	}

	list=0; len=0; siz=0; lastID=0;
}

void KNArticleCollection::compactList()
{
	int newLen, nullStart=0, nullCnt=0, ptrStart=0, ptrCnt=0;

	for(int idx=0; idx<len; idx++) {
		if(list[idx]==0) {
			ptrStart=-1;
			ptrCnt=-1;
			nullStart=idx;
			nullCnt=1;
			for(int idx2=idx+1; idx2<len; idx2++) {
				if(list[idx2]==0) nullCnt++;
				else {
					ptrStart=idx2;
					ptrCnt=1;
					break;
				}
			}
			if(ptrStart!=-1) {
				for(int idx2=ptrStart+1; idx2<len; idx2++) {
					if(list[idx2]!=0) ptrCnt++;
					else break;
				}
			  memmove(&(list[nullStart]), &(list[ptrStart]), ptrCnt*sizeof(KNArticle*));
			  for(int idx2=nullStart+ptrCnt; idx2<nullStart+ptrCnt+nullCnt; idx2++)
			  	list[idx2]=0;
			  idx=nullStart+ptrCnt-1;
			  }
			else break;
		}
	}
	newLen=0;
	while(list[newLen]!=0) newLen++;
	len=newLen;
}

int KNArticleCollection::findId(int id)
{
	int start=0, end=len, mid=0, currentId=0;
	bool found=false;
	end=len;

  while (start!=end && !found) {
  	mid=(start+end)/2;
   	currentId=list[mid]->id();
    	if (currentId==id) found=true;
    	else
    		if (currentId < id)
      	start=mid+1;
    		else end=mid;
  }

 	if (found) return mid;
  else {
  	qDebug("ID %d not found!\n", id);
  	return -1;
  }

	/*int start=0, end=len, mid=0, currentId=0;
	bool found=false;

  while (start!=end && !found) {
  	mid=(start+end)/2;
   	while(mid<len && list[mid]==0) mid++;
   	if(mid==len || list[mid]==0) {
   		mid=(start+end)/2;
   	  while(mid>-1 && list[mid]==0) mid--;
   	}

   	if(mid==len || mid==-1 || list[mid]==0) {
   		found=false;
   		break;
   	}
   	else {
   		currentId=list[mid]->id();
   		if(currentId==id) found=true;
    	else if (currentId < id) start=mid+1;
    	else end=mid;
    }
	}

 	if (found) return list[mid];
  else {
  	qDebug("ID %d not found!\n", id);
  	return 0;
  }	*/
}

/*bool KNArticleCollection::setCurrent(KNArticle *a)
{
	if(a) {
		if(byId(a->id())!=0) {
			c_urrent=a;
			return true;
		}
		else {
			c_urrent=0;
			return false;
		}
	}
	else {
		c_urrent=0;
		return true;
	}
}  */

// ================================================================================

KNFile::KNFile(const QString& fname=QString::null)
 : QFile(fname), filePos(0), readBytes(0)
{
  buffer.resize(512);
  dataPtr=buffer.data();
  dataPtr[0]='\0';
}

KNFile::~KNFile()
{
}

const QCString& KNFile::readLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
   while(dataPtr[readBytes-1]!='\n') {
      at(filePos);
      if(!increaseBuffer() ||
        (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        readBytes=1;
        break;
      }
    }
  } else
    readBytes=1;

  dataPtr[readBytes-1] = '\0';
  return buffer;
}

const QCString& KNFile::readLineWnewLine()
{
  filePos=at();
  readBytes=QFile::readLine(dataPtr, buffer.size()-1);
  if(readBytes!=-1) {
    while(dataPtr[readBytes-1]!='\n') {
      at(filePos);
      if(!increaseBuffer() ||
        (readBytes=QFile::readLine(dataPtr, buffer.size()-1))==-1) {
        dataPtr[0] = '\0';
        break;
      }
    }
  }
  else dataPtr[0] = '\0';

  return buffer;
}

bool KNFile::increaseBuffer()
{
  if(buffer.resize(2*buffer.size())) {;
    dataPtr=buffer.data();
    dataPtr[0]='\0';
    qDebug("KNFile::increaseBuffer() : buffer doubled");
    return true;
  }
  else return false;
}

<|endoftext|>


<commit_before>#include "bandit_base.h"
#include "msg.h"

go_bandit([]()
{
    describe("Msg with `Hello %s.`", []()
    {
        PtrT<Msg> pMsg;
        before_each([&]() {
            pMsg.reset(new Msg("Hello %s"));
        });

        describe("Msg::str", [&]() {
            it("adds world", [&](){
                pMsg->add("world");
                AssertThat(pMsg->str(), Equals("Hello world."));
            });

            it("adds John", [&](){
                pMsg->add("John");
                AssertThat(pMsg->str(), Equals("Hello John."));
            });
        });

    });

    describe("args counts", [&]() {
        it("runs no args", [&]() {
            AssertThat(Msg("%% %%").count_format_count(), Equals(0));
            AssertThat(Msg("abc abc %% %%").count_format_count(), Equals(0));
            AssertThat(Msg("dce de%%").count_format_count(), Equals(0));
            AssertThat(Msg("asflkjsafklw").count_format_count(), Equals(0));
        });

        it("runs 1 arg", [&]() {
            AssertThat(Msg("%% %d").count_format_count(), Equals(1));
            AssertThat(Msg("abc %f abc %% %%").count_format_count(), Equals(1));
            AssertThat(Msg("dce%d de%%").count_format_count(), Equals(1));
            AssertThat(Msg("asfl%skjsafklw").count_format_count(), Equals(1));
        });
    });
});
<commit_msg>add 5 args test cases for count_format_args, and passed<commit_after>#include "bandit_base.h"
#include "msg.h"

go_bandit([]()
{
    describe("Msg with `Hello %s.`", []()
    {
        PtrT<Msg> pMsg;
        before_each([&]() {
            pMsg.reset(new Msg("Hello %s"));
        });

        describe("Msg::str", [&]() {
            it("adds world", [&](){
                pMsg->add("world");
                AssertThat(pMsg->str(), Equals("Hello world."));
            });

            it("adds John", [&](){
                pMsg->add("John");
                AssertThat(pMsg->str(), Equals("Hello John."));
            });
        });

    });

    describe("args counts", [&]() {
        it("runs no args", [&]() {
            AssertThat(Msg("%% %%").count_format_count(), Equals(0));
            AssertThat(Msg("abc abc %% %%").count_format_count(), Equals(0));
            AssertThat(Msg("dce de%%").count_format_count(), Equals(0));
            AssertThat(Msg("asflkjsafklw").count_format_count(), Equals(0));
        });

        it("runs 1 arg", [&]() {
            AssertThat(Msg("%% %d").count_format_count(), Equals(1));
            AssertThat(Msg("abc %f abc %% %%").count_format_count(), Equals(1));
            AssertThat(Msg("dce%d de%%").count_format_count(), Equals(1));
            AssertThat(Msg("asfl%skjsafklw").count_format_count(), Equals(1));
        });

        it("runs 5 args", [&]() {
            AssertThat(Msg("%s %d %d %f %s").count_format_count(), Equals(5));
            AssertThat(Msg("%sf%s%d%fa%sf").count_format_count(), Equals(5));
            AssertThat(Msg("%f%s%d%%s%f%%s%d").count_format_count(), Equals(5));
            AssertThat(Msg("Hello %s %f is %d and %d and %f").count_format_count(), Equals(5));
        });
    });
});
<|endoftext|>


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

#include <common.cxx>
#include <util/chunk.hpp>

static const size_t N = 1024;

CASE("Constructing an empty chunk")
{
  Chunk c;

  EXPECT(c.length() == 0);

  EXPECT_THROWS_AS(c.at(0), std::out_of_range);

  EXPECT_NOT(c);
}
CASE("Constructing a chunk with a shared buffer and size")
{
  auto buf = Chunk::make_shared_buffer(N);

  Chunk c{buf, N};

  EXPECT(c.size() == N);
  EXPECT(c);

  EXPECT(c.data() == buf.get());
}
CASE("Constructing a chunk with size")
{
  Chunk c{N};

  EXPECT(c.size() == N);
  EXPECT(c);
}
CASE("Constructing a chunk with data and size")
{
  const uint8_t* data = new uint8_t[N]{1};

  Chunk c{data, N};

  EXPECT(c.size() == N);

  auto res = std::memcmp(data, c.data(), N);

  EXPECT(res == 0);
}
CASE("Copy and move construction and assignment")
{
  const Chunk base{10};
  std::memset(base.data(), 'A', base.size());

  Chunk c1{base};
  EXPECT(c1 == base);

  Chunk c2{std::move(c1)};
  EXPECT(c2 == base);

  Chunk c3;
  c3 = base;
  EXPECT(c3 == base);

  Chunk c4;
  c4 = std::move(c3);
  EXPECT(c4 == base);
}
CASE("Combining two chunks into a new chunk")
{
  const size_t SZ = 10;

  Chunk c1{SZ};
  std::memset(c1.data(), 'A', c1.size());

  Chunk c2{SZ};
  std::memset(c2.data(), 'B', c2.size());

  EXPECT_NOT(c1 == c2);
  EXPECT(c1 != c2);

  auto c3 = c1 + c2;
  EXPECT(c3.size() == (c1.size() + c2.size()));

  auto r1 = std::memcmp(c3.data(), c1.data(), c1.size());
  auto r2 = std::memcmp(c3.data() + c1.size(), c2.data(), c2.size());

  EXPECT((r1 + r2) == 0);
}
CASE("Operations and iterators")
{
  const std::string test{"This string is for testing chunks."};

  Chunk c{(const uint8_t*) test.data(), test.size()};

  EXPECT(c.size() == test.size());

  EXPECT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  EXPECT(c[6] == test[6]);

  EXPECT_THROWS_AS(c.at(test.size()+1), std::out_of_range);

  std::string test2{c.begin(), c.end()};

  EXPECT(test2 == test);

  std::string test3;
  for(auto it = c.begin(); it != c.end(); ++it)
    test3.push_back((const char)(*it));

  EXPECT(test3 == test);

  c.at(c.size() - 1) = '!';

  EXPECT_NOT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  const std::string test4{"This string is for testing chunks!"};

  EXPECT(std::memcmp(c.data(), test4.data(), c.size()) == 0);

  c.clear();

  EXPECT_NOT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  auto is_cleared = [&c]()->bool
  {
    for(auto&& byte : c)
      if(byte != 0) return false;
    return true;
  };
  EXPECT(is_cleared());
}
CASE("Filling chunks")
{
  const std::string test{"This string is for testing chunks."};

  Chunk c1{test.size()};
  auto written = c1.fill((const uint8_t*) test.data(), test.size());

  EXPECT(written == test.size());

  EXPECT(std::memcmp(c1.data(), test.data(), c1.size()) == 0);

  const auto half = test.size() / 2;

  written = c1.fill((const uint8_t*) test.data(), test.size(), half);

  EXPECT(written == half);

  EXPECT_NOT(std::memcmp(c1.data(), test.data(), c1.size()) == 0);

  EXPECT(std::memcmp(c1.data() + half, test.data(), half) == 0);

  Chunk c2{half};

  written = c2.fill((const uint8_t*) test.data(), test.size());

  EXPECT(written == half);

  std::string test2{c2.begin(), c2.end()};
  EXPECT(test2 == test.substr(0, half));

  written = c2.fill((const uint8_t*) test.data(), test.size(), half);
  EXPECT(written == 0);
}
<commit_msg>unit_test: Prevented badly encoded output from showing<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2016-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <common.cxx>
#include <util/chunk.hpp>

static const size_t N = 1024;

CASE("Constructing an empty chunk")
{
  Chunk c;

  EXPECT(c.length() == 0);

  EXPECT_THROWS_AS(c.at(0), std::out_of_range);

  EXPECT_NOT(c);
}
CASE("Constructing a chunk with a shared buffer and size")
{
  auto buf = Chunk::make_shared_buffer(N);

  Chunk c{buf, N};

  EXPECT(c.size() == N);
  EXPECT(static_cast<bool>(c));

  EXPECT(c.data() == buf.get());
}
CASE("Constructing a chunk with size")
{
  Chunk c{N};

  EXPECT(c.size() == N);
  EXPECT(c);
}
CASE("Constructing a chunk with data and size")
{
  const uint8_t* data = new uint8_t[N]{1};

  Chunk c{data, N};

  EXPECT(c.size() == N);

  auto res = std::memcmp(data, c.data(), N);

  EXPECT(res == 0);
}
CASE("Copy and move construction and assignment")
{
  const Chunk base{10};
  std::memset(base.data(), 'A', base.size());

  Chunk c1{base};
  EXPECT(c1 == base);

  Chunk c2{std::move(c1)};
  EXPECT(c2 == base);

  Chunk c3;
  c3 = base;
  EXPECT(c3 == base);

  Chunk c4;
  c4 = std::move(c3);
  EXPECT(c4 == base);
}
CASE("Combining two chunks into a new chunk")
{
  const size_t SZ = 10;

  Chunk c1{SZ};
  std::memset(c1.data(), 'A', c1.size());

  Chunk c2{SZ};
  std::memset(c2.data(), 'B', c2.size());

  EXPECT_NOT(c1 == c2);
  EXPECT(c1 != c2);

  auto c3 = c1 + c2;
  EXPECT(c3.size() == (c1.size() + c2.size()));

  auto r1 = std::memcmp(c3.data(), c1.data(), c1.size());
  auto r2 = std::memcmp(c3.data() + c1.size(), c2.data(), c2.size());

  EXPECT((r1 + r2) == 0);
}
CASE("Operations and iterators")
{
  const std::string test{"This string is for testing chunks."};

  Chunk c{(const uint8_t*) test.data(), test.size()};

  EXPECT(c.size() == test.size());

  EXPECT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  EXPECT(c[6] == test[6]);

  EXPECT_THROWS_AS(c.at(test.size()+1), std::out_of_range);

  std::string test2{c.begin(), c.end()};

  EXPECT(test2 == test);

  std::string test3;
  for(auto it = c.begin(); it != c.end(); ++it)
    test3.push_back((const char)(*it));

  EXPECT(test3 == test);

  c.at(c.size() - 1) = '!';

  EXPECT_NOT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  const std::string test4{"This string is for testing chunks!"};

  EXPECT(std::memcmp(c.data(), test4.data(), c.size()) == 0);

  c.clear();

  EXPECT_NOT(std::memcmp(c.data(), test.data(), c.size()) == 0);

  auto is_cleared = [&c]()->bool
  {
    for(auto&& byte : c)
      if(byte != 0) return false;
    return true;
  };
  EXPECT(is_cleared());
}
CASE("Filling chunks")
{
  const std::string test{"This string is for testing chunks."};

  Chunk c1{test.size()};
  auto written = c1.fill((const uint8_t*) test.data(), test.size());

  EXPECT(written == test.size());

  EXPECT(std::memcmp(c1.data(), test.data(), c1.size()) == 0);

  const auto half = test.size() / 2;

  written = c1.fill((const uint8_t*) test.data(), test.size(), half);

  EXPECT(written == half);

  EXPECT_NOT(std::memcmp(c1.data(), test.data(), c1.size()) == 0);

  EXPECT(std::memcmp(c1.data() + half, test.data(), half) == 0);

  Chunk c2{half};

  written = c2.fill((const uint8_t*) test.data(), test.size());

  EXPECT(written == half);

  std::string test2{c2.begin(), c2.end()};
  EXPECT(test2 == test.substr(0, half));

  written = c2.fill((const uint8_t*) test.data(), test.size(), half);
  EXPECT(written == 0);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "image.h"
#include <Eigen/Dense>
#include <Eigen/SVD>

#define DEFAULT_SIZE 5

using namespace MR;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "denoise DWI data and estimate the noise level based on the optimal threshold for PCA.";

  AUTHOR = "Daan Christiaens (daan.christiaens@kuleuven.be) & Jelle Veraart (jelle.veraart@nyumc.org) & J-Donald Tournier (jdtournier.gmail.com)";

  ARGUMENTS
  + Argument ("dwi", "the input diffusion-weighted image.").type_image_in ()

  + Argument ("out", "the output denoised DWI image.").type_image_out ();

  OPTIONS
    + Option ("mask", "only perform computation within the specified binary brain mask image.")
    +   Argument ("image").type_image_in()

    + Option ("extent", "set the window size of the denoising filter. (default = " + str(DEFAULT_SIZE) + ")")
    +   Argument ("window").type_integer (0, 50)

    + Option ("noise", "the output noise map.")
    +   Argument ("level").type_image_out();

}

typedef float value_type;

template <class ImageType>
class DenoisingFunctor
{
  public:
  DenoisingFunctor (ImageType& dwi, int extent, Image<bool>& mask, ImageType& noise)
    : extent (extent/2),
      m (dwi.size(3)),
      n (extent*extent*extent),
      r ((m<n) ? m : n),
      X (m,n),
      pos {{0, 0, 0}},
      mask (mask),
      noise (noise)
  { }

  void operator () (ImageType& dwi, ImageType& out)
  {
    if (mask.valid()) {
      assign_pos_of (dwi).to (mask);
      if (!mask.value())
        return;
    }

    // Load data in local window
    load_data (dwi);

    // Compute Eigendecomposition:
    Eigen::MatrixXf XtX (r,r);
    if (m <= n)
      XtX.template triangularView<Eigen::Lower>() = X * X.transpose();
    else
      XtX.template triangularView<Eigen::Lower>() = X.transpose() * X;
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (XtX);
    // eigenvalues provide squared singular values:
    Eigen::VectorXf s = eig.eigenvalues();

    // Marchenko-Pastur optimal threshold
    const double lam_r = s[0] / n;
    double clam = 0.0;
    sigma2 = NaN;
    ssize_t cutoff_p = 0;
    for (ssize_t p = 0; p < r; ++p)
    {
      double lam = s[p] / n;
      clam += lam;
      double gam = double(m-r+p+1) / double(n);
      double sigsq1 = clam / (m-r+p+1) / std::max (gam, 1.0);
      double sigsq2 = (lam - lam_r) / 4 / std::sqrt(gam);
      // sigsq2 > sigsq1 if signal else noise
      if (sigsq2 < sigsq1) {
        sigma2 = sigsq1;
        cutoff_p = p+1;
      }
    }

    if (cutoff_p > 0) {
      // recombine data using only eigenvectors above threshold:
      s.head (cutoff_p).setZero();
      s.tail (r-cutoff_p).setOnes();
      if (m <= n)
        X.col (n/2) = eig.eigenvectors() * s.asDiagonal() * eig.eigenvectors().adjoint() * X.col(n/2);
      else
        X.col (n/2) = X * eig.eigenvectors() * s.asDiagonal() * eig.eigenvectors().adjoint().col(n/2);
    }

    // Store output
    assign_pos_of(dwi).to(out);
    for (auto l = Loop (3) (out); l; ++l)
      out.value() = X(out.index(3), n/2);

    // store noise map if requested:
    if (noise.valid()) {
      assign_pos_of(dwi).to(noise);
      noise.value() = value_type (std::sqrt(sigma2));
    }
  }

  void load_data (ImageType& dwi)
  {
    pos[0] = dwi.index(0); pos[1] = dwi.index(1); pos[2] = dwi.index(2);
    X.setZero();
    ssize_t k = 0;
    for (dwi.index(2) = pos[2]-extent; dwi.index(2) <= pos[2]+extent; ++dwi.index(2))
      for (dwi.index(1) = pos[1]-extent; dwi.index(1) <= pos[1]+extent; ++dwi.index(1))
        for (dwi.index(0) = pos[0]-extent; dwi.index(0) <= pos[0]+extent; ++dwi.index(0), ++k)
          if (! is_out_of_bounds(dwi))
            X.col(k) = dwi.row(3).template cast<float>();
    // reset image position
    dwi.index(0) = pos[0];
    dwi.index(1) = pos[1];
    dwi.index(2) = pos[2];
  }

private:
  const int extent;
  const ssize_t m, n, r;
  Eigen::MatrixXf X;
  std::array<ssize_t, 3> pos;
  double sigma2;
  Image<bool> mask;
  ImageType noise;

};

void run ()
{
  auto dwi_in = Image<value_type>::open (argument[0]).with_direct_io(3);

  Image<bool> mask;
  auto opt = get_options ("mask");
  if (opt.size()) {
    mask = Image<bool>::open (opt[0][0]);
    check_dimensions (mask, dwi_in, 0, 3);
  }

  auto header = Header (dwi_in);
  header.datatype() = DataType::Float32;
  auto dwi_out = Image<value_type>::create (argument[1], header);

  int extent = get_option_value("extent", DEFAULT_SIZE);
  if (!(extent & 1))
    throw Exception ("-extent must be an odd number");

  Image<value_type> noise;
  opt = get_options("noise");
  if (opt.size()) {
    header.set_ndim(3);
    noise = Image<value_type>::create (opt[0][0], header);
  }

  DenoisingFunctor< Image<value_type> > func (dwi_in, extent, mask, noise);
  ThreadedLoop ("running MP-PCA denoising", dwi_in, 0, 3)
    .run (func, dwi_in, dwi_out);
}

<commit_msg>MP-PCA: dotting the i's and crossing the t's.<commit_after>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "image.h"
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>

#define DEFAULT_SIZE 5

using namespace MR;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "denoise DWI data and estimate the noise level based on the optimal threshold for PCA.";

  AUTHOR = "Daan Christiaens (daan.christiaens@kuleuven.be) & Jelle Veraart (jelle.veraart@nyumc.org) & J-Donald Tournier (jdtournier@gmail.com)";

  ARGUMENTS
  + Argument ("dwi", "the input diffusion-weighted image.").type_image_in ()

  + Argument ("out", "the output denoised DWI image.").type_image_out ();

  OPTIONS
    + Option ("mask", "only perform computation within the specified binary brain mask image.")
    +   Argument ("image").type_image_in()

    + Option ("extent", "set the window size of the denoising filter. (default = " + str(DEFAULT_SIZE) + ")")
    +   Argument ("window").type_integer (0, 50)

    + Option ("noise", "the output noise map.")
    +   Argument ("level").type_image_out();

}

typedef float value_type;

template <class ImageType>
class DenoisingFunctor
{
  public:
  DenoisingFunctor (ImageType& dwi, int extent, Image<bool>& mask, ImageType& noise)
    : extent (extent/2),
      m (dwi.size(3)),
      n (extent*extent*extent),
      r ((m<n) ? m : n),
      X (m,n),
      pos {{0, 0, 0}},
      mask (mask),
      noise (noise)
  { }

  void operator () (ImageType& dwi, ImageType& out)
  {
    if (mask.valid()) {
      assign_pos_of (dwi).to (mask);
      if (!mask.value())
        return;
    }

    // Load data in local window
    load_data (dwi);

    // Compute Eigendecomposition:
    Eigen::MatrixXf XtX (r,r);
    if (m <= n)
      XtX.template triangularView<Eigen::Lower>() = X * X.transpose();
    else
      XtX.template triangularView<Eigen::Lower>() = X.transpose() * X;
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (XtX);
    // eigenvalues provide squared singular values:
    Eigen::VectorXf s = eig.eigenvalues();

    // Marchenko-Pastur optimal threshold
    const double lam_r = s[0] / n;
    double clam = 0.0;
    sigma2 = NaN;
    ssize_t cutoff_p = 0;
    for (ssize_t p = 0; p < r; ++p)
    {
      double lam = s[p] / n;
      clam += lam;
      double gam = double(m-r+p+1) / double(n);
      double sigsq1 = clam / (m-r+p+1) / std::max (gam, 1.0);
      double sigsq2 = (lam - lam_r) / 4 / std::sqrt(gam);
      // sigsq2 > sigsq1 if signal else noise
      if (sigsq2 < sigsq1) {
        sigma2 = sigsq1;
        cutoff_p = p+1;
      }
    }

    if (cutoff_p > 0) {
      // recombine data using only eigenvectors above threshold:
      s.head (cutoff_p).setZero();
      s.tail (r-cutoff_p).setOnes();
      if (m <= n)
        X.col (n/2) = eig.eigenvectors() * s.asDiagonal() * eig.eigenvectors().adjoint() * X.col(n/2);
      else
        X.col (n/2) = X * eig.eigenvectors() * s.asDiagonal() * eig.eigenvectors().adjoint().col(n/2);
    }

    // Store output
    assign_pos_of(dwi).to(out);
    for (auto l = Loop (3) (out); l; ++l)
      out.value() = X(out.index(3), n/2);

    // store noise map if requested:
    if (noise.valid()) {
      assign_pos_of(dwi).to(noise);
      noise.value() = value_type (std::sqrt(sigma2));
    }
  }

  void load_data (ImageType& dwi)
  {
    pos[0] = dwi.index(0); pos[1] = dwi.index(1); pos[2] = dwi.index(2);
    X.setZero();
    ssize_t k = 0;
    for (dwi.index(2) = pos[2]-extent; dwi.index(2) <= pos[2]+extent; ++dwi.index(2))
      for (dwi.index(1) = pos[1]-extent; dwi.index(1) <= pos[1]+extent; ++dwi.index(1))
        for (dwi.index(0) = pos[0]-extent; dwi.index(0) <= pos[0]+extent; ++dwi.index(0), ++k)
          if (! is_out_of_bounds(dwi))
            X.col(k) = dwi.row(3).template cast<float>();
    // reset image position
    dwi.index(0) = pos[0];
    dwi.index(1) = pos[1];
    dwi.index(2) = pos[2];
  }

private:
  const int extent;
  const ssize_t m, n, r;
  Eigen::MatrixXf X;
  std::array<ssize_t, 3> pos;
  double sigma2;
  Image<bool> mask;
  ImageType noise;

};

void run ()
{
  auto dwi_in = Image<value_type>::open (argument[0]).with_direct_io(3);

  Image<bool> mask;
  auto opt = get_options ("mask");
  if (opt.size()) {
    mask = Image<bool>::open (opt[0][0]);
    check_dimensions (mask, dwi_in, 0, 3);
  }

  auto header = Header (dwi_in);
  header.datatype() = DataType::Float32;
  auto dwi_out = Image<value_type>::create (argument[1], header);

  int extent = get_option_value("extent", DEFAULT_SIZE);
  if (!(extent & 1))
    throw Exception ("-extent must be an odd number");

  Image<value_type> noise;
  opt = get_options("noise");
  if (opt.size()) {
    header.set_ndim(3);
    noise = Image<value_type>::create (opt[0][0], header);
  }

  DenoisingFunctor< Image<value_type> > func (dwi_in, extent, mask, noise);
  ThreadedLoop ("running MP-PCA denoising", dwi_in, 0, 3)
    .run (func, dwi_in, dwi_out);
}

<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

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

  StatPages.cc

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

#include "ink_config.h"
#include "ProxyConfig.h"
#include "StatPages.h"
#include "HdrUtils.h"
#include "MatcherUtils.h"

#define MAX_STAT_PAGES      32

// Globals
StatPagesManager statPagesManager;

static struct
{
  char *module;
  StatPagesFunc func;
} stat_pages[MAX_STAT_PAGES];

static volatile int n_stat_pages = 0;

void
StatPagesManager::init()
{
  REC_EstablishStaticConfigInt32(m_enabled, "proxy.config.http_ui_enabled");
}

void
StatPagesManager::register_http(const char *module, StatPagesFunc func)
{
  ink_release_assert(n_stat_pages < MAX_STAT_PAGES);

  stat_pages[n_stat_pages].module = (char *)ats_malloc(strlen(module) + 3);
  snprintf(stat_pages[n_stat_pages].module, strlen(module) + 3, "{%s}", module);
  stat_pages[n_stat_pages++].func = func;
}

Action *
StatPagesManager::handle_http(Continuation * cont, HTTPHdr * header, int client_ip)
{
  NOWARN_UNUSED(client_ip);
  URL *url = header->url_get();

  if (((m_enabled == 1 || m_enabled == 3) && is_cache_inspector_page(url)) ||
      ((m_enabled == 2 || m_enabled == 3) && is_stat_page(url) && !is_cache_inspector_page(url))) {
    int host_len;
    char host[MAXDNAME + 1];
    const char *h;
    int i;

    h = url->host_get(&host_len);
    if (host_len > MAXDNAME)
      host_len = MAXDNAME;
    memcpy(host, h, host_len);
    host[host_len] = '\0';
    host_len = unescapifyStr(host);

    for (i = 0; i < n_stat_pages; i++) {
      if (ptr_len_cmp(host, host_len, stat_pages[i].module) == 0) {
        return stat_pages[i].func(cont, header);
      }
    }
  }

  cont->handleEvent(STAT_PAGE_FAILURE, 0);
  return ACTION_RESULT_DONE;
}

bool
StatPagesManager::is_stat_page(URL * url)
{
  int length;
  const char *h = url->host_get(&length);
  char host[MAXDNAME + 1];

  if (h == NULL || length < 2 || length > MAXDNAME)
    return false;

  memcpy(host, h, length);
  host[length] = '\0';
  length = unescapifyStr(host);

  if ((host[0] == '{') && (host[length - 1] == '}'))
    return true;

  return false;
}

bool
StatPagesManager::is_cache_inspector_page(URL * url)
{
  int length;
  const char *h = url->host_get(&length);
  char host[MAXDNAME + 1];

  if (h == NULL || length < 2 || length > MAXDNAME)
    return false;

  memcpy(host, h, length);
  host[length] = '\0';
  length = unescapifyStr(host);

  if (strncmp(host, "{cache}", length) == 0)
    return true;
  else
    return false;

}

void
BaseStatPagesHandler::resp_clear()
{
  ats_free(response);
  response = NULL;
  response_size = 0;
  response_length = 0;
}

void
BaseStatPagesHandler::resp_add(const char *fmt, ...)
{
  va_list args;
  char buf[16384];
  int length;
  int size;

  va_start(args, fmt);
  length = vsnprintf(buf, 16384, fmt, args);
  va_end(args);

  size = response_size;
  if (size == 0) {
    size = 1024;
  }
  while ((response_length + length + 1) > size) {
    size *= 2;
  }

  if (size != response_size) {
    if (!response) {
      response = (char *)ats_malloc(size);
    } else {
      response = (char *)ats_realloc(response, size);
    }
    response_size = size;
  }

  memcpy(&response[response_length], buf, length + 1);
  response_length += length;
}

void
BaseStatPagesHandler::resp_add_sep()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin(const char *title)
{
  resp_clear();
  resp_add("\n"
           "<title>%s</title>\n"
           "\n", title);
}

void
BaseStatPagesHandler::resp_end()
{
  resp_add("\n" "\n");
}

void
BaseStatPagesHandler::resp_begin_numbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_numbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_unnumbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_unnumbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_item()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_item()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_table(int border, int columns, int percent)
{
  resp_add("
\n", border, columns, percent);
}

void
BaseStatPagesHandler::resp_end_table()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_row()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_row()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_column(int percent, const char *align)
{
  if (percent == -1) {
    resp_add("\n", align ? "align=" : "", align ? align : "");
  } else {
    resp_add("\n", percent, align ? "align=" : "", align ? align : "");
  }
}

void
BaseStatPagesHandler::resp_end_column()
{
  resp_add("	\n");
}
<commit_msg>TS-979 Small optimization when stat pages are disabled<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

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

  StatPages.cc

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

#include "ink_config.h"
#include "ProxyConfig.h"
#include "StatPages.h"
#include "HdrUtils.h"
#include "MatcherUtils.h"

#define MAX_STAT_PAGES      32

// Globals
StatPagesManager statPagesManager;

static struct
{
  char *module;
  StatPagesFunc func;
} stat_pages[MAX_STAT_PAGES];

static volatile int n_stat_pages = 0;

void
StatPagesManager::init()
{
  REC_EstablishStaticConfigInt32(m_enabled, "proxy.config.http_ui_enabled");
}

void
StatPagesManager::register_http(const char *module, StatPagesFunc func)
{
  ink_release_assert(n_stat_pages < MAX_STAT_PAGES);

  stat_pages[n_stat_pages].module = (char *)ats_malloc(strlen(module) + 3);
  snprintf(stat_pages[n_stat_pages].module, strlen(module) + 3, "{%s}", module);
  stat_pages[n_stat_pages++].func = func;
}

Action *
StatPagesManager::handle_http(Continuation * cont, HTTPHdr * header, int client_ip)
{
  NOWARN_UNUSED(client_ip);
  URL *url = header->url_get();

  if (((m_enabled == 1 || m_enabled == 3) && is_cache_inspector_page(url)) ||
      ((m_enabled == 2 || m_enabled == 3) && is_stat_page(url) && !is_cache_inspector_page(url))) {
    int host_len;
    char host[MAXDNAME + 1];
    const char *h;
    int i;

    h = url->host_get(&host_len);
    if (host_len > MAXDNAME)
      host_len = MAXDNAME;
    memcpy(host, h, host_len);
    host[host_len] = '\0';
    host_len = unescapifyStr(host);

    for (i = 0; i < n_stat_pages; i++) {
      if (ptr_len_cmp(host, host_len, stat_pages[i].module) == 0) {
        return stat_pages[i].func(cont, header);
      }
    }
  }

  cont->handleEvent(STAT_PAGE_FAILURE, 0);
  return ACTION_RESULT_DONE;
}

bool
StatPagesManager::is_stat_page(URL * url)
{
  // This gets called from the state machine, so we should optimize here and not in caller.
  if (m_enabled <= 0)
    return false;

  int length;
  const char *h = url->host_get(&length);
  char host[MAXDNAME + 1];

  if (h == NULL || length < 2 || length > MAXDNAME)
    return false;

  memcpy(host, h, length);
  host[length] = '\0';
  length = unescapifyStr(host);

  if ((host[0] == '{') && (host[length - 1] == '}'))
    return true;

  return false;
}

bool
StatPagesManager::is_cache_inspector_page(URL * url)
{
  int length;
  const char *h = url->host_get(&length);
  char host[MAXDNAME + 1];

  if (h == NULL || length < 2 || length > MAXDNAME)
    return false;

  memcpy(host, h, length);
  host[length] = '\0';
  length = unescapifyStr(host);

  if (strncmp(host, "{cache}", length) == 0)
    return true;
  else
    return false;

}

void
BaseStatPagesHandler::resp_clear()
{
  ats_free(response);
  response = NULL;
  response_size = 0;
  response_length = 0;
}

void
BaseStatPagesHandler::resp_add(const char *fmt, ...)
{
  va_list args;
  char buf[16384];
  int length;
  int size;

  va_start(args, fmt);
  length = vsnprintf(buf, 16384, fmt, args);
  va_end(args);

  size = response_size;
  if (size == 0) {
    size = 1024;
  }
  while ((response_length + length + 1) > size) {
    size *= 2;
  }

  if (size != response_size) {
    if (!response) {
      response = (char *)ats_malloc(size);
    } else {
      response = (char *)ats_realloc(response, size);
    }
    response_size = size;
  }

  memcpy(&response[response_length], buf, length + 1);
  response_length += length;
}

void
BaseStatPagesHandler::resp_add_sep()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin(const char *title)
{
  resp_clear();
  resp_add("\n"
           "<title>%s</title>\n"
           "\n", title);
}

void
BaseStatPagesHandler::resp_end()
{
  resp_add("\n" "\n");
}

void
BaseStatPagesHandler::resp_begin_numbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_numbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_unnumbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_unnumbered()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_item()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_item()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_table(int border, int columns, int percent)
{
  resp_add("
\n", border, columns, percent);
}

void
BaseStatPagesHandler::resp_end_table()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_row()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_end_row()
{
  resp_add("
\n");
}

void
BaseStatPagesHandler::resp_begin_column(int percent, const char *align)
{
  if (percent == -1) {
    resp_add("\n", align ? "align=" : "", align ? align : "");
  } else {
    resp_add("\n", percent, align ? "align=" : "", align ? align : "");
  }
}

void
BaseStatPagesHandler::resp_end_column()
{
  resp_add("	\n");
}
<|endoftext|>


<commit_before>#include <iostream>
#include <math.h>
#include <string>
#include <vector>
#include "mex.h"

#include <nix.hpp>

#include "handle.h"
#include "arguments.h"

// *** datatype converter

template<typename T>
struct to_mx_class_id {

    static std::pair<mxClassID, mxComplexity> value() {
        nix::DataType dtype = nix::to_data_type<T>::value;
        switch (dtype) {
            case nix::DataType::Double:
                return std::make_pair(mxDOUBLE_CLASS, mxREAL);

            default:
                mexErrMsgIdAndTxt("nix:toclassid:notimplemented", "Implement me!");
                return std::make_pair(mxVOID_CLASS, mxREAL);
        }
    }

};

template<typename T>
mxArray* vector_to_array(const std::vector<T> &v) {
    std::pair<mxClassID, mxComplexity> klass = to_mx_class_id<T>::value();
    mxArray *data = mxCreateNumericMatrix(1, v.size(), klass.first, klass.second);
    double *ptr = mxGetPr(data);
    memcpy(ptr, v.data(), sizeof(T) * v.size());
    return data;
}

template<>
mxArray* vector_to_array(const std::vector<std::string> &v) {
    mxArray *data = mxCreateCellMatrix(1, v.size());
    for (size_t i = 0; i < v.size(); i++) {
        mxSetCell(data, i, mxCreateString(v[i].c_str()));
    }

    return data;
}

// *** functions ***

static void entity_destory(const extractor &input, infusor &output)
{
    mexPrintf("[+] entity_destory\n");
    handle h = input.hdl(1);
    h.destroy();
}

static void open_file(const extractor &input, infusor &output)
{
    input.require_arguments({mxCHAR_CLASS, mxCHAR_CLASS}, true);
    mexPrintf("[+] open_file\n");

    std::string name = input.str(1);

    nix::File fn = nix::File::open(name, nix::FileMode::ReadWrite);
    handle h = handle(fn);

    output.set(0, h);
}

static void list_blocks(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_blocks\n");
    nix::File fd = input.entity<nix::File>(1);

    std::vector<nix::Block> blocks = fd.blocks();

    std::vector<const char *> fields = { "name", "id" };

    mxArray *sa =  mxCreateStructMatrix(blocks.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < blocks.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(blocks[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(blocks[n].id().c_str()));
    }

    output.set(0, sa);
}

static void list_data_arrays(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");

    nix::File nf = input.entity<nix::File>(1);
    nix::Block block = nf.getBlock(input.str(2));

    std::vector<nix::DataArray> arr = block.dataArrays();

    std::vector<const char *> fields = { "name", "id" };

    mxArray *sa =  mxCreateStructMatrix(arr.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < arr.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(arr[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(arr[n].id().c_str()));
    }

    output.set(0, sa);
}

static void open_block(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");
    nix::File nf = input.entity<nix::File>(1);
    nix::Block block = nf.getBlock(input.str(2));
    handle bb = handle(block);
    output.set(0, bb);
}

static void open_data_array(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");
    nix::Block block = input.entity<nix::Block>(1);
    nix::DataArray da = block.getDataArray(input.str(2));
    handle bd = handle(da);
    output.set(0, bd);
}

static void block_list_data_arrays(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");

    nix::Block block = input.entity<nix::Block>(1);
    std::vector<nix::DataArray> arr = block.dataArrays();

    std::vector<const char *> fields = { "name", "id" };

    mxArray *sa =  mxCreateStructMatrix(arr.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < arr.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(arr[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(arr[n].id().c_str()));
    }

    output.set(0, sa);
}

static mxArray * ndsize_to_mxarray(const nix::NDSize &size)
{
    mxArray *res = mxCreateNumericMatrix(1, size.size(), mxUINT64_CLASS, mxREAL);
    void *ptr = mxGetData(res);
    uint64_t *data = static_cast<uint64_t *>(ptr);

    for (size_t i = 0; i < size.size(); i++) {
        data[i] = static_cast<uint64_t>(size[i]);
    }

    return res;
}

static nix::NDSize mx_array_to_ndsize(const mxArray *arr) {

    size_t m = mxGetM(arr);
    size_t n = mxGetN(arr);

    //if (m != 1 && n != 1)

    size_t k = std::max(n, m);
    nix::NDSize size(k);

    double *data = mxGetPr(arr);
    for (size_t i = 0; i < size.size(); i++) {
        size[i] = static_cast<nix::NDSize::value_type>(data[i]);
    }

    return size;
}

static mxArray *nmCreateScalar(uint32_t val) {
    mxArray *arr = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL);
    void *data = mxGetData(arr);
    memcpy(data, &val, sizeof(uint32_t));
    return arr;
}

static mxArray *dim_to_struct(nix::SetDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "labels" };
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("set"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(1));

    std::vector<std::string> labels = dim.labels();
    mxSetFieldByNumber(sa, 0, 2, vector_to_array(labels));

    return sa;
}

static mxArray *dim_to_struct(nix::SampledDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "interval", "label", "unit"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("sampled"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(2));
    mxSetFieldByNumber(sa, 0, 2, mxCreateDoubleScalar(dim.samplingInterval()));

    boost::optional<std::string> label = dim.label();
    if (label) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(label->c_str()));
    }

    boost::optional<std::string> unit = dim.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 4, mxCreateString(unit->c_str()));
    }

    return sa;
}

static mxArray *dim_to_struct(nix::RangeDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "ticks", "unit"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("range"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(3));

    std::vector<double> ticks = dim.ticks();
    mxSetFieldByNumber(sa, 0, 2, vector_to_array(ticks));

    boost::optional<std::string> unit = dim.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(unit->c_str()));
    }

    return sa;
}

static void data_array_describe(const extractor &input, infusor &output)
{
    mexPrintf("[+] block_describe_data_array\n");
    nix::DataArray da = input.entity<nix::DataArray>(1);

    std::vector<const char *> fields = { "name", "id", "shape",  "unit", "dimensions", "label",
                                         "polynom_coefficients"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString(da.name().c_str()));
    mxSetFieldByNumber(sa, 0, 1, mxCreateString(da.id().c_str()));
    mxSetFieldByNumber(sa, 0, 2, ndsize_to_mxarray(da.dataExtent()));

    boost::optional<std::string> unit = da.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(unit->c_str()));
    }

    size_t ndims = da.dimensionCount();

    mxArray *dims = mxCreateCellMatrix(1, ndims);
    std::vector<nix::Dimension> da_dims = da.dimensions();

    for(size_t i = 0; i < ndims; i++) {
        mxArray *ca;

        switch(da_dims[i].dimensionType()) {
            case nix::DimensionType::Set:
                ca = dim_to_struct(da_dims[i].asSetDimension());
                break;
            case nix::DimensionType::Range:
                ca = dim_to_struct(da_dims[i].asRangeDimension());
                break;
            case nix::DimensionType::Sample:
                ca = dim_to_struct(da_dims[i].asSampledDimension());
                break;
        }

        mxSetCell(dims, i, ca);
    }

    mxSetFieldByNumber(sa, 0, 4, dims);

    boost::optional<std::string> label = da.label();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 5, mxCreateString(label->c_str()));
    }

    std::vector<double> pc = da.polynomCoefficients();

    if (!pc.empty()) {
        mxSetFieldByNumber(sa, 0, 6, vector_to_array(pc));
    }

    output.set(0, sa);
}

static void data_array_read_all(const extractor &input, infusor &output)
{
    mexPrintf("[+] block_describe_data_array\n");
    nix::DataArray da = input.entity<nix::DataArray>(1);

    nix::NDSize size = da.dataExtent();
    std::vector<mwSize> dims(size.size());

    for (size_t i = 0; i < size.size(); i++) {
        dims[i] = static_cast<mwSize>(size[i]);
    }

    mxArray *data = mxCreateNumericArray(size.size(), dims.data(), mxDOUBLE_CLASS, mxREAL);
    double *ptr = mxGetPr(data);

    nix::NDSize offset(size.size(), 0);
    da.getData(nix::DataType::Double , ptr, size, offset);

    output.set(0, data);
}

// *** ***

typedef void (*fn_t)(const extractor &input, infusor &output);

struct fendpoint {

fendpoint(std::string name, fn_t fn) : name(name), fn(fn) {}

    std::string name;
    fn_t fn;
};

const std::vector<fendpoint> funcs = {
        {"Entity::destroy", entity_destory},
        {"File::open", open_file},
        {"File::listBlocks", list_blocks},
        {"File::listDataArrays", list_data_arrays},
        {"File::openBlock", open_block},
        {"Block::openDataArray", open_data_array},
        {"Block::listDataArrays", block_list_data_arrays},
        {"DataArray::describe", data_array_describe},
        {"DataArray::readAll", data_array_read_all}
};

// main entry point
void mexFunction(int            nlhs,
                 mxArray       *lhs[],
                 int            nrhs,
                 const mxArray *rhs[])
{
    extractor input(rhs, nrhs);
    infusor   output(lhs, nlhs);

    std::string cmd = input.str(0);

    mexPrintf("[F] %s\n", cmd.c_str());

    bool processed = false;
    for (const auto &fn : funcs) {
        if (fn.name == cmd) {
            try {
                fn.fn(input, output);
            } catch (std::exception &e) {
                mexErrMsgIdAndTxt("nix:arg:dispatch", e.what());
            } catch (...) {
                mexErrMsgIdAndTxt("nix:arg:dispatch", "unkown exception");
            }
            processed = true;
            break;
        }
    }

    if (!processed) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "Unkown command");
    }
}

<commit_msg>vector_to_array → make_mx_array<commit_after>#include <iostream>
#include <math.h>
#include <string>
#include <vector>
#include "mex.h"

#include <nix.hpp>

#include "handle.h"
#include "arguments.h"

// *** datatype converter

template<typename T>
struct to_mx_class_id {

    static std::pair<mxClassID, mxComplexity> value() {
        nix::DataType dtype = nix::to_data_type<T>::value;
        switch (dtype) {
            case nix::DataType::Double:
                return std::make_pair(mxDOUBLE_CLASS, mxREAL);

            default:
                mexErrMsgIdAndTxt("nix:toclassid:notimplemented", "Implement me!");
                return std::make_pair(mxVOID_CLASS, mxREAL);
        }
    }

};

template<typename T>
mxArray* make_mx_array(const std::vector<T> &v) {
    std::pair<mxClassID, mxComplexity> klass = to_mx_class_id<T>::value();
    mxArray *data = mxCreateNumericMatrix(1, v.size(), klass.first, klass.second);
    double *ptr = mxGetPr(data);
    memcpy(ptr, v.data(), sizeof(T) * v.size());
    return data;
}

template<>
mxArray* make_mx_array(const std::vector<std::string> &v) {
    mxArray *data = mxCreateCellMatrix(1, v.size());
    for (size_t i = 0; i < v.size(); i++) {
        mxSetCell(data, i, mxCreateString(v[i].c_str()));
    }

    return data;
}

// *** functions ***

static void entity_destory(const extractor &input, infusor &output)
{
    mexPrintf("[+] entity_destory\n");
    handle h = input.hdl(1);
    h.destroy();
}

static void open_file(const extractor &input, infusor &output)
{
    input.require_arguments({mxCHAR_CLASS, mxCHAR_CLASS}, true);
    mexPrintf("[+] open_file\n");

    std::string name = input.str(1);

    nix::File fn = nix::File::open(name, nix::FileMode::ReadWrite);
    handle h = handle(fn);

    output.set(0, h);
}

static void list_blocks(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_blocks\n");
    nix::File fd = input.entity<nix::File>(1);

    std::vector<nix::Block> blocks = fd.blocks();

    std::vector<const char *> fields = { "name", "id", "type" };

    mxArray *sa =  mxCreateStructMatrix(blocks.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < blocks.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(blocks[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(blocks[n].id().c_str()));
        mxSetFieldByNumber(sa, n, 2, mxCreateString(blocks[n].type().c_str()));
    }

    output.set(0, sa);
}

static void list_data_arrays(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");

    nix::File nf = input.entity<nix::File>(1);
    nix::Block block = nf.getBlock(input.str(2));

    std::vector<nix::DataArray> arr = block.dataArrays();

    std::vector<const char *> fields = { "name", "id" };

    mxArray *sa =  mxCreateStructMatrix(arr.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < arr.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(arr[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(arr[n].id().c_str()));
    }

    output.set(0, sa);
}

static void open_block(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");
    nix::File nf = input.entity<nix::File>(1);
    nix::Block block = nf.getBlock(input.str(2));
    handle bb = handle(block);
    output.set(0, bb);
}

static void open_data_array(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");
    nix::Block block = input.entity<nix::Block>(1);
    nix::DataArray da = block.getDataArray(input.str(2));
    handle bd = handle(da);
    output.set(0, bd);
}

static void block_list_data_arrays(const extractor &input, infusor &output)
{
    mexPrintf("[+] list_data_arrays\n");

    nix::Block block = input.entity<nix::Block>(1);
    std::vector<nix::DataArray> arr = block.dataArrays();

    std::vector<const char *> fields = { "name", "id" };

    mxArray *sa =  mxCreateStructMatrix(arr.size(), 1, fields.size(), fields.data());

    for (size_t n = 0; n < arr.size(); n++) {
        mxSetFieldByNumber(sa, n, 0, mxCreateString(arr[n].name().c_str()));
        mxSetFieldByNumber(sa, n, 1, mxCreateString(arr[n].id().c_str()));
    }

    output.set(0, sa);
}

static mxArray * ndsize_to_mxarray(const nix::NDSize &size)
{
    mxArray *res = mxCreateNumericMatrix(1, size.size(), mxUINT64_CLASS, mxREAL);
    void *ptr = mxGetData(res);
    uint64_t *data = static_cast<uint64_t *>(ptr);

    for (size_t i = 0; i < size.size(); i++) {
        data[i] = static_cast<uint64_t>(size[i]);
    }

    return res;
}

static nix::NDSize mx_array_to_ndsize(const mxArray *arr) {

    size_t m = mxGetM(arr);
    size_t n = mxGetN(arr);

    //if (m != 1 && n != 1)

    size_t k = std::max(n, m);
    nix::NDSize size(k);

    double *data = mxGetPr(arr);
    for (size_t i = 0; i < size.size(); i++) {
        size[i] = static_cast<nix::NDSize::value_type>(data[i]);
    }

    return size;
}

static mxArray *nmCreateScalar(uint32_t val) {
    mxArray *arr = mxCreateNumericMatrix(1, 1, mxUINT32_CLASS, mxREAL);
    void *data = mxGetData(arr);
    memcpy(data, &val, sizeof(uint32_t));
    return arr;
}

static mxArray *dim_to_struct(nix::SetDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "labels" };
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("set"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(1));

    std::vector<std::string> labels = dim.labels();
    mxSetFieldByNumber(sa, 0, 2, make_mx_array(labels));

    return sa;
}

static mxArray *dim_to_struct(nix::SampledDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "interval", "label", "unit"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("sampled"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(2));
    mxSetFieldByNumber(sa, 0, 2, mxCreateDoubleScalar(dim.samplingInterval()));

    boost::optional<std::string> label = dim.label();
    if (label) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(label->c_str()));
    }

    boost::optional<std::string> unit = dim.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 4, mxCreateString(unit->c_str()));
    }

    return sa;
}

static mxArray *dim_to_struct(nix::RangeDimension dim) {

    std::vector<const char *> fields = { "type", "type_id", "ticks", "unit"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString("range"));
    mxSetFieldByNumber(sa, 0, 1, nmCreateScalar(3));

    std::vector<double> ticks = dim.ticks();
    mxSetFieldByNumber(sa, 0, 2, make_mx_array(ticks));

    boost::optional<std::string> unit = dim.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(unit->c_str()));
    }

    return sa;
}

static void data_array_describe(const extractor &input, infusor &output)
{
    mexPrintf("[+] block_describe_data_array\n");
    nix::DataArray da = input.entity<nix::DataArray>(1);

    std::vector<const char *> fields = { "name", "id", "shape",  "unit", "dimensions", "label",
                                         "polynom_coefficients"};
    mxArray *sa =  mxCreateStructMatrix(1, 1, fields.size(), fields.data());

    mxSetFieldByNumber(sa, 0, 0, mxCreateString(da.name().c_str()));
    mxSetFieldByNumber(sa, 0, 1, mxCreateString(da.id().c_str()));
    mxSetFieldByNumber(sa, 0, 2, ndsize_to_mxarray(da.dataExtent()));

    boost::optional<std::string> unit = da.unit();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 3, mxCreateString(unit->c_str()));
    }

    size_t ndims = da.dimensionCount();

    mxArray *dims = mxCreateCellMatrix(1, ndims);
    std::vector<nix::Dimension> da_dims = da.dimensions();

    for(size_t i = 0; i < ndims; i++) {
        mxArray *ca;

        switch(da_dims[i].dimensionType()) {
            case nix::DimensionType::Set:
                ca = dim_to_struct(da_dims[i].asSetDimension());
                break;
            case nix::DimensionType::Range:
                ca = dim_to_struct(da_dims[i].asRangeDimension());
                break;
            case nix::DimensionType::Sample:
                ca = dim_to_struct(da_dims[i].asSampledDimension());
                break;
        }

        mxSetCell(dims, i, ca);
    }

    mxSetFieldByNumber(sa, 0, 4, dims);

    boost::optional<std::string> label = da.label();
    if (unit) {
        mxSetFieldByNumber(sa, 0, 5, mxCreateString(label->c_str()));
    }

    std::vector<double> pc = da.polynomCoefficients();

    if (!pc.empty()) {
        mxSetFieldByNumber(sa, 0, 6, make_mx_array(pc));
    }

    output.set(0, sa);
}

static void data_array_read_all(const extractor &input, infusor &output)
{
    mexPrintf("[+] block_describe_data_array\n");
    nix::DataArray da = input.entity<nix::DataArray>(1);

    nix::NDSize size = da.dataExtent();
    std::vector<mwSize> dims(size.size());

    for (size_t i = 0; i < size.size(); i++) {
        dims[i] = static_cast<mwSize>(size[i]);
    }

    mxArray *data = mxCreateNumericArray(size.size(), dims.data(), mxDOUBLE_CLASS, mxREAL);
    double *ptr = mxGetPr(data);

    nix::NDSize offset(size.size(), 0);
    da.getData(nix::DataType::Double , ptr, size, offset);

    output.set(0, data);
}

// *** ***

typedef void (*fn_t)(const extractor &input, infusor &output);

struct fendpoint {

fendpoint(std::string name, fn_t fn) : name(name), fn(fn) {}

    std::string name;
    fn_t fn;
};

const std::vector<fendpoint> funcs = {
        {"Entity::destroy", entity_destory},
        {"File::open", open_file},
        {"File::listBlocks", list_blocks},
        {"File::listDataArrays", list_data_arrays},
        {"File::openBlock", open_block},
        {"Block::openDataArray", open_data_array},
        {"Block::listDataArrays", block_list_data_arrays},
        {"DataArray::describe", data_array_describe},
        {"DataArray::readAll", data_array_read_all}
};

// main entry point
void mexFunction(int            nlhs,
                 mxArray       *lhs[],
                 int            nrhs,
                 const mxArray *rhs[])
{
    extractor input(rhs, nrhs);
    infusor   output(lhs, nlhs);

    std::string cmd = input.str(0);

    mexPrintf("[F] %s\n", cmd.c_str());

    bool processed = false;
    for (const auto &fn : funcs) {
        if (fn.name == cmd) {
            try {
                fn.fn(input, output);
            } catch (std::exception &e) {
                mexErrMsgIdAndTxt("nix:arg:dispatch", e.what());
            } catch (...) {
                mexErrMsgIdAndTxt("nix:arg:dispatch", "unkown exception");
            }
            processed = true;
            break;
        }
    }

    if (!processed) {
        mexErrMsgIdAndTxt("nix:arg:dispatch", "Unkown command");
    }
}

<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2009-2011 Robert N. M. Watson
 * Copyright (c) 2011 Jonathan Anderson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "capsicum.h"
#include "capsicum-test.h"

// Test openat(2) in a variety of sitations to ensure that it obeys Capsicum
// "strict relative" rules:
//
// 1. Use strict relative lookups in capability mode or when operating
//    relative to a capability.
// 2. When performing strict relative lookups, absolute paths (including
//    symlinks to absolute paths) are not allowed, nor are paths containing
//    '..' components.
FORK_TEST(Openat, Relative) {
  int etc = open("/etc/", O_RDONLY);
  EXPECT_OK(etc);

  cap_rights_t rights;
  EXPECT_SYSCALL_FAIL(EINVAL, cap_getrights(etc, &rights));

  cap_rights_t baserights = (CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP);
  int etc_cap = cap_new(etc, CAP_READ);
  EXPECT_OK(etc_cap);
  int etc_cap_ro = cap_new(etc, CAP_READ | CAP_LOOKUP);
  EXPECT_OK(etc_cap_ro);
  int etc_cap_base = cap_new(etc, baserights);
  EXPECT_OK(etc_cap_base);
  int etc_cap_all = cap_new(etc, CAP_MASK_VALID);
  EXPECT_OK(etc_cap_all);

  // openat(2) with regular file descriptors in non-capability mode
  // should Just Work (tm).
  EXPECT_OK(openat(etc, "/etc/passwd", O_RDONLY));
  EXPECT_OK(openat(AT_FDCWD, "/etc/passwd", O_RDONLY));
  EXPECT_OK(openat(etc, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc, "../etc/passwd", O_RDONLY));

  // Lookups relative to capabilities should be strictly relative.
  // When not in capability mode, we don't actually require CAP_LOOKUP.
  EXPECT_OK(openat(etc_cap_ro, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_base, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_all, "passwd", O_RDONLY));

#ifndef __linux__
  // TODO(drysdale): figure out why this returns EBADF not ENOTCAPABLE
  EXPECT_NOTCAPABLE(openat(etc_cap_ro, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_base, "../etc/passwd", O_RDONLY));
#endif

  // This requires discussion: do we treat a capability with
  // CAP_MASK_VALID *exactly* like a non-capability file descriptor
  // (currently, the implementation says yes)?
  EXPECT_OK(openat(etc_cap_all, "../etc/passwd", O_RDONLY));

  // A file opened relative to a capability should itself be a capability.
  EXPECT_OK(cap_getrights(etc_cap_base, &rights));

  int fd = openat(etc_cap_base, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_RIGHTS_IN(rights, baserights);

  // Enter capability mode; now ALL lookups are strictly relative.
  EXPECT_OK(cap_enter());

  // Relative lookups on regular files or capabilities with CAP_LOOKUP
  // ought to succeed.
  EXPECT_OK(openat(etc, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_ro, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_base, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_all, "passwd", O_RDONLY));

  // Lookup relative to capabilities without CAP_LOOKUP should fail.
  EXPECT_NOTCAPABLE(openat(etc_cap, "passwd", O_RDONLY));

  // Absolute lookups should fail.
  EXPECT_CAPMODE(openat(AT_FDCWD, "/etc/passwd", O_RDONLY));
#ifndef __linux__
  // TODO(drysdale): figure out why this returns ECAPMODE not ENOTCAPABLE
  EXPECT_NOTCAPABLE(openat(etc, "/etc/passwd", O_RDONLY));

  // Lookups containing '..' should fail in capability mode.
  EXPECT_NOTCAPABLE(openat(etc, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_ro, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_base, "../etc/passwd", O_RDONLY));
#endif

  fd = openat(etc, "passwd", O_RDONLY);
  EXPECT_OK(fd);

  // A file opened relative to a capability should itself be a capability.
  fd = openat(etc_cap_base, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_OK(cap_getrights(fd, &rights));
  EXPECT_RIGHTS_IN(rights, baserights);

  fd = openat(etc_cap_ro, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_OK(cap_getrights(fd, &rights));
  EXPECT_RIGHTS_IN(rights, (CAP_READ|CAP_LOOKUP));
}
<commit_msg>Only expect openat() to return ENOTCAPABLE on systems that police rights before cap_enter() (i.e. not on current capsicum-linux).<commit_after>/*-
 * Copyright (c) 2009-2011 Robert N. M. Watson
 * Copyright (c) 2011 Jonathan Anderson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "capsicum.h"
#include "capsicum-test.h"

// Test openat(2) in a variety of sitations to ensure that it obeys Capsicum
// "strict relative" rules:
//
// 1. Use strict relative lookups in capability mode or when operating
//    relative to a capability.
// 2. When performing strict relative lookups, absolute paths (including
//    symlinks to absolute paths) are not allowed, nor are paths containing
//    '..' components.
FORK_TEST(Openat, Relative) {
  int etc = open("/etc/", O_RDONLY);
  EXPECT_OK(etc);

  cap_rights_t rights;
  EXPECT_SYSCALL_FAIL(EINVAL, cap_getrights(etc, &rights));

  cap_rights_t baserights = (CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP);
  int etc_cap = cap_new(etc, CAP_READ);
  EXPECT_OK(etc_cap);
  int etc_cap_ro = cap_new(etc, CAP_READ | CAP_LOOKUP);
  EXPECT_OK(etc_cap_ro);
  int etc_cap_base = cap_new(etc, baserights);
  EXPECT_OK(etc_cap_base);
  int etc_cap_all = cap_new(etc, CAP_MASK_VALID);
  EXPECT_OK(etc_cap_all);

  // openat(2) with regular file descriptors in non-capability mode
  // should Just Work (tm).
  EXPECT_OK(openat(etc, "/etc/passwd", O_RDONLY));
  EXPECT_OK(openat(AT_FDCWD, "/etc/passwd", O_RDONLY));
  EXPECT_OK(openat(etc, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc, "../etc/passwd", O_RDONLY));

  // Lookups relative to capabilities should be strictly relative.
  // When not in capability mode, we don't actually require CAP_LOOKUP.
  EXPECT_OK(openat(etc_cap_ro, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_base, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_all, "passwd", O_RDONLY));

#ifdef HAVE_RIGHTS_CHECK_OUTSIDE_CAPMODE
  EXPECT_NOTCAPABLE(openat(etc_cap_ro, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_base, "../etc/passwd", O_RDONLY));
#else
  int temp_fd = openat(etc_cap_base, "../etc/passwd", O_RDONLY);
  EXPECT_OK(temp_fd);
  if (temp_fd >= 0) close(temp_fd);
#endif

  // This requires discussion: do we treat a capability with
  // CAP_MASK_VALID *exactly* like a non-capability file descriptor
  // (currently, the implementation says yes)?
  EXPECT_OK(openat(etc_cap_all, "../etc/passwd", O_RDONLY));

  // A file opened relative to a capability should itself be a capability.
  EXPECT_OK(cap_getrights(etc_cap_base, &rights));

  int fd = openat(etc_cap_base, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_RIGHTS_IN(rights, baserights);

  // Enter capability mode; now ALL lookups are strictly relative.
  EXPECT_OK(cap_enter());

  // Relative lookups on regular files or capabilities with CAP_LOOKUP
  // ought to succeed.
  EXPECT_OK(openat(etc, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_ro, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_base, "passwd", O_RDONLY));
  EXPECT_OK(openat(etc_cap_all, "passwd", O_RDONLY));

  // Lookup relative to capabilities without CAP_LOOKUP should fail.
  EXPECT_NOTCAPABLE(openat(etc_cap, "passwd", O_RDONLY));

  // Absolute lookups should fail.
  EXPECT_CAPMODE(openat(AT_FDCWD, "/etc/passwd", O_RDONLY));
#ifndef __linux__
  // TODO(drysdale): figure out why this returns ECAPMODE not ENOTCAPABLE
  EXPECT_NOTCAPABLE(openat(etc, "/etc/passwd", O_RDONLY));

  // Lookups containing '..' should fail in capability mode.
  EXPECT_NOTCAPABLE(openat(etc, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_ro, "../etc/passwd", O_RDONLY));
  EXPECT_NOTCAPABLE(openat(etc_cap_base, "../etc/passwd", O_RDONLY));
#endif

  fd = openat(etc, "passwd", O_RDONLY);
  EXPECT_OK(fd);

  // A file opened relative to a capability should itself be a capability.
  fd = openat(etc_cap_base, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_OK(cap_getrights(fd, &rights));
  EXPECT_RIGHTS_IN(rights, baserights);

  fd = openat(etc_cap_ro, "passwd", O_RDONLY);
  EXPECT_OK(fd);
  EXPECT_OK(cap_getrights(fd, &rights));
  EXPECT_RIGHTS_IN(rights, (CAP_READ|CAP_LOOKUP));
}
<|endoftext|>