<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// expression_test.cpp
//
// Identification: test/expression/expressionutil_test.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "common/harness.h"
#include "common/logger.h"

#include "type/value.h"
#include "type/value_factory.h"
#include "expression/abstract_expression.h"
#include "expression/expression_util.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {

namespace test {

class ExpressionUtilTests : public PelotonTest {};

std::string CONSTANT_VALUE_STRING1 = "ABC";
std::string CONSTANT_VALUE_STRING2 = "XYZ";

expression::AbstractExpression* createExpTree() {
  auto exp1 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(1));
  auto exp2 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(1));
  auto exp3 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, exp1, exp2);

  auto exp4 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetVarcharValue(CONSTANT_VALUE_STRING1));
  auto exp5 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetVarcharValue(CONSTANT_VALUE_STRING2));
  auto exp6 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_NOTEQUAL, exp4, exp5);

  auto root = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, exp3, exp6);
  return (root);
}

// Make sure that we can traverse a tree
TEST_F(ExpressionUtilTests, GetInfoTest) {
  auto root = createExpTree();
  std::string info = expression::ExpressionUtil::GetInfo(root);

  // Just make sure that it has our constant strings
  EXPECT_TRUE(info.size() > 0);
  EXPECT_NE(std::string::npos, info.find(CONSTANT_VALUE_STRING1));
  EXPECT_NE(std::string::npos, info.find(CONSTANT_VALUE_STRING2));

  delete root;
}

TEST_F(ExpressionUtilTests, ExtractJoinColTest) {
  // Table1.a = Table2.b
  auto expr1 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr2 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 0);
  auto expr3 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr1, expr2);

  // Table1.c < Table2.d
  auto expr4 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 0);
  auto expr5 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 1);
  auto expr6 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_LESSTHAN, expr4, expr5);

  // Table1.a = 3
  auto expr7 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr8 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(3));
  auto expr9 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr7, expr8);

  // Table1.c = Table2.d
  auto expr10 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 0);
  auto expr11 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 1);
  auto expr12 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr10, expr11);

  std::vector<std::unique_ptr<const expression::AbstractExpression>> l_column_ids,
      r_column_ids;
  // Table1.a = Table2.b -> nullptr
  auto ret_expr1 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr3, true);
  EXPECT_EQ(nullptr, ret_expr1);
  EXPECT_EQ(1, l_column_ids.size());

  // (Table1.a = Table2.b) AND (Table1.c < Table2.d) -> (Table1.c < Table2.d)
  auto expr13 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr3, expr6);
  l_column_ids.clear();
  r_column_ids.clear();
  auto ret_expr2 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr13, true);

  EXPECT_EQ(ExpressionType::COMPARE_LESSTHAN, ret_expr2->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr2->GetChild(0)->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr2->GetChild(1)->GetExpressionType());

  EXPECT_EQ(1, l_column_ids.size());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[0].get())->GetColumnId());

  // Table1.a = Table2.b
  auto expr14 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr15 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 0);
  auto expr16 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr14, expr15);
  // ((Table1.a = Table2.b AND Table1.c = Table2.d) AND Table1.a = 3) ->
  // Table1.a = 3
  auto expr17 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr16, expr12);

  auto expr18 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr17, expr9);

  l_column_ids.clear();
  r_column_ids.clear();
  auto ret_expr3 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr18, true);

  EXPECT_EQ(2, l_column_ids.size());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[1].get())->GetColumnId());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[1].get())->GetColumnId());

  EXPECT_EQ(ExpressionType::COMPARE_EQUAL, ret_expr3->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr3->GetChild(0)->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_CONSTANT,
            ret_expr3->GetChild(1)->GetExpressionType());

  if (ret_expr1 != nullptr) delete ret_expr1;
  delete ret_expr2;
  delete ret_expr3;
  delete expr18;
  delete expr13;
}
}  // namespace test
}  // namespace peloton
<commit_msg>Fix expression_util_test<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// expression_test.cpp
//
// Identification: test/expression/expressionutil_test.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "common/harness.h"
#include "common/logger.h"

#include "type/value.h"
#include "type/value_factory.h"
#include "expression/abstract_expression.h"
#include "expression/expression_util.h"

using ::testing::NotNull;
using ::testing::Return;

namespace peloton {

namespace test {

class ExpressionUtilTests : public PelotonTest {};

std::string CONSTANT_VALUE_STRING1 = "ABC";
std::string CONSTANT_VALUE_STRING2 = "XYZ";

expression::AbstractExpression* createExpTree() {
  auto exp1 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(1));
  auto exp2 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(1));
  auto exp3 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, exp1, exp2);

  auto exp4 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetVarcharValue(CONSTANT_VALUE_STRING1));
  auto exp5 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetVarcharValue(CONSTANT_VALUE_STRING2));
  auto exp6 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_NOTEQUAL, exp4, exp5);

  auto root = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, exp3, exp6);
  return (root);
}

// Make sure that we can traverse a tree
TEST_F(ExpressionUtilTests, GetInfoTest) {
  auto root = createExpTree();
  std::string info = expression::ExpressionUtil::GetInfo(root);

  // Just make sure that it has our constant strings
  EXPECT_TRUE(info.size() > 0);
  EXPECT_NE(std::string::npos, info.find(CONSTANT_VALUE_STRING1));
  EXPECT_NE(std::string::npos, info.find(CONSTANT_VALUE_STRING2));

  delete root;
}

TEST_F(ExpressionUtilTests, ExtractJoinColTest) {
  // Table1.a = Table2.b
  auto expr1 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr2 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 0);
  auto expr3 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr1, expr2);

  // Table1.c < Table2.d
  auto expr4 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 0);
  auto expr5 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 1);
  auto expr6 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_LESSTHAN, expr4, expr5);

  // Table1.a = 3
  auto expr7 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr8 = expression::ExpressionUtil::ConstantValueFactory(
      type::ValueFactory::GetIntegerValue(3));
  auto expr9 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr7, expr8);

  // Table1.c = Table2.d
  auto expr10 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 0);
  auto expr11 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 1);
  auto expr12 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr10, expr11);

  std::vector<std::unique_ptr<const expression::AbstractExpression>> l_column_ids,
      r_column_ids;
  // Table1.a = Table2.b -> nullptr
  auto ret_expr1 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr3);
  EXPECT_EQ(nullptr, ret_expr1);
  EXPECT_EQ(1, l_column_ids.size());

  // (Table1.a = Table2.b) AND (Table1.c < Table2.d) -> (Table1.c < Table2.d)
  auto expr13 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr3, expr6);
  l_column_ids.clear();
  r_column_ids.clear();
  auto ret_expr2 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr13);

  EXPECT_EQ(ExpressionType::COMPARE_LESSTHAN, ret_expr2->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr2->GetChild(0)->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr2->GetChild(1)->GetExpressionType());

  EXPECT_EQ(1, l_column_ids.size());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[0].get())->GetColumnId());

  // Table1.a = Table2.b
  auto expr14 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 0, 1);
  auto expr15 =
      expression::ExpressionUtil::TupleValueFactory(type::Type::INTEGER, 1, 0);
  auto expr16 = expression::ExpressionUtil::ComparisonFactory(
      ExpressionType::COMPARE_EQUAL, expr14, expr15);
  // ((Table1.a = Table2.b AND Table1.c = Table2.d) AND Table1.a = 3) ->
  // Table1.a = 3
  auto expr17 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr16, expr12);

  auto expr18 = expression::ExpressionUtil::ConjunctionFactory(
      ExpressionType::CONJUNCTION_AND, expr17, expr9);

  l_column_ids.clear();
  r_column_ids.clear();
  auto ret_expr3 = expression::ExpressionUtil::ExtractJoinColumns(
      l_column_ids, r_column_ids, expr18);

  EXPECT_EQ(2, l_column_ids.size());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[0].get())->GetColumnId());
  EXPECT_EQ(0, reinterpret_cast<const expression::TupleValueExpression *>(
        l_column_ids[1].get())->GetColumnId());
  EXPECT_EQ(1, reinterpret_cast<const expression::TupleValueExpression *>(
        r_column_ids[1].get())->GetColumnId());

  EXPECT_EQ(ExpressionType::COMPARE_EQUAL, ret_expr3->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_TUPLE,
            ret_expr3->GetChild(0)->GetExpressionType());
  EXPECT_EQ(ExpressionType::VALUE_CONSTANT,
            ret_expr3->GetChild(1)->GetExpressionType());

  if (ret_expr1 != nullptr) delete ret_expr1;
  delete ret_expr2;
  delete ret_expr3;
  delete expr18;
  delete expr13;
}
}  // namespace test
}  // namespace peloton
<|endoftext|>


<commit_before>#ifndef DOMLSParserFilter_HEADER_GUARD_
#define DOMLSParserFilter_HEADER_GUARD_

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

/*
 * $Id$
 */

/**
 *
 * DOMLSParserFilter.hpp: interface for the DOMLSParserFilter class.
 *
 * DOMLSParserFilter provide applications the ability to examine nodes
 * as they are being created during the parse process.
 *
 * DOMLSParserFilter lets the application decide what nodes should be
 * in the output DOM tree or not.
 *
 * @since DOM Level 3
 */

XERCES_CPP_NAMESPACE_BEGIN

class CDOM_EXPORT DOMLSParserFilter {
protected:
    // -----------------------------------------------------------------------
    //  Hidden constructors
    // -----------------------------------------------------------------------
    /** @name Hidden constructors */
    //@{
    DOMLSParserFilter() {};
    //@}

private:
    // -----------------------------------------------------------------------
    // Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    /** @name Unimplemented constructors and operators */
    //@{
    DOMLSParserFilter(const DOMLSParserFilter &);
    DOMLSParserFilter & operator = (const DOMLSParserFilter &);
    //@}

public:
    // -----------------------------------------------------------------------
    //  All constructors are hidden, just the destructor is available
    // -----------------------------------------------------------------------
    /** @name Destructor */
    //@{
    /**
     * Destructor
     *
     */
    virtual ~DOMLSParserFilter() {};
    //@}

    // -----------------------------------------------------------------------
    //  Class Types
    // -----------------------------------------------------------------------
    /** @name Public Contants */
    //@{
    /**
     * Constants returned by acceptNode.
     *
     *
FILTER_ACCEPT:
     * Accept the node.

     *
     *
FILTER_REJECT:
     * Reject the node and its children.

     *
     *
FILTER_SKIP:
     * Skip this single node. The children of this node will still be considered.

     *
     *
FILTER_INTERRUPT:
     * Interrupt the normal processing of the document.

     *
     * @since DOM Level 3
     */
    enum FilterAction {FILTER_ACCEPT = 1,
                       FILTER_REJECT = 2,
                       FILTER_SKIP   = 3,
                       FILTER_INTERRUPT = 4};

    // -----------------------------------------------------------------------
    //  Virtual DOMLSParserFilter interface
    // -----------------------------------------------------------------------
    /** @name Functions introduced in DOM Level 3 */
    //@{
	 /**
       * This method will be called by the parser at the completion of the parsing of each node.
       * The node and all of its descendants will exist and be complete. The parent node will also exist,
       * although it may be incomplete, i.e. it may have additional children that have not yet been parsed.
       * Attribute nodes are never passed to this function.
       * From within this method, the new node may be freely modified - children may be added or removed,
       * text nodes modified, etc. The state of the rest of the document outside this node is not defined,
       * and the affect of any attempt to navigate to, or to modify any other part of the document is undefined.
       * For validating parsers, the checks are made on the original document, before any modification by the
       * filter. No validity checks are made on any document modifications made by the filter.
       * If this new node is rejected, the parser might reuse the new node and any of its descendants.
       *
       * @param node The newly constructed element. At the time this method is called, the element is complete -
       *             it has all of its children (and their children, recursively) and attributes, and is attached
       *             as a child to its parent.
       * @return One of the FilterAction enum
       */
    virtual short acceptNode(DOMNode* node) = 0;

	 /**
       * The parser will call this method after each DOMElement start tag has been scanned,
       * but before the remainder of the DOMElement is processed. The intent is to allow the element,
       * including any children, to be efficiently skipped. Note that only element nodes are passed to the
       * startElement function.
       * The element node passed to startElement for filtering will include all of the attributes, but none
       * of the children nodes. The DOMElement may not yet be in place in the document being
       * constructed (it may not have a parent node.)
       * A startElement filter function may access or change the attributes for the DOMElement.
       * Changing namespace declarations will have no effect on namespace resolution by the parser.
       *
       * @param node The newly encountered element. At the time this method is called, the element is incomplete -
       *             it will have its attributes, but no children.
       * @return One of the FilterAction enum
       */
    virtual short startElement(DOMElement* node) = 0;

    /**
     * Tells the DOMLSParser what types of nodes to show to the method DOMLSParserFilter::acceptNode.
     * If a node is not shown to the filter using this attribute, it is automatically included in the DOM document being built.
     * See DOMNodeFilter for definition of the constants. The constants SHOW_ATTRIBUTE, SHOW_DOCUMENT,
     * SHOW_DOCUMENT_TYPE, SHOW_NOTATION, SHOW_ENTITY, and SHOW_DOCUMENT_FRAGMENT are meaningless here.
     * Those nodes will never be passed to DOMLSParserFilter::acceptNode.
     *
     * @return The constants of what types of nodes to show.
     * @since DOM Level 3
     */
    virtual unsigned long getWhatToShow() const = 0;

    //@}

private:

};

XERCES_CPP_NAMESPACE_END

#endif
<commit_msg>added forward declaration of DOMNode and DOMElement - needed since the header files are not included<commit_after>#ifndef DOMLSParserFilter_HEADER_GUARD_
#define DOMLSParserFilter_HEADER_GUARD_

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

/*
 * $Id$
 */

/**
 *
 * DOMLSParserFilter.hpp: interface for the DOMLSParserFilter class.
 *
 * DOMLSParserFilter provide applications the ability to examine nodes
 * as they are being created during the parse process.
 *
 * DOMLSParserFilter lets the application decide what nodes should be
 * in the output DOM tree or not.
 *
 * @since DOM Level 3
 */

XERCES_CPP_NAMESPACE_BEGIN

class DOMElement;
class DOMNode;

class CDOM_EXPORT DOMLSParserFilter {
protected:
    // -----------------------------------------------------------------------
    //  Hidden constructors
    // -----------------------------------------------------------------------
    /** @name Hidden constructors */
    //@{
    DOMLSParserFilter() {};
    //@}

private:
    // -----------------------------------------------------------------------
    // Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    /** @name Unimplemented constructors and operators */
    //@{
    DOMLSParserFilter(const DOMLSParserFilter &);
    DOMLSParserFilter & operator = (const DOMLSParserFilter &);
    //@}

public:
    // -----------------------------------------------------------------------
    //  All constructors are hidden, just the destructor is available
    // -----------------------------------------------------------------------
    /** @name Destructor */
    //@{
    /**
     * Destructor
     *
     */
    virtual ~DOMLSParserFilter() {};
    //@}

    // -----------------------------------------------------------------------
    //  Class Types
    // -----------------------------------------------------------------------
    /** @name Public Contants */
    //@{
    /**
     * Constants returned by acceptNode.
     *
     *
FILTER_ACCEPT:
     * Accept the node.

     *
     *
FILTER_REJECT:
     * Reject the node and its children.

     *
     *
FILTER_SKIP:
     * Skip this single node. The children of this node will still be considered.

     *
     *
FILTER_INTERRUPT:
     * Interrupt the normal processing of the document.

     *
     * @since DOM Level 3
     */
    enum FilterAction {FILTER_ACCEPT = 1,
                       FILTER_REJECT = 2,
                       FILTER_SKIP   = 3,
                       FILTER_INTERRUPT = 4};

    // -----------------------------------------------------------------------
    //  Virtual DOMLSParserFilter interface
    // -----------------------------------------------------------------------
    /** @name Functions introduced in DOM Level 3 */
    //@{
	 /**
       * This method will be called by the parser at the completion of the parsing of each node.
       * The node and all of its descendants will exist and be complete. The parent node will also exist,
       * although it may be incomplete, i.e. it may have additional children that have not yet been parsed.
       * Attribute nodes are never passed to this function.
       * From within this method, the new node may be freely modified - children may be added or removed,
       * text nodes modified, etc. The state of the rest of the document outside this node is not defined,
       * and the affect of any attempt to navigate to, or to modify any other part of the document is undefined.
       * For validating parsers, the checks are made on the original document, before any modification by the
       * filter. No validity checks are made on any document modifications made by the filter.
       * If this new node is rejected, the parser might reuse the new node and any of its descendants.
       *
       * @param node The newly constructed element. At the time this method is called, the element is complete -
       *             it has all of its children (and their children, recursively) and attributes, and is attached
       *             as a child to its parent.
       * @return One of the FilterAction enum
       */
    virtual short acceptNode(DOMNode* node) = 0;

	 /**
       * The parser will call this method after each DOMElement start tag has been scanned,
       * but before the remainder of the DOMElement is processed. The intent is to allow the element,
       * including any children, to be efficiently skipped. Note that only element nodes are passed to the
       * startElement function.
       * The element node passed to startElement for filtering will include all of the attributes, but none
       * of the children nodes. The DOMElement may not yet be in place in the document being
       * constructed (it may not have a parent node.)
       * A startElement filter function may access or change the attributes for the DOMElement.
       * Changing namespace declarations will have no effect on namespace resolution by the parser.
       *
       * @param node The newly encountered element. At the time this method is called, the element is incomplete -
       *             it will have its attributes, but no children.
       * @return One of the FilterAction enum
       */
    virtual short startElement(DOMElement* node) = 0;

    /**
     * Tells the DOMLSParser what types of nodes to show to the method DOMLSParserFilter::acceptNode.
     * If a node is not shown to the filter using this attribute, it is automatically included in the DOM document being built.
     * See DOMNodeFilter for definition of the constants. The constants SHOW_ATTRIBUTE, SHOW_DOCUMENT,
     * SHOW_DOCUMENT_TYPE, SHOW_NOTATION, SHOW_ENTITY, and SHOW_DOCUMENT_FRAGMENT are meaningless here.
     * Those nodes will never be passed to DOMLSParserFilter::acceptNode.
     *
     * @return The constants of what types of nodes to show.
     * @since DOM Level 3
     */
    virtual unsigned long getWhatToShow() const = 0;

    //@}

private:

};

XERCES_CPP_NAMESPACE_END

#endif
<|endoftext|>


<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * 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/.
 */

#include "stringhelper.h"
#include <QFile>
#include <QTextStream>
#include <QStringRef>
#include <QVector>
#include <QByteArray>
#include <QCryptographicHash>
#include <QString>
#include <QtGlobal>
#include <vector>
#include <utility>
#include <algorithm>
#include <cmath>
#include "../Common/defines.h"
#include "../Helpers/indiceshelper.h"

#if defined(Q_OS_WIN)
#define NOMINMAX
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined(Q_OS_MAC)
 #include <arpa/inet.h>
#elif defined(Q_OS_LINUX)
#include <arpa/inet.h>
#endif

#define SYNONYMS_DISTANCE 3

namespace Helpers {
    void foreachPart(const QString &text,
                     const std::function<bool (const QChar &symbol)> &isSeparatorPred,
                     const std::function<bool (const QString &word)> &pred,
                     const std::function<void (int start, int length, const QString &word)> &action)
    {
        int i = 0;
        const int size = text.size();
        int lastStart = -1;

        while (i < size) {
            QChar c = text[i];
            if (isSeparatorPred(c)) {
                if (lastStart != -1) {
                    int wordLength = i - lastStart;
                    QString word = text.mid(lastStart, wordLength);

                    if (pred(word)) {
                        action(lastStart, wordLength, word);
                    }

                    lastStart = -1;
                }
            } else {
                if (lastStart == -1) {
                    lastStart = i;
                }
            }

            i++;
        }

        if (lastStart != -1) {
            int wordLength = size - lastStart;
            QString word = text.mid(lastStart, wordLength);

            if (pred(word)) {
                action(lastStart, wordLength, word);
            }
        }
    }

    void foreachWord(const QString &text,
            const std::function<bool (const QString &word)> &pred,
            const std::function<void (int start, int length, const QString &word)> &action)
    {
        foreachPart(text,
                    [](const QChar &c) { return c.isSpace() || isPunctuation(c); },
        pred, action);
    }

    bool isLeftWordBound(const QString &text, int index, bool skipWordBounds=false) {
        if (index == 0) { return true; }

        QChar curr = text[index];
        QChar prev = text[index - 1];

        const bool currIsSeparator = isPunctuation(curr) || curr.isSpace();
        const bool prevIsSeparator = isPunctuation(prev) || prev.isSpace();

        return (skipWordBounds || !currIsSeparator) && (prevIsSeparator);
    }

    bool isRightWordBound(const QString &text, int lastIndex, int index, bool skipWordBounds=false) {
        if (index == lastIndex) { return true; }

        QChar curr = text[index];
        QChar next = text[index + 1];

        const bool currIsSeparator = isPunctuation(curr) || curr.isSpace();
        const bool nextIsSeparator = isPunctuation(next) || next.isSpace();

        return (skipWordBounds || !currIsSeparator) && (nextIsSeparator);
    }

    bool isAWholeWord(const QString &text, int start, int length, bool onlyCheckBounds=false) {
        if (text.isEmpty()) { return false; }

        if (!isLeftWordBound(text, start, onlyCheckBounds)) { return false; }
        const int lastIndex = text.size() - 1;
        if (!isRightWordBound(text, lastIndex, start + length - 1, onlyCheckBounds)) { return false; }

        return true;
    }

    QString replaceWholeWords(const QString &text, const QString &replaceWhat,
                              const QString &replaceTo, Qt::CaseSensitivity caseSensitivity) {
        int pos = 0;
        const int size = replaceWhat.size();
        std::vector<std::pair<int, int> > hits;
        hits.reserve(std::max(text.length() / replaceWhat.length(), 10));

        while (pos != -1) {
            pos = text.indexOf(replaceWhat, pos, caseSensitivity);
            if (pos >= 0) {
                if (isAWholeWord(text, pos, size, true)) {
                    hits.emplace_back(std::make_pair(pos, size));
                }

                pos += size;
            }
        }

        if (hits.empty()) { return text; }

        QString result;
        result.reserve(text.length());

        int lastStart = 0;
        for (auto &hit: hits) {
            if (hit.first > lastStart) {
                result.append(text.mid(lastStart, hit.first - lastStart));
            }

            result.append(replaceTo);
            lastStart = hit.first + hit.second;
        }

        if (lastStart < text.length() - 1) {
            result.append(text.mid(lastStart));
        }

        return result;
    }

    bool containsWholeWords(const QString &haystack, const QString &needle, Qt::CaseSensitivity caseSensitivity) {
        bool anyHit = false;

        int pos = 0;
        const int size = needle.size();

        while (pos != -1) {
            pos = haystack.indexOf(needle, pos, caseSensitivity);
            if (pos >= 0) {
                if (isAWholeWord(haystack, pos, size, true)) {
                    anyHit = true;
                    break;
                }

                pos += size;
            }
        }

        return anyHit;
    }

#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
    QString getLastNLines(const QString &text, int N) {
        QString result;

        QVector<QStringRef> items = text.splitRef(QRegExp("[\r\n]"), QString::SkipEmptyParts);

        const int length = items.length();

        if (length > 0) {
            int startIndex = length - N;
            if (startIndex < 0) {
                startIndex = 0;
            }

            int pos = items[startIndex].position();
            result = text.right(text.length() - pos);
        } else {
            result = text;
        }

        return result;
    }

#else
    QString getLastNLines(const QString &text, int N) {
        QString result;
        QStringList lastNLines;

        QStringList items = text.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);

        int length = items.length();

        if (length > 0) {
            int startIndex = length - N;
            if (startIndex < 0) {
                startIndex = 0;
            }

            for (int pos = startIndex; pos < length; pos++) {
                lastNLines.append(items[pos]);
            }

            result = lastNLines.join("\n");
        } else {
            result = text;
        }

        return result;
    }

#endif

    void splitText(const QString &text, QStringList &parts) {
        foreachWord(text,
                    [](const QString&) { return true; },
        [&parts](int, int, const QString &word) { parts.append(word); });
    }

    void splitKeywords(const QString &text, const QVector<QChar> &separators, QStringList &parts) {
        foreachPart(text,
                    [&separators](const QChar &c) { return separators.contains(c); },
        [](const QString&) { return true; },
        [&parts](int, int, const QString &word) { parts.append(word); });
    }

    std::string string_format(const std::string fmt, ...) {
        int size = ((int)fmt.size()) * 2 + 50;   // Use a rubric appropriate for your code
        std::string str;
        va_list ap;
        while (1) {     // Maximum two passes on a POSIX system...
            str.resize(size);
            va_start(ap, fmt);
            int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
            va_end(ap);
            if (n > -1 && n < size) {  // Everything worked
                str.resize(n);
                return str;
            }
            if (n > -1)  // Needed size returned
                size = n + 1;   // For null char
            else
                size *= 2;      // Guess at a larger size (OS specific)
        }

        return str;
    }

    unsigned int levensteinDistance(const QString &a, const QString &b) {
        const unsigned int lengthA = a.size(), lengthB = b.size();
        std::vector<unsigned int> costs(lengthB + 1), prevCosts(lengthB + 1);
        const unsigned int prevCostsSize = (unsigned int)prevCosts.size();

        for (unsigned int i = 0; i < prevCostsSize; i++) {
            prevCosts[i] = i;
        }

        for (unsigned int i = 0; i < lengthA; i++) {
            costs[0] = i + 1;

            for (unsigned int j = 0; j < lengthB; j++) {
                costs[j + 1] = std::min(
                    std::min(prevCosts[1 + j] + 1, costs[j] + 1),
                    prevCosts[j] + (a[i] == b[j] ? 0 : 1));
            }

            costs.swap(prevCosts);
        }

        unsigned int result = prevCosts[lengthB];
        return result;
    }

    int levensteinPercentage(const QString &s1, const QString &s2) {
        int maxLength = std::max(s1.length(), s2.length());

        unsigned int distance = levensteinDistance(s1.toLower(), s2.toLower());
        int reverseDistance = maxLength - (int)distance;

        if (reverseDistance == 0) { return 0; }

        int percent = (reverseDistance * 100) / maxLength;
        return percent;
    }

    bool is7BitAscii(const QByteArray &s) {
        bool anyFault = false;
        const int size = s.size();

        for (int i = 0; i < size; i++) {
            int c = s[i];
            if (c < 0 || c >= 128) {
                anyFault = true;
                break;
            }
        }

        return !anyFault;
    }

    bool isPunctuation(const QChar &c) {
        return c.isPunct() && c != QChar('/');
    }

    void extendSegmentToWordBoundaries(const QString &text, std::pair<int, int> &segment) {
        int left = segment.first;
        while (!isLeftWordBound(text, left)) { left--; }

        int right = segment.second;
        const int lastIndex = text.size() - 1;
        while (!isRightWordBound(text, lastIndex, right)) { right++; }

        segment.first = left;
        segment.second = right;
    }

    std::pair<int, int> getSegmentFromHit(const QString &text, int hit, int radius) {
        int left = hit;
        while (!isLeftWordBound(text, left)) { left--; }

        int right = hit;
        const int lastIndex = text.size() - 1;
        while (!isRightWordBound(text, lastIndex, right)) { right++; }

        int first = std::max(0, left - radius);
        int second = std::min(lastIndex, right + radius);
        return std::make_pair(first, second);
    }

    QString getUnitedHitsString(const QString &text, const std::vector<int> &hits, int radius) {
        std::vector<std::pair<int, int> > segments;
        segments.resize(hits.size());

        // create segment from each hit
        std::transform(hits.begin(), hits.end(), segments.begin(),
                       [&text, radius](int hit) {
            return getSegmentFromHit(text, hit, radius);
        });

        for (auto &item: segments) {
            extendSegmentToWordBoundaries(text, item);
        }

        auto unitedSegments = Helpers::unionRanges(segments);

        QStringList entries;
        entries.reserve((int)unitedSegments.size());

        for (auto &element: unitedSegments) {
            entries.append(text.mid(element.first, element.second - element.first + 1));
        }

        QString result = entries.join(" ... ");
        return result;
    }

    quint32 switcherHash(const QString &text) {
        QCryptographicHash hash(QCryptographicHash::Sha256);
        hash.addData(text.toUtf8());
        QByteArray result = hash.result();

        char *data = result.data();
        quint32 prefix = ntohl(*((quint32 *)data));
        return prefix;
    }

    bool areSemanticDuplicates(const QString &s1, const QString &s2) {
        if (QString::compare(s1, s2, Qt::CaseInsensitive) == 0) { return true; }

        const int length1 = s1.length();
        const int length2 = s2.length();

        const int diff = abs(length1 - length2);
        if (diff > SYNONYMS_DISTANCE) { return false; }

        const auto distance = Helpers::levensteinDistance(s1, s2);
        return distance <= SYNONYMS_DISTANCE;
    }
}
<commit_msg>Fixes for tests<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * 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/.
 */

#include "stringhelper.h"
#include <QFile>
#include <QTextStream>
#include <QStringRef>
#include <QVector>
#include <QByteArray>
#include <QCryptographicHash>
#include <QString>
#include <QtGlobal>
#include <vector>
#include <utility>
#include <algorithm>
#include <cmath>
#include "../Common/defines.h"
#include "../Helpers/indiceshelper.h"

#if defined(Q_OS_WIN)
#define NOMINMAX
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined(Q_OS_MAC)
 #include <arpa/inet.h>
#elif defined(Q_OS_LINUX)
#include <arpa/inet.h>
#endif

#define SYNONYMS_DISTANCE 3

namespace Helpers {
    void foreachPart(const QString &text,
                     const std::function<bool (const QChar &symbol)> &isSeparatorPred,
                     const std::function<bool (const QString &word)> &pred,
                     const std::function<void (int start, int length, const QString &word)> &action)
    {
        int i = 0;
        const int size = text.size();
        int lastStart = -1;

        while (i < size) {
            QChar c = text[i];
            if (isSeparatorPred(c)) {
                if (lastStart != -1) {
                    int wordLength = i - lastStart;
                    QString word = text.mid(lastStart, wordLength);

                    if (pred(word)) {
                        action(lastStart, wordLength, word);
                    }

                    lastStart = -1;
                }
            } else {
                if (lastStart == -1) {
                    lastStart = i;
                }
            }

            i++;
        }

        if (lastStart != -1) {
            int wordLength = size - lastStart;
            QString word = text.mid(lastStart, wordLength);

            if (pred(word)) {
                action(lastStart, wordLength, word);
            }
        }
    }

    void foreachWord(const QString &text,
            const std::function<bool (const QString &word)> &pred,
            const std::function<void (int start, int length, const QString &word)> &action)
    {
        foreachPart(text,
                    [](const QChar &c) { return c.isSpace() || isPunctuation(c); },
        pred, action);
    }

    bool isLeftWordBound(const QString &text, int index, bool skipWordBounds=false) {
        if (index == 0) { return true; }

        QChar curr = text[index];
        QChar prev = text[index - 1];

        const bool currIsSeparator = isPunctuation(curr) || curr.isSpace();
        const bool prevIsSeparator = isPunctuation(prev) || prev.isSpace();

        return (skipWordBounds || !currIsSeparator) && (prevIsSeparator);
    }

    bool isRightWordBound(const QString &text, int lastIndex, int index, bool skipWordBounds=false) {
        if (index == lastIndex) { return true; }

        QChar curr = text[index];
        QChar next = text[index + 1];

        const bool currIsSeparator = isPunctuation(curr) || curr.isSpace();
        const bool nextIsSeparator = isPunctuation(next) || next.isSpace();

        return (skipWordBounds || !currIsSeparator) && (nextIsSeparator);
    }

    bool isAWholeWord(const QString &text, int start, int length, bool onlyCheckBounds=false) {
        if (text.isEmpty()) { return false; }

        if (!isLeftWordBound(text, start, onlyCheckBounds)) { return false; }
        const int lastIndex = text.size() - 1;
        if (!isRightWordBound(text, lastIndex, start + length - 1, onlyCheckBounds)) { return false; }

        return true;
    }

    QString replaceWholeWords(const QString &text, const QString &replaceWhat,
                              const QString &replaceTo, Qt::CaseSensitivity caseSensitivity) {
        int pos = 0;
        const int size = replaceWhat.size();
        std::vector<std::pair<int, int> > hits;
        hits.reserve(std::max(text.length() / replaceWhat.length(), 10));

        while (pos != -1) {
            pos = text.indexOf(replaceWhat, pos, caseSensitivity);
            if (pos >= 0) {
                if (isAWholeWord(text, pos, size, true)) {
                    hits.emplace_back(std::make_pair(pos, size));
                }

                pos += size;
            }
        }

        if (hits.empty()) { return text; }

        QString result;
        result.reserve(text.length());

        int lastStart = 0;
        for (auto &hit: hits) {
            if (hit.first > lastStart) {
                result.append(text.mid(lastStart, hit.first - lastStart));
            }

            result.append(replaceTo);
            lastStart = hit.first + hit.second;
        }

        if (lastStart < text.length() - 1) {
            result.append(text.mid(lastStart));
        }

        return result;
    }

    bool containsWholeWords(const QString &haystack, const QString &needle, Qt::CaseSensitivity caseSensitivity) {
        bool anyHit = false;

        int pos = 0;
        const int size = needle.size();

        while (pos != -1) {
            pos = haystack.indexOf(needle, pos, caseSensitivity);
            if (pos >= 0) {
                if (isAWholeWord(haystack, pos, size, true)) {
                    anyHit = true;
                    break;
                }

                pos += size;
            }
        }

        return anyHit;
    }

#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
    QString getLastNLines(const QString &text, int N) {
        QString result;

        QVector<QStringRef> items = text.splitRef(QRegExp("[\r\n]"), QString::SkipEmptyParts);

        const int length = items.length();

        if (length > 0) {
            int startIndex = length - N;
            if (startIndex < 0) {
                startIndex = 0;
            }

            int pos = items[startIndex].position();
            result = text.right(text.length() - pos);
        } else {
            result = text;
        }

        return result;
    }

#else
    QString getLastNLines(const QString &text, int N) {
        QString result;
        QStringList lastNLines;

        QStringList items = text.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);

        int length = items.length();

        if (length > 0) {
            int startIndex = length - N;
            if (startIndex < 0) {
                startIndex = 0;
            }

            for (int pos = startIndex; pos < length; pos++) {
                lastNLines.append(items[pos]);
            }

            result = lastNLines.join("\n");
        } else {
            result = text;
        }

        return result;
    }

#endif

    void splitText(const QString &text, QStringList &parts) {
        foreachWord(text,
                    [](const QString&) { return true; },
        [&parts](int, int, const QString &word) { parts.append(word); });
    }

    void splitKeywords(const QString &text, const QVector<QChar> &separators, QStringList &parts) {
        foreachPart(text,
                    [&separators](const QChar &c) { return separators.contains(c); },
        [](const QString&) { return true; },
        [&parts](int, int, const QString &word) { parts.append(word); });
    }

    std::string string_format(const std::string fmt, ...) {
        int size = ((int)fmt.size()) * 2 + 50;   // Use a rubric appropriate for your code
        std::string str;
        va_list ap;
        while (1) {     // Maximum two passes on a POSIX system...
            str.resize(size);
            va_start(ap, fmt);
            int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
            va_end(ap);
            if (n > -1 && n < size) {  // Everything worked
                str.resize(n);
                return str;
            }
            if (n > -1)  // Needed size returned
                size = n + 1;   // For null char
            else
                size *= 2;      // Guess at a larger size (OS specific)
        }

        return str;
    }

    unsigned int levensteinDistance(const QString &a, const QString &b) {
        const unsigned int lengthA = a.size(), lengthB = b.size();
        std::vector<unsigned int> costs(lengthB + 1), prevCosts(lengthB + 1);
        const unsigned int prevCostsSize = (unsigned int)prevCosts.size();

        for (unsigned int i = 0; i < prevCostsSize; i++) {
            prevCosts[i] = i;
        }

        for (unsigned int i = 0; i < lengthA; i++) {
            costs[0] = i + 1;

            for (unsigned int j = 0; j < lengthB; j++) {
                costs[j + 1] = std::min(
                    std::min(prevCosts[1 + j] + 1, costs[j] + 1),
                    prevCosts[j] + (a[i] == b[j] ? 0 : 1));
            }

            costs.swap(prevCosts);
        }

        unsigned int result = prevCosts[lengthB];
        return result;
    }

    int levensteinPercentage(const QString &s1, const QString &s2) {
        int maxLength = std::max(s1.length(), s2.length());

        unsigned int distance = levensteinDistance(s1.toLower(), s2.toLower());
        int reverseDistance = maxLength - (int)distance;

        if (reverseDistance == 0) { return 0; }

        int percent = (reverseDistance * 100) / maxLength;
        return percent;
    }

    bool is7BitAscii(const QByteArray &s) {
        bool anyFault = false;
        const int size = s.size();

        for (int i = 0; i < size; i++) {
            int c = s[i];
            if (c < 0 || c >= 128) {
                anyFault = true;
                break;
            }
        }

        return !anyFault;
    }

    bool isPunctuation(const QChar &c) {
        return c.isPunct() && c != QChar('/');
    }

    void extendSegmentToWordBoundaries(const QString &text, std::pair<int, int> &segment) {
        int left = segment.first;
        while (!isLeftWordBound(text, left)) { left--; }

        int right = segment.second;
        const int lastIndex = text.size() - 1;
        while (!isRightWordBound(text, lastIndex, right)) { right++; }

        segment.first = left;
        segment.second = right;
    }

    std::pair<int, int> getSegmentFromHit(const QString &text, int hit, int radius) {
        int left = hit;
        while (!isLeftWordBound(text, left)) { left--; }

        int right = hit;
        const int lastIndex = text.size() - 1;
        while (!isRightWordBound(text, lastIndex, right)) { right++; }

        int first = std::max(0, left - radius);
        int second = std::min(lastIndex, right + radius);
        return std::make_pair(first, second);
    }

    QString getUnitedHitsString(const QString &text, const std::vector<int> &hits, int radius) {
        std::vector<std::pair<int, int> > segments;
        segments.resize(hits.size());

        // create segment from each hit
        std::transform(hits.begin(), hits.end(), segments.begin(),
                       [&text, radius](int hit) {
            return getSegmentFromHit(text, hit, radius);
        });

        for (auto &item: segments) {
            extendSegmentToWordBoundaries(text, item);
        }

        auto unitedSegments = Helpers::unionRanges(segments);

        QStringList entries;
        entries.reserve((int)unitedSegments.size());

        for (auto &element: unitedSegments) {
            entries.append(text.mid(element.first, element.second - element.first + 1));
        }

        QString result = entries.join(" ... ");
        return result;
    }

    quint32 switcherHash(const QString &text) {
        QCryptographicHash hash(QCryptographicHash::Sha256);
        hash.addData(text.toUtf8());
        QByteArray result = hash.result();

        char *data = result.data();
        quint32 prefix = ntohl(*((quint32 *)data));
        return prefix;
    }

    bool areSemanticDuplicates(const QString &s1, const QString &s2) {
        if (QString::compare(s1, s2, Qt::CaseInsensitive) == 0) { return true; }

        const int length1 = s1.length();
        const int length2 = s2.length();

        const int diff = abs(length1 - length2);
        if (diff > SYNONYMS_DISTANCE) { return false; }

        const auto distance = Helpers::levensteinDistance(s1.toLower(), s2.toLower());
        return distance <= SYNONYMS_DISTANCE;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2012 Rhys Ulerich
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "ar.hpp"

#include <algorithm>
#include <cstdlib>
#include <iterator>
#include <iostream>
#include <limits>
#include <list>
#include <vector>

#include <octave/oct.h>

/** @file
 * A GNU Octave wrapper estimating the best AR(p) model given signal input.
 * Compare \ref arsel.cpp.
 */

// Compile-time defaults in the code also appearing in the help message
#define DEFAULT_SUBMEAN  true
#define DEFAULT_MAXORDER 512
#define STRINGIFY(x) STRINGIFY_HELPER(x)
#define STRINGIFY_HELPER(x) #x

DEFUN_DLD(
    arsel, args, nargout,
    "\t[A, mu, sigma2eps, eff_sigma2x, Neff, T0] = arsel (d, submean, maxorder)\n"
    "\tAutomatically fit an autoregressive model to an input signal.\n"
    "\t\n"
    "\tUse ar::burg_method followed by ar::best_model<CIC<Burg<MeanHandling > >\n"
    "\tto obtain the most likely autoregressive process for input signal d.\n"
    "\tThe sample mean of d will be subtracted whenever submean is true.\n"
    "\tModel orders zero through min(size(d), maxorder) will be considered.\n"
    "\t\n"
    "\tThe filter()-ready process parameters are returned in A, the sample mean\n"
    "\tin mu, and the innovation variance \\sigma^2_\\epsilon in sigma2eps.\n"
    "\tGiven the observed autocorrelation structure, a decorrelation time T0 is\n"
    "\tcomputed and used to estimate the effective signal variance eff_sigma2x.\n"
    "\tThe number of effectively independent samples is returned in Neff.\n"
    "\t\n"
    "\tOne may simulate N samples from the fitted process by calling:\n"
    "\t\n"
    "\t\tx = mu + filter([1], A, sqrt(sigma2eps)*randn(N,1));\n"
    "\t\n"
    "\tWhen not supplied, submean defaults to " STRINGIFY(DEFAULT_SUBMEAN) ".\n"
    "\tWhen not supplied, maxorder defaults to " STRINGIFY(DEFAULT_MAXORDER) ".\n"
    "\tWhen no output arguments are requested, all details are displayed.\n"
)
{
    std::size_t maxorder = DEFAULT_MAXORDER;
    bool        submean  = DEFAULT_SUBMEAN;
    RowVector   data;
    switch (args.length())
    {
        case 3:
            maxorder = args(2).ulong_value();
        case 2:
            submean = args(1).bool_value();
        case 1:
            data = args(0).row_vector_value();
            break;
        default:
            error("Invalid call to arsel.  Correct usage is: ");
        case 0:
            print_usage();
            return octave_value();
    }

    // How much data will we be processing?
    const size_t N = data.dims().numel();
    if (!N) {
        error("arsel: input signal d must have nonzero length");
        return octave_value();
    }

    // Use burg_method to estimate a hierarchy of AR models from input data
    double mu;
    std::vector<double> params, sigma2e, gain, autocor;
    params .reserve(maxorder*(maxorder + 1)/2);
    sigma2e.reserve(maxorder + 1);
    gain   .reserve(maxorder + 1);
    autocor.reserve(maxorder + 1);
    ar::burg_method(data.fortran_vec(), data.fortran_vec() + N,
                    mu, maxorder,
                    std::back_inserter(params),
                    std::back_inserter(sigma2e),
                    std::back_inserter(gain),
                    std::back_inserter(autocor),
                    submean, /* output hierarchy? */ true);

    // Keep only best model according to CIC accounting for subtract_mean.
    if (submean) {
        ar::best_model<ar::CIC<ar::Burg<ar::mean_subtracted> > >(
                N, params, sigma2e, gain, autocor);
    } else {
        ar::best_model<ar::CIC<ar::Burg<ar::mean_retained> > >(
                N, params, sigma2e, gain, autocor);
    }

    // Compute decorrelation time from the estimated autocorrelation model
    double T0 = std::numeric_limits<double>::quiet_NaN();
    if (nargout == 0 || nargout > 2) {
        ar::predictor<double> p = ar::autocorrelation(
                params.begin(), params.end(), gain[0], autocor.begin());
        T0 = ar::decorrelation_time(N, p, /* abs(rho) */ true);
    }

    // Prepare autoregressive process parameters for Octave's filter function
    RowVector A(params.size() + 1, /* leading one */ 1);
    std::copy(params.begin(), params.end(), A.fortran_vec() + 1);

    // Prepare output: [A, mu, sigma2eps, eff_sigma2x, Neff, T0]
    octave_value_list retval;
    std::list<std::string> names;
    switch (nargout == 0 ? std::numeric_limits<int>::max() : nargout)
    {
        default:
            if (nargout) warning("arsel: too many output values requested");
        case 6:
            retval.prepend(T0);
            names.push_front("T0");
        case 5:
            retval.prepend(N / T0);
            names.push_front("Neff");
        case 4:
            retval.prepend((N*gain[0]*sigma2e[0]) / (N - T0));
            names.push_front("eff_sigma2x");
        case 3:
            retval.prepend(sigma2e[0]);
            names.push_front("sigma2eps");
        case 2:
            retval.prepend(mu);
            names.push_front("mu");
        case 1:
            retval.prepend(A);
            names.push_front("A");
            break;
        case 0:
            panic_impossible();
    }
    retval.stash_name_tags(names);

    // Provide no results whenever errors are detected
    if (error_state) retval.resize(0);

    // FIXME Use Octave's default stream (?) instead of std::cout
    // Display results to user when no output was requested
    if (!nargout) {
        int i = 0;
        while (names.size()) {
            retval(i++).print_with_name(std::cout, names.front());
            names.pop_front();
        }
        retval.resize(0);
    }

    return retval;
}
<commit_msg>Return struct on 0 nargout<commit_after>// Copyright (C) 2012 Rhys Ulerich
//
// 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 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "ar.hpp"

#include <algorithm>
#include <cstdlib>
#include <iterator>
#include <limits>
#include <list>
#include <vector>

#include <octave/oct.h>
#include <octave/oct-map.h>

/** @file
 * A GNU Octave wrapper estimating the best AR(p) model given signal input.
 * Compare \ref arsel.cpp.
 */

// Compile-time defaults in the code also appearing in the help message
#define DEFAULT_SUBMEAN  true
#define DEFAULT_MAXORDER 512
#define STRINGIFY(x) STRINGIFY_HELPER(x)
#define STRINGIFY_HELPER(x) #x

DEFUN_DLD(
    arsel, args, nargout,
    "\t[A, mu, sigma2eps, eff_sigma2x, Neff, T0] = arsel (d, submean, maxorder)\n"
    "\tAutomatically fit an autoregressive model to an input signal.\n"
    "\t\n"
    "\tUse ar::burg_method followed by ar::best_model<CIC<Burg<MeanHandling > >\n"
    "\tto obtain the most likely autoregressive process for input signal d.\n"
    "\tThe sample mean of d will be subtracted whenever submean is true.\n"
    "\tModel orders zero through min(size(d), maxorder) will be considered.\n"
    "\t\n"
    "\tThe filter()-ready process parameters are returned in A, the sample mean\n"
    "\tin mu, and the innovation variance \\sigma^2_\\epsilon in sigma2eps.\n"
    "\tGiven the observed autocorrelation structure, a decorrelation time T0 is\n"
    "\tcomputed and used to estimate the effective signal variance eff_sigma2x.\n"
    "\tThe number of effectively independent samples is returned in Neff.\n"
    "\t\n"
    "\tOne may simulate N samples from the fitted process by calling:\n"
    "\t\n"
    "\t\tx = mu + filter([1], A, sqrt(sigma2eps)*randn(N,1));\n"
    "\t\n"
    "\tWhen not supplied, submean defaults to " STRINGIFY(DEFAULT_SUBMEAN) ".\n"
    "\tWhen not supplied, maxorder defaults to " STRINGIFY(DEFAULT_MAXORDER) ".\n"
    "\tWhen no outputs are requested, a struct with all outputs is returned.\n"
)
{
    std::size_t maxorder = DEFAULT_MAXORDER;
    bool        submean  = DEFAULT_SUBMEAN;
    RowVector   data;
    switch (args.length())
    {
        case 3:
            maxorder = args(2).ulong_value();
        case 2:
            submean = args(1).bool_value();
        case 1:
            data = args(0).row_vector_value();
            break;
        default:
            error("Invalid call to arsel.  Correct usage is: ");
        case 0:
            print_usage();
            return octave_value();
    }

    // How much data will we be processing?
    const size_t N = data.dims().numel();
    if (!N)
    {
        error("arsel: input signal d must have nonzero length");
        return octave_value();
    }

    // Use burg_method to estimate a hierarchy of AR models from input data
    double mu;
    std::vector<double> params, sigma2e, gain, autocor;
    params .reserve(maxorder*(maxorder + 1)/2);
    sigma2e.reserve(maxorder + 1);
    gain   .reserve(maxorder + 1);
    autocor.reserve(maxorder + 1);
    ar::burg_method(data.fortran_vec(), data.fortran_vec() + N,
                    mu, maxorder,
                    std::back_inserter(params),
                    std::back_inserter(sigma2e),
                    std::back_inserter(gain),
                    std::back_inserter(autocor),
                    submean, /* output hierarchy? */ true);

    // Keep only best model according to CIC accounting for subtract_mean.
    if (submean)
    {
        ar::best_model<ar::CIC<ar::Burg<ar::mean_subtracted> > >(
                N, params, sigma2e, gain, autocor);
    }
    else
    {
        ar::best_model<ar::CIC<ar::Burg<ar::mean_retained> > >(
                N, params, sigma2e, gain, autocor);
    }

    // Compute decorrelation time from the estimated autocorrelation model
    double T0 = std::numeric_limits<double>::quiet_NaN();
    if (nargout == 0 || nargout > 2)
    {
        ar::predictor<double> p = ar::autocorrelation(
                params.begin(), params.end(), gain[0], autocor.begin());
        T0 = ar::decorrelation_time(N, p, /* abs(rho) */ true);
    }

    // Prepare autoregressive process parameters for Octave's filter function
    RowVector A(params.size() + 1, /* leading one */ 1);
    std::copy(params.begin(), params.end(), A.fortran_vec() + 1);

    // Prepare output: [A, mu, sigma2eps, eff_sigma2x, Neff, T0]
    octave_value_list result;
    std::list<std::string> names;
    switch (nargout == 0 ? std::numeric_limits<int>::max() : nargout)
    {
        default:
            if (nargout) warning("arsel: too many output values requested");
        case 6:
            names.push_front("T0");
            result.prepend(T0);
        case 5:
            names.push_front("Neff");
            result.prepend(N / T0);
        case 4:
            names.push_front("eff_sigma2x");
            result.prepend((N*gain[0]*sigma2e[0]) / (N - T0));
        case 3:
            names.push_front("sigma2eps");
            result.prepend(sigma2e[0]);
        case 2:
            names.push_front("mu");
            result.prepend(mu);
        case 1:
            names.push_front("A");
            result.prepend(A);
            break;
        case 0:
            panic_impossible();
    }

    // Either return requested results in assignment-friendly fashion
    // or, when nothing was requested, return a struct to likely display.
    if (nargout)
    {
        result.stash_name_tags(names);
    }
    else // nargout == 0
    {
        Octave_map m;
        int i = 0;
        while (names.size()) {
            m.assign(names.front(), result(i++));
            names.pop_front();
        }
        result.resize(1);
        result(0) = m;
    }

    // Provide no results whenever an error was detected
    if (error_state)
    {
        warning("arsel: error detected; no results returned");
        result.resize(0);
    }

    return result;
}
<|endoftext|>


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

#pragma once

#include <thrust/detail/config.h>
#include <thrust/system/cuda/detail/trivial_copy.h>
#include <thrust/system/cuda/detail/guarded_cuda_runtime_api.h>
#include <thrust/system_error.h>
#include <thrust/system/cuda/error.h>
#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/cpp/detail/execution_policy.h>
#include <thrust/detail/raw_pointer_cast.h>
#include <thrust/functional.h>
#include <thrust/iterator/retag.h>

namespace thrust
{
namespace system
{
namespace cuda
{
namespace detail
{
namespace trivial_copy_detail
{

template<typename System1,
         typename System2>
  cudaMemcpyKind cuda_memcpy_kind(const thrust::cuda::execution_policy<System1> &,
                                  const thrust::cpp::execution_policy<System2> &)
{
  return cudaMemcpyDeviceToHost;
} // end cuda_memcpy_kind()

template<typename System1,
         typename System2>
  cudaMemcpyKind cuda_memcpy_kind(const thrust::cpp::execution_policy<System1> &,
                                  const thrust::cuda::execution_policy<System2> &)
{
  return cudaMemcpyHostToDevice;
} // end cuda_memcpy_kind()

} // end namespace trivial_copy_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename Size,
         typename RandomAccessIterator2>
__host__ __device__
void trivial_copy_n(execution_policy<DerivedPolicy> &exec,
                    RandomAccessIterator1 first,
                    Size n,
                    RandomAccessIterator2 result)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type T;

#ifndef __CUDA_ARCH__
  void *dst = thrust::raw_pointer_cast(&*result);
  const void *src = thrust::raw_pointer_cast(&*first);

  throw_on_error(cudaMemcpy(dst, src, n * sizeof(T), cudaMemcpyDeviceToDevice), "cudaMemcpy in trivial_copy_n");
#else
  // XXX transform is implemented with zip_iterator, which freaks out when the zipped iterators have unrelated system tags
  //     force both iterators' system tags to DerivedPolicy
  thrust::transform(exec,
                    thrust::reinterpret_tag<DerivedPolicy>(first), thrust::reinterpret_tag<DerivedPolicy>(first + n),
                    thrust::reinterpret_tag<DerivedPolicy>(result),
                    thrust::identity<T>());
#endif
}

template<typename System1,
         typename System2,
         typename RandomAccessIterator1,
         typename Size,
         typename RandomAccessIterator2>
void trivial_copy_n(cross_system<System1,System2> &systems,
                    RandomAccessIterator1 first,
                    Size n,
                    RandomAccessIterator2 result)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type T;

  void *dst = thrust::raw_pointer_cast(&*result);
  const void *src = thrust::raw_pointer_cast(&*first);

  cudaMemcpyKind kind = trivial_copy_detail::cuda_memcpy_kind(thrust::detail::derived_cast(systems.system1), thrust::detail::derived_cast(systems.system2));

  throw_on_error(cudaMemcpy(dst, src, n * sizeof(T), kind), "cudaMemcpy in trivial_copy_n");
}

} // end namespace detail
} // end namespace cuda
} // end namespace system
} // end namespace thrust

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

#pragma once

#include <thrust/detail/config.h>
#include <thrust/system/cuda/detail/trivial_copy.h>
#include <thrust/system/cuda/detail/guarded_cuda_runtime_api.h>
#include <thrust/system_error.h>
#include <thrust/system/cuda/error.h>
#include <thrust/system/cuda/detail/throw_on_error.h>
#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/cpp/detail/execution_policy.h>
#include <thrust/detail/raw_pointer_cast.h>
#include <thrust/functional.h>
#include <thrust/iterator/retag.h>

namespace thrust
{
namespace system
{
namespace cuda
{
namespace detail
{
namespace trivial_copy_detail
{

template<typename System1,
         typename System2>
  cudaMemcpyKind cuda_memcpy_kind(const thrust::cuda::execution_policy<System1> &,
                                  const thrust::cpp::execution_policy<System2> &)
{
  return cudaMemcpyDeviceToHost;
} // end cuda_memcpy_kind()

template<typename System1,
         typename System2>
  cudaMemcpyKind cuda_memcpy_kind(const thrust::cpp::execution_policy<System1> &,
                                  const thrust::cuda::execution_policy<System2> &)
{
  return cudaMemcpyHostToDevice;
} // end cuda_memcpy_kind()

} // end namespace trivial_copy_detail

template<typename DerivedPolicy,
         typename RandomAccessIterator1,
         typename Size,
         typename RandomAccessIterator2>
__host__ __device__
void trivial_copy_n(execution_policy<DerivedPolicy> &exec,
                    RandomAccessIterator1 first,
                    Size n,
                    RandomAccessIterator2 result)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type T;

#ifndef __CUDA_ARCH__
  void *dst = thrust::raw_pointer_cast(&*result);
  const void *src = thrust::raw_pointer_cast(&*first);

  throw_on_error(cudaMemcpy(dst, src, n * sizeof(T), cudaMemcpyDeviceToDevice), "cudaMemcpy in trivial_copy_n");
#else
  // XXX transform is implemented with zip_iterator, which freaks out when the zipped iterators have unrelated system tags
  //     force both iterators' system tags to DerivedPolicy
  thrust::transform(exec,
                    thrust::reinterpret_tag<DerivedPolicy>(first), thrust::reinterpret_tag<DerivedPolicy>(first + n),
                    thrust::reinterpret_tag<DerivedPolicy>(result),
                    thrust::identity<T>());
#endif
}

template<typename System1,
         typename System2,
         typename RandomAccessIterator1,
         typename Size,
         typename RandomAccessIterator2>
void trivial_copy_n(cross_system<System1,System2> &systems,
                    RandomAccessIterator1 first,
                    Size n,
                    RandomAccessIterator2 result)
{
  typedef typename thrust::iterator_value<RandomAccessIterator1>::type T;

  void *dst = thrust::raw_pointer_cast(&*result);
  const void *src = thrust::raw_pointer_cast(&*first);

  cudaMemcpyKind kind = trivial_copy_detail::cuda_memcpy_kind(thrust::detail::derived_cast(systems.system1), thrust::detail::derived_cast(systems.system2));

  throw_on_error(cudaMemcpy(dst, src, n * sizeof(T), kind), "cudaMemcpy in trivial_copy_n");
}

} // end namespace detail
} // end namespace cuda
} // end namespace system
} // end namespace thrust

<|endoftext|>


<commit_before>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QScopedPointer>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/storage/connector.hh"
#include "com/centreon/broker/storage/factory.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::storage;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

/**
 *  Find a parameter in configuration.
 *
 *  @param[in] cfg Configuration object.
 *  @param[in] key Property to get.
 *
 *  @return Property value.
 */
static QString const& find_param(config::endpoint const& cfg,
                                 QString const& key) {
  QMap<QString, QString>::const_iterator it(cfg.params.find(key));
  if (cfg.params.end() == it)
    throw (exceptions::msg() << "storage: no '" << key
	   << "' defined for endpoint '" << cfg.name << "'");
  return (it.value());
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
factory::factory(factory const& f) : io::factory(f) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& f) {
  io::factory::operator=(f);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return Exact copy of this factory.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if a configuration match the storage layer.
 *
 *  @param[in] cfg       Endpoint configuration.
 *  @param[in] is_input  true if endpoint should act as input.
 *  @param[in] is_output true if endpoint should act as output.
 *
 *  @return true if the configuration matches the storage layer.
 */
bool factory::has_endpoint(config::endpoint const& cfg,
                           bool is_input,
                           bool is_output) const {
  (void)is_input;
  (void)is_output;
  return (cfg.type == "storage");
}

/**
 *  Build a storage endpoint from a configuration.
 *
 *  @param[in]  cfg         Endpoint configuration.
 *  @param[in]  is_input    true if endpoint should act as input.
 *  @param[in]  is_output   true if endpoint should act as output.
 *  @param[out] is_acceptor Will be set to false.
 *
 *  @return Endpoint matching the given configuration.
 */
io::endpoint* factory::new_endpoint(config::endpoint const& cfg,
                                    bool is_input,
                                    bool is_output,
                                    bool& is_acceptor) const {
  (void)is_output;

  // Check that endpoint should not be an input.
  if (is_input)
    throw (exceptions::msg()
             << "storage: cannot create an input endpoint");

  // Find lengths.
  unsigned int interval_length(find_param(cfg, "interval").toUInt());
  unsigned int rrd_length(find_param(cfg, "length").toUInt());

  // Find storage DB parameters.
  QString type(find_param(cfg, "db_type"));
  QString host(find_param(cfg, "db_host"));
  unsigned short port(find_param(cfg, "db_port").toUShort());
  QString user(find_param(cfg, "db_user"));
  QString password(find_param(cfg, "db_password"));
  QString name(find_param(cfg, "db_name"));

  // Connector.
  QScopedPointer<storage::connector> c(new storage::connector);
  c->connect_to(type,
    host,
    port,
    user,
    password,
    name,
    rrd_length,
    interval_length);
  is_acceptor = false;
  return (c.take());
}
<commit_msg>Fix configuration parsing in storage module.<commit_after>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QScopedPointer>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/storage/connector.hh"
#include "com/centreon/broker/storage/factory.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::storage;

/**************************************
*                                     *
*           Static Objects            *
*                                     *
**************************************/

/**
 *  Find a parameter in configuration.
 *
 *  @param[in] cfg Configuration object.
 *  @param[in] key Property to get.
 *
 *  @return Property value.
 */
static QString const& find_param(config::endpoint const& cfg,
                                 QString const& key) {
  QMap<QString, QString>::const_iterator it(cfg.params.find(key));
  if (cfg.params.end() == it)
    throw (exceptions::msg() << "storage: no '" << key
	   << "' defined for endpoint '" << cfg.name << "'");
  return (it.value());
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
factory::factory() {}

/**
 *  Copy constructor.
 *
 *  @param[in] f Object to copy.
 */
factory::factory(factory const& f) : io::factory(f) {}

/**
 *  Destructor.
 */
factory::~factory() {}

/**
 *  Assignment operator.
 *
 *  @param[in] f Object to copy.
 *
 *  @return This object.
 */
factory& factory::operator=(factory const& f) {
  io::factory::operator=(f);
  return (*this);
}

/**
 *  Clone this object.
 *
 *  @return Exact copy of this factory.
 */
io::factory* factory::clone() const {
  return (new factory(*this));
}

/**
 *  Check if a configuration match the storage layer.
 *
 *  @param[in] cfg       Endpoint configuration.
 *  @param[in] is_input  true if endpoint should act as input.
 *  @param[in] is_output true if endpoint should act as output.
 *
 *  @return true if the configuration matches the storage layer.
 */
bool factory::has_endpoint(config::endpoint const& cfg,
                           bool is_input,
                           bool is_output) const {
  (void)is_input;
  return (is_output && (cfg.type == "storage"));
}

/**
 *  Build a storage endpoint from a configuration.
 *
 *  @param[in]  cfg         Endpoint configuration.
 *  @param[in]  is_input    true if endpoint should act as input.
 *  @param[in]  is_output   true if endpoint should act as output.
 *  @param[out] is_acceptor Will be set to false.
 *
 *  @return Endpoint matching the given configuration.
 */
io::endpoint* factory::new_endpoint(config::endpoint const& cfg,
                                    bool is_input,
                                    bool is_output,
                                    bool& is_acceptor) const {
  (void)is_input;
  (void)is_output;

  // Find lengths.
  unsigned int interval_length(find_param(cfg, "interval").toUInt());
  unsigned int rrd_length(find_param(cfg, "length").toUInt());

  // Find storage DB parameters.
  QString type(find_param(cfg, "db_type"));
  QString host(find_param(cfg, "db_host"));
  unsigned short port(find_param(cfg, "db_port").toUShort());
  QString user(find_param(cfg, "db_user"));
  QString password(find_param(cfg, "db_password"));
  QString name(find_param(cfg, "db_name"));

  // Connector.
  QScopedPointer<storage::connector> c(new storage::connector);
  c->connect_to(type,
    host,
    port,
    user,
    password,
    name,
    rrd_length,
    interval_length);
  is_acceptor = false;
  return (c.take());
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2015 Matthijs Kooijman
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This the HAL to run LMIC on top of the Arduino environment.
 *******************************************************************************/

#include <Arduino.h>
#include <SPI.h>
#include "../lmic.h"
#include "hal.h"
#include <stdio.h>

// -----------------------------------------------------------------------------
// I/O

static void hal_io_init () {
    // NSS and DIO0 are required, DIO1 is required for LoRa, DIO2 for FSK
    ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
    ASSERT(lmic_pins.dio[0] != LMIC_UNUSED_PIN);
    ASSERT(lmic_pins.dio[1] != LMIC_UNUSED_PIN || lmic_pins.dio[2] != LMIC_UNUSED_PIN);

    pinMode(lmic_pins.nss, OUTPUT);
    if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.rxtx, OUTPUT);
    if (lmic_pins.rst != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.rst, OUTPUT);

    pinMode(lmic_pins.dio[0], INPUT);
    if (lmic_pins.dio[1] != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.dio[1], INPUT);
    if (lmic_pins.dio[2] != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.dio[2], INPUT);
}

// val == 1  => tx 1
void hal_pin_rxtx (u1_t val) {
    if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
        digitalWrite(lmic_pins.rxtx, val);
}

// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
    if (lmic_pins.rst == LMIC_UNUSED_PIN)
        return;

    if(val == 0 || val == 1) { // drive pin
        pinMode(lmic_pins.rst, OUTPUT);
        digitalWrite(lmic_pins.rst, val);
    } else { // keep pin floating
        pinMode(lmic_pins.rst, INPUT);
    }
}

static bool dio_states[NUM_DIO] = {0};

static void hal_io_check() {
    uint8_t i;
    for (i = 0; i < NUM_DIO; ++i) {
        if (lmic_pins.dio[i] == LMIC_UNUSED_PIN)
            continue;

        if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
            dio_states[i] = !dio_states[i];
            if (dio_states[i])
                radio_irq_handler(i);
        }
    }
}

// -----------------------------------------------------------------------------
// SPI

static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);

static void hal_spi_init () {
    SPI.begin();
}

void hal_pin_nss (u1_t val) {
    if (!val)
        SPI.beginTransaction(settings);
    else
        SPI.endTransaction();

    //Serial.println(val?">>":"<<");
    digitalWrite(lmic_pins.nss, val);
}

// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
    u1_t res = SPI.transfer(out);
/*
    Serial.print(">");
    Serial.print(out, HEX);
    Serial.print("<");
    Serial.println(res, HEX);
    */
    return res;
}

// -----------------------------------------------------------------------------
// TIME

static void hal_time_init () {
    // Nothing to do
}

u4_t hal_ticks () {
    // Because micros() is scaled down in this function, micros() will
    // overflow before the tick timer should, causing the tick timer to
    // miss a significant part of its values if not corrected. To fix
    // this, the "overflow" serves as an overflow area for the micros()
    // counter. It consists of three parts:
    //  - The US_PER_OSTICK upper bits are effectively an extension for
    //    the micros() counter and are added to the result of this
    //    function.
    //  - The next bit overlaps with the most significant bit of
    //    micros(). This is used to detect micros() overflows.
    //  - The remaining bits are always zero.
    //
    // By comparing the overlapping bit with the corresponding bit in
    // the micros() return value, overflows can be detected and the
    // upper bits are incremented. This is done using some clever
    // bitwise operations, to remove the need for comparisons and a
    // jumps, which should result in efficient code. By avoiding shifts
    // other than by multiples of 8 as much as possible, this is also
    // efficient on AVR (which only has 1-bit shifts).
    static uint8_t overflow = 0;

    // Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
    // the others will be the lower bits of our return value.
    uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT;
    // Most significant byte of scaled
    uint8_t msb = scaled >> 24;
    // Mask pointing to the overlapping bit in msb and overflow.
    const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
    // Update overflow. If the overlapping bit is different
    // between overflow and msb, it is added to the stored value,
    // so the overlapping bit becomes equal again and, if it changed
    // from 1 to 0, the upper bits are incremented.
    overflow += (msb ^ overflow) & mask;

    // Return the scaled value with the upper bits of stored added. The
    // overlapping bit will be equal and the lower bits will be 0, so
    // bitwise or is a no-op for them.
    return scaled | ((uint32_t)overflow << 24);

    // 0 leads to correct, but overly complex code (it could just return
    // micros() unmodified), 8 leaves no room for the overlapping bit.
    static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
}

// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
    return (s4_t)(time - hal_ticks());
}

void hal_waitUntil (u4_t time) {
    s4_t delta = delta_time(time);
    // From delayMicroseconds docs: Currently, the largest value that
    // will produce an accurate delay is 16383.
    while (delta > (16000 / US_PER_OSTICK)) {
        delay(16);
        delta -= (16000 / US_PER_OSTICK);
    }
    if (delta > 0)
        delayMicroseconds(delta * US_PER_OSTICK);
}

// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
    // No need to schedule wakeup, since we're not sleeping
    return delta_time(time) <= 0;
}

static uint8_t irqlevel = 0;

void hal_disableIRQs () {
    noInterrupts();
    irqlevel++;
}

void hal_enableIRQs () {
    if(--irqlevel == 0) {
        interrupts();

        // Instead of using proper interrupts (which are a bit tricky
        // and/or not available on all pins on AVR), just poll the pin
        // values. Since os_runloop disables and re-enables interrupts,
        // putting this here makes sure we check at least once every
        // loop.
        //
        // As an additional bonus, this prevents the can of worms that
        // we would otherwise get for running SPI transfers inside ISRs
        hal_io_check();
    }
}

void hal_sleep () {
    // Not implemented
}

// -----------------------------------------------------------------------------

#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
    LMIC_PRINTF_TO.write(c) ;
    return 0 ;
}

void hal_printf_init() {
    // create a FILE structure to reference our UART output function
    static FILE uartout;
    memset(&uartout, 0, sizeof(uartout));

    // fill in the UART file descriptor with pointer to writer.
    fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);

    // The uart is the standard output device STDOUT.
    stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)

void hal_init () {
    // configure radio I/O and interrupt handler
    hal_io_init();
    // configure radio SPI
    hal_spi_init();
    // configure timer and interrupt handler
    hal_time_init();
#if defined(LMIC_PRINTF_TO)
    // printf support
    hal_printf_init();
#endif
}

void hal_failed (const char *file, u2_t line) {
#if defined(LMIC_FAILURE_TO)
    LMIC_FAILURE_TO.println("FAILURE ");
    LMIC_FAILURE_TO.print(file);
    LMIC_FAILURE_TO.print(':');
    LMIC_FAILURE_TO.println(line);
    LMIC_FAILURE_TO.flush();
#endif
    hal_disableIRQs();
    while(1);
}
<commit_msg>Make default SPI freq 1MHz<commit_after>/*******************************************************************************
 * Copyright (c) 2015 Matthijs Kooijman
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This the HAL to run LMIC on top of the Arduino environment.
 *******************************************************************************/

#include <Arduino.h>
#include <SPI.h>
#include "../lmic.h"
#include "hal.h"
#include <stdio.h>

// -----------------------------------------------------------------------------
// I/O

static void hal_io_init () {
    // NSS and DIO0 are required, DIO1 is required for LoRa, DIO2 for FSK
    ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
    ASSERT(lmic_pins.dio[0] != LMIC_UNUSED_PIN);
    ASSERT(lmic_pins.dio[1] != LMIC_UNUSED_PIN || lmic_pins.dio[2] != LMIC_UNUSED_PIN);

    pinMode(lmic_pins.nss, OUTPUT);
    if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.rxtx, OUTPUT);
    if (lmic_pins.rst != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.rst, OUTPUT);

    pinMode(lmic_pins.dio[0], INPUT);
    if (lmic_pins.dio[1] != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.dio[1], INPUT);
    if (lmic_pins.dio[2] != LMIC_UNUSED_PIN)
        pinMode(lmic_pins.dio[2], INPUT);
}

// val == 1  => tx 1
void hal_pin_rxtx (u1_t val) {
    if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
        digitalWrite(lmic_pins.rxtx, val);
}

// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
    if (lmic_pins.rst == LMIC_UNUSED_PIN)
        return;

    if(val == 0 || val == 1) { // drive pin
        pinMode(lmic_pins.rst, OUTPUT);
        digitalWrite(lmic_pins.rst, val);
    } else { // keep pin floating
        pinMode(lmic_pins.rst, INPUT);
    }
}

static bool dio_states[NUM_DIO] = {0};

static void hal_io_check() {
    uint8_t i;
    for (i = 0; i < NUM_DIO; ++i) {
        if (lmic_pins.dio[i] == LMIC_UNUSED_PIN)
            continue;

        if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
            dio_states[i] = !dio_states[i];
            if (dio_states[i])
                radio_irq_handler(i);
        }
    }
}

// -----------------------------------------------------------------------------
// SPI

static const SPISettings settings(1E6, MSBFIRST, SPI_MODE0);

static void hal_spi_init () {
    SPI.begin();
}

void hal_pin_nss (u1_t val) {
    if (!val)
        SPI.beginTransaction(settings);
    else
        SPI.endTransaction();

    //Serial.println(val?">>":"<<");
    digitalWrite(lmic_pins.nss, val);
}

// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
    u1_t res = SPI.transfer(out);
/*
    Serial.print(">");
    Serial.print(out, HEX);
    Serial.print("<");
    Serial.println(res, HEX);
    */
    return res;
}

// -----------------------------------------------------------------------------
// TIME

static void hal_time_init () {
    // Nothing to do
}

u4_t hal_ticks () {
    // Because micros() is scaled down in this function, micros() will
    // overflow before the tick timer should, causing the tick timer to
    // miss a significant part of its values if not corrected. To fix
    // this, the "overflow" serves as an overflow area for the micros()
    // counter. It consists of three parts:
    //  - The US_PER_OSTICK upper bits are effectively an extension for
    //    the micros() counter and are added to the result of this
    //    function.
    //  - The next bit overlaps with the most significant bit of
    //    micros(). This is used to detect micros() overflows.
    //  - The remaining bits are always zero.
    //
    // By comparing the overlapping bit with the corresponding bit in
    // the micros() return value, overflows can be detected and the
    // upper bits are incremented. This is done using some clever
    // bitwise operations, to remove the need for comparisons and a
    // jumps, which should result in efficient code. By avoiding shifts
    // other than by multiples of 8 as much as possible, this is also
    // efficient on AVR (which only has 1-bit shifts).
    static uint8_t overflow = 0;

    // Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
    // the others will be the lower bits of our return value.
    uint32_t scaled = micros() >> US_PER_OSTICK_EXPONENT;
    // Most significant byte of scaled
    uint8_t msb = scaled >> 24;
    // Mask pointing to the overlapping bit in msb and overflow.
    const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
    // Update overflow. If the overlapping bit is different
    // between overflow and msb, it is added to the stored value,
    // so the overlapping bit becomes equal again and, if it changed
    // from 1 to 0, the upper bits are incremented.
    overflow += (msb ^ overflow) & mask;

    // Return the scaled value with the upper bits of stored added. The
    // overlapping bit will be equal and the lower bits will be 0, so
    // bitwise or is a no-op for them.
    return scaled | ((uint32_t)overflow << 24);

    // 0 leads to correct, but overly complex code (it could just return
    // micros() unmodified), 8 leaves no room for the overlapping bit.
    static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
}

// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
    return (s4_t)(time - hal_ticks());
}

void hal_waitUntil (u4_t time) {
    s4_t delta = delta_time(time);
    // From delayMicroseconds docs: Currently, the largest value that
    // will produce an accurate delay is 16383.
    while (delta > (16000 / US_PER_OSTICK)) {
        delay(16);
        delta -= (16000 / US_PER_OSTICK);
    }
    if (delta > 0)
        delayMicroseconds(delta * US_PER_OSTICK);
}

// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
    // No need to schedule wakeup, since we're not sleeping
    return delta_time(time) <= 0;
}

static uint8_t irqlevel = 0;

void hal_disableIRQs () {
    noInterrupts();
    irqlevel++;
}

void hal_enableIRQs () {
    if(--irqlevel == 0) {
        interrupts();

        // Instead of using proper interrupts (which are a bit tricky
        // and/or not available on all pins on AVR), just poll the pin
        // values. Since os_runloop disables and re-enables interrupts,
        // putting this here makes sure we check at least once every
        // loop.
        //
        // As an additional bonus, this prevents the can of worms that
        // we would otherwise get for running SPI transfers inside ISRs
        hal_io_check();
    }
}

void hal_sleep () {
    // Not implemented
}

// -----------------------------------------------------------------------------

#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
    LMIC_PRINTF_TO.write(c) ;
    return 0 ;
}

void hal_printf_init() {
    // create a FILE structure to reference our UART output function
    static FILE uartout;
    memset(&uartout, 0, sizeof(uartout));

    // fill in the UART file descriptor with pointer to writer.
    fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);

    // The uart is the standard output device STDOUT.
    stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)

void hal_init () {
    // configure radio I/O and interrupt handler
    hal_io_init();
    // configure radio SPI
    hal_spi_init();
    // configure timer and interrupt handler
    hal_time_init();
#if defined(LMIC_PRINTF_TO)
    // printf support
    hal_printf_init();
#endif
}

void hal_failed (const char *file, u2_t line) {
#if defined(LMIC_FAILURE_TO)
    LMIC_FAILURE_TO.println("FAILURE ");
    LMIC_FAILURE_TO.print(file);
    LMIC_FAILURE_TO.print(':');
    LMIC_FAILURE_TO.println(line);
    LMIC_FAILURE_TO.flush();
#endif
    hal_disableIRQs();
    while(1);
}
<|endoftext|>