<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ndtyp.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 02:02:50 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _NDTYP_HXX
#define _NDTYP_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

// Ids fuer die verschiedenden Nodes; in der Basisklasse steht der Member,
// der angibt, um was fuer einen es sich handelt
const BYTE ND_ENDNODE       = 0x01;
const BYTE ND_STARTNODE     = 0x02;
const BYTE ND_TABLENODE     = 0x06;
const BYTE ND_TEXTNODE      = 0x08;
const BYTE ND_GRFNODE       = 0x10;
const BYTE ND_OLENODE       = 0x20;

const BYTE ND_CONTENTNODE   = 0x38; // ContentNode (eines von den 3 Bits)
const BYTE ND_NOTXTNODE     = 0x30; // NoTxtNode (eines von den 2 Bits)

const BYTE ND_SECTIONNODE   = 0x42;
// nur fuer internen Gebrauch!!
const BYTE ND_SECTIONDUMMY  = 0x40; //(ND_SECTIONNODE & ~ND_STARTNODE);

// spezielle Types der StartNodes, die keine Ableitungen sind, aber
// "Bereiche" zusammenhalten.
enum SwStartNodeType
{
    SwNormalStartNode = 0,
    SwTableBoxStartNode,
    SwFlyStartNode,
    SwFootnoteStartNode,
    SwHeaderStartNode,
    SwFooterStartNode
};

// is the node the first and/or last node of a section?
// This information is used for the export filters. Our layout never have a
// distance before or after if the node is the first or last in a section.
const BYTE ND_HAS_PREV_LAYNODE = 0x01;
const BYTE ND_HAS_NEXT_LAYNODE = 0x02;

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.2.1202); FILE MERGED 2008/04/01 15:56:16 thb 1.2.1202.2: #i85898# Stripping all external header guards 2008/03/31 16:52:40 rt 1.2.1202.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ndtyp.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _NDTYP_HXX
#define _NDTYP_HXX

#include <tools/solar.h>

// Ids fuer die verschiedenden Nodes; in der Basisklasse steht der Member,
// der angibt, um was fuer einen es sich handelt
const BYTE ND_ENDNODE       = 0x01;
const BYTE ND_STARTNODE     = 0x02;
const BYTE ND_TABLENODE     = 0x06;
const BYTE ND_TEXTNODE      = 0x08;
const BYTE ND_GRFNODE       = 0x10;
const BYTE ND_OLENODE       = 0x20;

const BYTE ND_CONTENTNODE   = 0x38; // ContentNode (eines von den 3 Bits)
const BYTE ND_NOTXTNODE     = 0x30; // NoTxtNode (eines von den 2 Bits)

const BYTE ND_SECTIONNODE   = 0x42;
// nur fuer internen Gebrauch!!
const BYTE ND_SECTIONDUMMY  = 0x40; //(ND_SECTIONNODE & ~ND_STARTNODE);

// spezielle Types der StartNodes, die keine Ableitungen sind, aber
// "Bereiche" zusammenhalten.
enum SwStartNodeType
{
    SwNormalStartNode = 0,
    SwTableBoxStartNode,
    SwFlyStartNode,
    SwFootnoteStartNode,
    SwHeaderStartNode,
    SwFooterStartNode
};

// is the node the first and/or last node of a section?
// This information is used for the export filters. Our layout never have a
// distance before or after if the node is the first or last in a section.
const BYTE ND_HAS_PREV_LAYNODE = 0x01;
const BYTE ND_HAS_NEXT_LAYNODE = 0x02;

#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////
// This file is part of Grappa, a system for scaling irregular
// applications on commodity clusters.

// Copyright (C) 2010-2014 University of Washington and Battelle
// Memorial Institute. University of Washington authorizes use of this
// Grappa software.

// Grappa is free software: you can redistribute it and/or modify it
// under the terms of the Affero General Public License as published
// by Affero, Inc., either version 1 of the License, or (at your
// option) any later version.

// Grappa 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
// Affero General Public License for more details.

// You should have received a copy of the Affero General Public
// License along with this program. If not, you may obtain one from
// http://www.affero.org/oagpl.html.
////////////////////////////////////////////////////////////////////////
#pragma once

#include "Addressing.hpp"
#include "Communicator.hpp"
#include "Collective.hpp"
#include "Cache.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "GlobalAllocator.hpp"
#include <type_traits>
#include "Delegate.hpp"

namespace Grappa {
/// @addtogroup Containers
/// @{

/// Initialize an array of elements of generic type with a given value.
///
/// This version sends a large number of active messages, the same way as the Incoherent
/// releaser, to set each part of a global array. In theory, this version should be able
/// to be called from multiple locations at the same time (to initialize different regions of global memory).
///
/// @param base Base address of the array to be set.
/// @param value Value to set every element of array to (will be copied to all the nodes)
/// @param count Number of elements to set, starting at the base address.
template< typename T, typename S >
void memset(GlobalAddress<T> base, S value, size_t count) {
  call_on_all_cores([base,count,value]{
    T * local_base = base.localize();
    T * local_end = (base+count).localize();
    for (size_t i=0; i<local_end-local_base; i++) {
      local_base[i] = value;
    }
  });
}

namespace impl {
  /// Copy elements of array (src..src+nelem) that are local to corresponding locations in dst
  template< typename T >
  void do_memcpy_locally(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
    typedef typename Incoherent<T>::WO Writeback;
    auto src_end = src+nelem;
    // T * local_base = src.localize(), * local_end = (src+nelem).localize();
    int64_t nfirstcore = src.block_max() - src;
    int64_t nlastcore = src_end - src_end.block_min();
    int64_t nmiddle = nelem - nfirstcore - nlastcore;

    const size_t nblock = block_size / sizeof(T);

    CHECK_EQ(nmiddle % nblock, 0);

    auto src_start = src;
    if (src.core() == mycore()) {
      int64_t nfirstcore = src.block_max() - src;
      if (nfirstcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nfirstcore = " << nfirstcore;
        Writeback w(dst, nfirstcore, src.pointer());
        src_start += nfirstcore;
      }
    }
    if ((src_end-1).core() == mycore()) {
      int64_t nlastcore = src_end - src_end.block_min();
      int64_t index = nelem - nlastcore;
      if (nlastcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nlastcore = " << nlastcore << ", index = " << index;
        CHECK((src+index).core() == mycore());
        Writeback w(dst+index, nlastcore, (src+index).pointer());
        src_end -= nlastcore;
      }
    }

    auto * local_base = src_start.localize();
    size_t nlocal_trimmed = src_end.localize() - local_base;
    CHECK_EQ((nlocal_trimmed) % nblock, 0);
    size_t nlocalblocks = nlocal_trimmed/nblock;
    Writeback * ws = locale_alloc<Writeback>(nlocalblocks);
    for (size_t i=0; i<nlocalblocks; i++) {
      size_t j = make_linear(local_base+(i*nblock))-src;
      new (ws+i) Writeback(dst+j, nblock, local_base+(i*nblock));
      ws[i].start_release();
    }
    for (size_t i=0; i<nlocalblocks; i++) { ws[i].block_until_released(); }
    locale_free(ws);
  }
}

/// Memcpy over Grappa global arrays. Arguments `dst` and `src` must point into global arrays
/// (so must be linear addresses) and be non-overlapping, and both must have at least `nelem`
/// elements.
template< typename T >
void memcpy(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_all_cores([dst,src,nelem]{
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// Helper so we don't have to change the code if we change a Global pointer to a normal pointer (in theory).
template< typename T >
void memcpy(T* dst, T* src, size_t nelem) {
  ::memcpy(dst, src, nelem*sizeof(T));
}

/// Asynchronous version of memcpy, spawns only on cores with array elements. Synchronizes
/// with given GlobalCompletionEvent, so memcpy's are known to be complete after GCE->wait().
/// Note: same restrictions on `dst` and `src` as Grappa::memcpy).
template< GlobalCompletionEvent * GCE = &impl::local_gce, typename T = void >
void memcpy_async(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_cores_localized_async<GCE>(src, nelem, [dst,src,nelem](T* base, size_t nlocal){
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// not implemented yet
template< typename T >
void prefix_sum(GlobalAddress<T> array, size_t nelem) {
  // not implemented
  CHECK(false) << "prefix_sum is currently unimplemented!";
}

namespace util {
  /// String representation of a local array, matches form of Grappa::array_str that takes a global array.
  template<typename T>
  inline std::string array_str(const char * name, T * base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << base[i];
    }
    ss << "\n]";
    return ss.str();
  }

  /// String representation of a global array.
  /// @example
  /// @code
  ///   GlobalAddress<int> xs;
  ///   DVLOG(2) << array_str("x", xs, 4);
  /// // (if DEBUG=1 and --v=2)
  /// //> x: [
  /// //>  7 4 2 3
  /// //> ]
  /// @endcode
  template<typename T>
  inline std::string array_str(const char * name, GlobalAddress<T> base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << delegate::read(base+i);
    }
    ss << "\n]";
    return ss.str();
  }

  template< typename ArrayT, class = typename std::enable_if<std::is_array<ArrayT>::value>::type >
  inline std::string array_str(const char * name, ArrayT array, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    long i=0;
    for (auto e : array) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << e;
      i++;
    }
    ss << "\n]";
    return ss.str();
  }

  template<typename T>
  struct SimpleIterator {
    T * base;
    size_t nelem;
    T * begin() { return base; }
    T * end()   { return base+nelem; }
  };

  /// Easier C++11 iteration over local array. Similar idea to Addressing::iterate_local().
  ///
  /// @code
  ///   auto array = new long[N];
  ///   for (auto& v : util::iterate(array,N)) {
  ///     v++;
  ///   }
  /// @endcode
  template<typename T>
  SimpleIterator<T> iterate(T* base = nullptr, size_t nelem = 0) { return SimpleIterator<T>{base, nelem}; }

} // namespace util

/// @}
} // namespace Grappa
<commit_msg>fix Grappa::memcpy to handle void*<commit_after>////////////////////////////////////////////////////////////////////////
// This file is part of Grappa, a system for scaling irregular
// applications on commodity clusters.

// Copyright (C) 2010-2014 University of Washington and Battelle
// Memorial Institute. University of Washington authorizes use of this
// Grappa software.

// Grappa is free software: you can redistribute it and/or modify it
// under the terms of the Affero General Public License as published
// by Affero, Inc., either version 1 of the License, or (at your
// option) any later version.

// Grappa 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
// Affero General Public License for more details.

// You should have received a copy of the Affero General Public
// License along with this program. If not, you may obtain one from
// http://www.affero.org/oagpl.html.
////////////////////////////////////////////////////////////////////////
#pragma once

#include "Addressing.hpp"
#include "Communicator.hpp"
#include "Collective.hpp"
#include "Cache.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include "GlobalAllocator.hpp"
#include <type_traits>
#include "Delegate.hpp"

namespace Grappa {
/// @addtogroup Containers
/// @{

/// Initialize an array of elements of generic type with a given value.
///
/// This version sends a large number of active messages, the same way as the Incoherent
/// releaser, to set each part of a global array. In theory, this version should be able
/// to be called from multiple locations at the same time (to initialize different regions of global memory).
///
/// @param base Base address of the array to be set.
/// @param value Value to set every element of array to (will be copied to all the nodes)
/// @param count Number of elements to set, starting at the base address.
template< typename T, typename S >
void memset(GlobalAddress<T> base, S value, size_t count) {
  call_on_all_cores([base,count,value]{
    T * local_base = base.localize();
    T * local_end = (base+count).localize();
    for (size_t i=0; i<local_end-local_base; i++) {
      local_base[i] = value;
    }
  });
}

namespace impl {
  /// Copy elements of array (src..src+nelem) that are local to corresponding locations in dst
  template< typename T >
  void do_memcpy_locally(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
    typedef typename Incoherent<T>::WO Writeback;
    auto src_end = src+nelem;
    // T * local_base = src.localize(), * local_end = (src+nelem).localize();
    int64_t nfirstcore = src.block_max() - src;
    int64_t nlastcore = src_end - src_end.block_min();
    int64_t nmiddle = nelem - nfirstcore - nlastcore;

    const size_t nblock = block_size / sizeof(T);

    CHECK_EQ(nmiddle % nblock, 0);

    auto src_start = src;
    if (src.core() == mycore()) {
      int64_t nfirstcore = src.block_max() - src;
      if (nfirstcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nfirstcore = " << nfirstcore;
        Writeback w(dst, nfirstcore, src.pointer());
        src_start += nfirstcore;
      }
    }
    if ((src_end-1).core() == mycore()) {
      int64_t nlastcore = src_end - src_end.block_min();
      int64_t index = nelem - nlastcore;
      if (nlastcore > 0 && nlastcore != nblock) {
        DVLOG(3) << "nlastcore = " << nlastcore << ", index = " << index;
        CHECK((src+index).core() == mycore());
        Writeback w(dst+index, nlastcore, (src+index).pointer());
        src_end -= nlastcore;
      }
    }

    auto * local_base = src_start.localize();
    size_t nlocal_trimmed = src_end.localize() - local_base;
    CHECK_EQ((nlocal_trimmed) % nblock, 0);
    size_t nlocalblocks = nlocal_trimmed/nblock;
    Writeback * ws = locale_alloc<Writeback>(nlocalblocks);
    for (size_t i=0; i<nlocalblocks; i++) {
      size_t j = make_linear(local_base+(i*nblock))-src;
      new (ws+i) Writeback(dst+j, nblock, local_base+(i*nblock));
      ws[i].start_release();
    }
    for (size_t i=0; i<nlocalblocks; i++) { ws[i].block_until_released(); }
    locale_free(ws);
  }
}

/// Memcpy over Grappa global arrays. Arguments `dst` and `src` must point into global arrays
/// (so must be linear addresses) and be non-overlapping, and both must have at least `nelem`
/// elements.
template< typename T >
void memcpy(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_all_cores([dst,src,nelem]{
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// Helper so we don't have to change the code if we change a Global pointer to a normal pointer (in theory).
template< typename T >
inline void memcpy(T* dst, T* src, size_t nelem) {
  ::memcpy(dst, src, nelem*sizeof(T));
}

template<>
inline void memcpy<void>(void* dst, void* src, size_t nelem) {
  ::memcpy(dst, src, nelem);
}

/// Asynchronous version of memcpy, spawns only on cores with array elements. Synchronizes
/// with given GlobalCompletionEvent, so memcpy's are known to be complete after GCE->wait().
/// Note: same restrictions on `dst` and `src` as Grappa::memcpy).
template< GlobalCompletionEvent * GCE = &impl::local_gce, typename T = void >
void memcpy_async(GlobalAddress<T> dst, GlobalAddress<T> src, size_t nelem) {
  on_cores_localized_async<GCE>(src, nelem, [dst,src,nelem](T* base, size_t nlocal){
    impl::do_memcpy_locally(dst,src,nelem);
  });
}

/// not implemented yet
template< typename T >
void prefix_sum(GlobalAddress<T> array, size_t nelem) {
  // not implemented
  CHECK(false) << "prefix_sum is currently unimplemented!";
}

namespace util {
  /// String representation of a local array, matches form of Grappa::array_str that takes a global array.
  template<typename T>
  inline std::string array_str(const char * name, T * base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << base[i];
    }
    ss << "\n]";
    return ss.str();
  }

  /// String representation of a global array.
  /// @example
  /// @code
  ///   GlobalAddress<int> xs;
  ///   DVLOG(2) << array_str("x", xs, 4);
  /// // (if DEBUG=1 and --v=2)
  /// //> x: [
  /// //>  7 4 2 3
  /// //> ]
  /// @endcode
  template<typename T>
  inline std::string array_str(const char * name, GlobalAddress<T> base, size_t nelem, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    for (size_t i=0; i<nelem; i++) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << delegate::read(base+i);
    }
    ss << "\n]";
    return ss.str();
  }

  template< typename ArrayT, class = typename std::enable_if<std::is_array<ArrayT>::value>::type >
  inline std::string array_str(const char * name, ArrayT array, int width = 10) {
    std::stringstream ss; ss << "\n" << name << ": [";
    long i=0;
    for (auto e : array) {
      if (i % width == 0) ss << "\n  ";
      ss << " " << e;
      i++;
    }
    ss << "\n]";
    return ss.str();
  }

  template<typename T>
  struct SimpleIterator {
    T * base;
    size_t nelem;
    T * begin() { return base; }
    T * end()   { return base+nelem; }
  };

  /// Easier C++11 iteration over local array. Similar idea to Addressing::iterate_local().
  ///
  /// @code
  ///   auto array = new long[N];
  ///   for (auto& v : util::iterate(array,N)) {
  ///     v++;
  ///   }
  /// @endcode
  template<typename T>
  SimpleIterator<T> iterate(T* base = nullptr, size_t nelem = 0) { return SimpleIterator<T>{base, nelem}; }

} // namespace util

/// @}
} // namespace Grappa
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.

#define EIGEN2_SUPPORT
#define EIGEN_NO_STATIC_ASSERT
#include "main.h"
#include <functional>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

using namespace std;

template<typename Scalar> struct AddIfNull {
    const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
    enum { Cost = NumTraits<Scalar>::AddCost };
};

template<typename MatrixType>
typename Eigen::internal::enable_if<!NumTraits<typename MatrixType::Scalar>::IsInteger,typename MatrixType::Scalar>::type
cwiseops_real_only(MatrixType& m1, MatrixType& m2, MatrixType& m3, MatrixType& mones)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  VERIFY_IS_APPROX(m1.cwise() / m2,    m1.cwise() * (m2.cwise().inverse()));
  m3 = m1.cwise().abs().cwise().sqrt();
  VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
  VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
  VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());

  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
  m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
  VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
  m3 = m1.cwise().abs();
  VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());

//   VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
  VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
  m3 = m1;
  m3.cwise() /= m2;
  VERIFY_IS_APPROX(m3, m1.cwise() / m2);

  return Scalar(0);
}

template<typename MatrixType>
typename Eigen::internal::enable_if<NumTraits<typename MatrixType::Scalar>::IsInteger,typename MatrixType::Scalar>::type
cwiseops_real_only(MatrixType& , MatrixType& , MatrixType& , MatrixType& )
{
  typedef typename MatrixType::Scalar Scalar;
  return 0;
}

template<typename MatrixType> void cwiseops(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             m4(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             mones = MatrixType::Ones(rows, cols),
             identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
                              ::Identity(rows, rows);
  VectorType vzero = VectorType::Zero(rows),
             vones = VectorType::Ones(rows),
             v3(rows);

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  Scalar s1 = internal::random<Scalar>();

  // test Zero, Ones, Constant, and the set* variants
  m3 = MatrixType::Constant(rows, cols, s1);
  for (int j=0; j<cols; ++j)
    for (int i=0; i<rows; ++i)
    {
      VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
      VERIFY_IS_APPROX(mones(i,j), Scalar(1));
      VERIFY_IS_APPROX(m3(i,j), s1);
    }
  VERIFY(mzero.isZero());
  VERIFY(mones.isOnes());
  VERIFY(m3.isConstant(s1));
  VERIFY(identity.isIdentity());
  VERIFY_IS_APPROX(m4.setConstant(s1), m3);
  VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
  VERIFY_IS_APPROX(m4.setZero(), mzero);
  VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
  VERIFY_IS_APPROX(m4.setOnes(), mones);
  VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
  m4.fill(s1);
  VERIFY_IS_APPROX(m4, m3);

  VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
  VERIFY_IS_APPROX(v3.setZero(rows), vzero);
  VERIFY_IS_APPROX(v3.setOnes(rows), vones);

  m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);

  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
  VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());

  VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
  VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
  m3 = m1; m3.cwise() += 1;
  VERIFY_IS_APPROX(m1 + mones, m3);
  m3 = m1; m3.cwise() -= 1;
  VERIFY_IS_APPROX(m1 - mones, m3);

  VERIFY_IS_APPROX(m2, m2.cwise() * mones);
  VERIFY_IS_APPROX(m1.cwise() * m2,  m2.cwise() * m1);
  m3 = m1;
  m3.cwise() *= m2;
  VERIFY_IS_APPROX(m3, m1.cwise() * m2);

  VERIFY_IS_APPROX(mones,    m2.cwise()/m2);

  // check min
  VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
  VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
  VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );

  // check max
  VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
  VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
  VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );

  VERIFY( (m1.cwise() == m1).all() );
  VERIFY( (m1.cwise() != m2).any() );
  VERIFY(!(m1.cwise() == (m1+mones)).any() );
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY( (m1.cwise() == m3).any() );
    VERIFY( !(m1.cwise() == m3).all() );
  }
  VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
  VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
  VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
  VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );

  VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
  VERIFY( !(m1.cwise()<m1.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
  VERIFY( !(m1.cwise()>m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );

  cwiseops_real_only(m1, m2, m3, mones);
}

void test_cwiseop()
{
  for(int i = 0; i < g_repeat ; i++) {
    CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( cwiseops(Matrix4d()) );
    CALL_SUBTEST_3( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_4( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_5( cwiseops(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_6( cwiseops(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
  }
}
<commit_msg>Workaround warning: assuming signed overflow does not occur when...<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@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/.

#define EIGEN2_SUPPORT
#define EIGEN_NO_STATIC_ASSERT
#include "main.h"
#include <functional>

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

using namespace std;

template<typename Scalar> struct AddIfNull {
    const Scalar operator() (const Scalar a, const Scalar b) const {return a<=1e-3 ? b : a;}
    enum { Cost = NumTraits<Scalar>::AddCost };
};

template<typename MatrixType>
typename Eigen::internal::enable_if<!NumTraits<typename MatrixType::Scalar>::IsInteger,typename MatrixType::Scalar>::type
cwiseops_real_only(MatrixType& m1, MatrixType& m2, MatrixType& m3, MatrixType& mones)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  VERIFY_IS_APPROX(m1.cwise() / m2,    m1.cwise() * (m2.cwise().inverse()));
  m3 = m1.cwise().abs().cwise().sqrt();
  VERIFY_IS_APPROX(m3.cwise().square(), m1.cwise().abs());
  VERIFY_IS_APPROX(m1.cwise().square().cwise().sqrt(), m1.cwise().abs());
  VERIFY_IS_APPROX(m1.cwise().abs().cwise().log().cwise().exp() , m1.cwise().abs());

  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
  m3 = (m1.cwise().abs().cwise()<=RealScalar(0.01)).select(mones,m1);
  VERIFY_IS_APPROX(m3.cwise().pow(-1), m3.cwise().inverse());
  m3 = m1.cwise().abs();
  VERIFY_IS_APPROX(m3.cwise().pow(RealScalar(0.5)), m3.cwise().sqrt());

//   VERIFY_IS_APPROX(m1.cwise().tan(), m1.cwise().sin().cwise() / m1.cwise().cos());
  VERIFY_IS_APPROX(mones, m1.cwise().sin().cwise().square() + m1.cwise().cos().cwise().square());
  m3 = m1;
  m3.cwise() /= m2;
  VERIFY_IS_APPROX(m3, m1.cwise() / m2);

  return Scalar(0);
}

template<typename MatrixType>
typename Eigen::internal::enable_if<NumTraits<typename MatrixType::Scalar>::IsInteger,typename MatrixType::Scalar>::type
cwiseops_real_only(MatrixType& , MatrixType& , MatrixType& , MatrixType& )
{
  typedef typename MatrixType::Scalar Scalar;
  return 0;
}

template<typename MatrixType> void cwiseops(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols),
             m1bis = m1,
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             m4(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             mones = MatrixType::Ones(rows, cols),
             identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
                              ::Identity(rows, rows);
  VectorType vzero = VectorType::Zero(rows),
             vones = VectorType::Ones(rows),
             v3(rows);

  Index r = internal::random<Index>(0, rows-1),
        c = internal::random<Index>(0, cols-1);

  Scalar s1 = internal::random<Scalar>();

  // test Zero, Ones, Constant, and the set* variants
  m3 = MatrixType::Constant(rows, cols, s1);
  for (int j=0; j<cols; ++j)
    for (int i=0; i<rows; ++i)
    {
      VERIFY_IS_APPROX(mzero(i,j), Scalar(0));
      VERIFY_IS_APPROX(mones(i,j), Scalar(1));
      VERIFY_IS_APPROX(m3(i,j), s1);
    }
  VERIFY(mzero.isZero());
  VERIFY(mones.isOnes());
  VERIFY(m3.isConstant(s1));
  VERIFY(identity.isIdentity());
  VERIFY_IS_APPROX(m4.setConstant(s1), m3);
  VERIFY_IS_APPROX(m4.setConstant(rows,cols,s1), m3);
  VERIFY_IS_APPROX(m4.setZero(), mzero);
  VERIFY_IS_APPROX(m4.setZero(rows,cols), mzero);
  VERIFY_IS_APPROX(m4.setOnes(), mones);
  VERIFY_IS_APPROX(m4.setOnes(rows,cols), mones);
  m4.fill(s1);
  VERIFY_IS_APPROX(m4, m3);

  VERIFY_IS_APPROX(v3.setConstant(rows, s1), VectorType::Constant(rows,s1));
  VERIFY_IS_APPROX(v3.setZero(rows), vzero);
  VERIFY_IS_APPROX(v3.setOnes(rows), vones);

  m2 = m2.template binaryExpr<AddIfNull<Scalar> >(mones);

  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().abs2());
  VERIFY_IS_APPROX(m1.cwise().pow(2), m1.cwise().square());
  VERIFY_IS_APPROX(m1.cwise().pow(3), m1.cwise().cube());

  VERIFY_IS_APPROX(m1 + mones, m1.cwise()+Scalar(1));
  VERIFY_IS_APPROX(m1 - mones, m1.cwise()-Scalar(1));
  m3 = m1; m3.cwise() += 1;
  VERIFY_IS_APPROX(m1 + mones, m3);
  m3 = m1; m3.cwise() -= 1;
  VERIFY_IS_APPROX(m1 - mones, m3);

  VERIFY_IS_APPROX(m2, m2.cwise() * mones);
  VERIFY_IS_APPROX(m1.cwise() * m2,  m2.cwise() * m1);
  m3 = m1;
  m3.cwise() *= m2;
  VERIFY_IS_APPROX(m3, m1.cwise() * m2);

  VERIFY_IS_APPROX(mones,    m2.cwise()/m2);

  // check min
  VERIFY_IS_APPROX( m1.cwise().min(m2), m2.cwise().min(m1) );
  VERIFY_IS_APPROX( m1.cwise().min(m1+mones), m1 );
  VERIFY_IS_APPROX( m1.cwise().min(m1-mones), m1-mones );

  // check max
  VERIFY_IS_APPROX( m1.cwise().max(m2), m2.cwise().max(m1) );
  VERIFY_IS_APPROX( m1.cwise().max(m1-mones), m1 );
  VERIFY_IS_APPROX( m1.cwise().max(m1+mones), m1+mones );

  VERIFY( (m1.cwise() == m1).all() );
  VERIFY( (m1.cwise() != m2).any() );
  VERIFY(!(m1.cwise() == (m1+mones)).any() );
  if (rows*cols>1)
  {
    m3 = m1;
    m3(r,c) += 1;
    VERIFY( (m1.cwise() == m3).any() );
    VERIFY( !(m1.cwise() == m3).all() );
  }
  VERIFY( (m1.cwise().min(m2).cwise() <= m2).all() );
  VERIFY( (m1.cwise().max(m2).cwise() >= m2).all() );
  VERIFY( (m1.cwise().min(m2).cwise() < (m1+mones)).all() );
  VERIFY( (m1.cwise().max(m2).cwise() > (m1-mones)).all() );

  VERIFY( (m1.cwise()<m1.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).all() );
  VERIFY( !(m1.cwise()<m1bis.unaryExpr(bind2nd(minus<Scalar>(), Scalar(1)))).all() );
  VERIFY( !(m1.cwise()>m1bis.unaryExpr(bind2nd(plus<Scalar>(), Scalar(1)))).any() );

  cwiseops_real_only(m1, m2, m3, mones);
}

void test_cwiseop()
{
  for(int i = 0; i < g_repeat ; i++) {
    CALL_SUBTEST_1( cwiseops(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( cwiseops(Matrix4d()) );
    CALL_SUBTEST_3( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_4( cwiseops(MatrixXf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_5( cwiseops(MatrixXi(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
    CALL_SUBTEST_6( cwiseops(MatrixXd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "was/Client.hxx"
#include "was/Launch.hxx"
#include "was/Lease.hxx"
#include "stopwatch.hxx"
#include "lease.hxx"
#include "HttpResponseHandler.hxx"
#include "direct.hxx"
#include "strmap.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/FileIstream.hxx"
#include "fb_pool.hxx"
#include "PInstance.hxx"
#include "spawn/Config.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/Registry.hxx"
#include "spawn/Local.hxx"
#include "io/Logger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"
#include "util/StaticArray.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

struct Context final
    : PInstance, WasLease, IstreamHandler, HttpResponseHandler {

    WasProcess process;

    IstreamPointer body;
    bool error;

    CancellablePointer cancel_ptr;

    Context():body(nullptr) {}

    /* virtual methods from class IstreamHandler */

    size_t OnData(const void *data, size_t length) noexcept override;

    void OnEof() noexcept override {
        body.Clear();
    }

    void OnError(std::exception_ptr ep) noexcept override {
        PrintException(ep);

        body.Clear();
        error = true;
    }

    /* virtual methods from class Lease */
    void ReleaseWas(gcc_unused bool reuse) override {
        kill(process.pid, SIGTERM);

        process.Close();
    }

    void ReleaseWasStop(gcc_unused uint64_t input_received) override {
        ReleaseWas(false);
    }

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * istream handler
 *
 */

size_t
Context::OnData(const void *data, size_t length) noexcept
{
    ssize_t nbytes = write(1, data, length);
    if (nbytes <= 0) {
        error = true;
        body.ClearAndClose();
        return 0;
    }

    return (size_t)nbytes;
}

/*
 * http_response_handler
 *
 */

void
Context::OnHttpResponse(http_status_t status,
                        gcc_unused StringMap &&headers,
                        UnusedIstreamPtr _body) noexcept
{
    fprintf(stderr, "status: %s\n", http_status_to_string(status));

    if (_body)
        body.Set(std::move(_body), *this);
}

void
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    error = true;
}

static Istream *
request_body(EventLoop &event_loop, struct pool &pool)
{
    struct stat st;
    return fstat(0, &st) == 0 && S_ISREG(st.st_mode)
        ? istream_file_fd_new(event_loop, pool,
                              "/dev/stdin", UniqueFileDescriptor(STDIN_FILENO),
                              FdType::FD_FILE, -1)
        : nullptr;
}

int
main(int argc, char **argv)
try {
    SetLogLevel(5);

    StaticArray<const char *, 64> params;

    if (argc < 3) {
        fprintf(stderr, "Usage: run_was PATH URI [--parameter a=b ...]\n");
        return EXIT_FAILURE;
    }

    const char *uri = argv[2];

    for (int i = 3; i < argc;) {
        if (strcmp(argv[i], "--parameter") == 0 ||
            strcmp(argv[i], "-p") == 0) {
            ++i;
            if (i >= argc)
                throw std::runtime_error("Parameter value missing");

            if (params.full())
                throw std::runtime_error("Too many parameters");

            params.push_back(argv[i++]);
        } else
            throw std::runtime_error("Unrecognized parameter");
    }

    direct_global_init();

    SpawnConfig spawn_config;

    const ScopeFbPoolInit fb_pool_init;

    ChildOptions child_options;

    Context context;
    ChildProcessRegistry child_process_registry(context.event_loop);
    child_process_registry.SetVolatile();
    LocalSpawnService spawn_service(spawn_config, child_process_registry);

    context.process = was_launch(spawn_service, "was",
                                 argv[1], nullptr,
                                 child_options, {}, nullptr);

    was_client_request(context.root_pool, context.event_loop, nullptr,
                       context.process.control,
                       context.process.input,
                       context.process.output,
                       context,
                       HTTP_METHOD_GET, uri,
                       nullptr,
                       nullptr, nullptr,
                       *strmap_new(context.root_pool),
                       UnusedIstreamPtr(request_body(context.event_loop,
                                                     context.root_pool)),
                       { (const char *const*)params.raw(), params.size() },
                       context, context.cancel_ptr);

    context.event_loop.Dispatch();

    return context.error;
} catch (const std::exception &e) {
    PrintException(e);
    return EXIT_FAILURE;
}
<commit_msg>test/run_was: use sink_fd instead of rolling our own IstreamHandler<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "was/Client.hxx"
#include "was/Launch.hxx"
#include "was/Lease.hxx"
#include "stopwatch.hxx"
#include "lease.hxx"
#include "HttpResponseHandler.hxx"
#include "direct.hxx"
#include "strmap.hxx"
#include "istream/sink_fd.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/FileIstream.hxx"
#include "fb_pool.hxx"
#include "PInstance.hxx"
#include "spawn/Config.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/Registry.hxx"
#include "spawn/Local.hxx"
#include "io/Logger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Cancellable.hxx"
#include "util/PrintException.hxx"
#include "util/StaticArray.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

struct Context final
    : PInstance, WasLease, HttpResponseHandler {

    WasProcess process;

    SinkFd *body = nullptr;
    bool error;

    CancellablePointer cancel_ptr;

    Context():body(nullptr) {}

    /* virtual methods from class Lease */
    void ReleaseWas(gcc_unused bool reuse) override {
        kill(process.pid, SIGTERM);

        process.Close();
    }

    void ReleaseWasStop(gcc_unused uint64_t input_received) override {
        ReleaseWas(false);
    }

    /* virtual methods from class HttpResponseHandler */
    void OnHttpResponse(http_status_t status, StringMap &&headers,
                        UnusedIstreamPtr body) noexcept override;
    void OnHttpError(std::exception_ptr ep) noexcept override;
};

/*
 * SinkFdHandler
 *
 */

static void
my_sink_fd_input_eof(void *ctx)
{
    auto &c = *(Context *)ctx;

    c.body = nullptr;
}

static void
my_sink_fd_input_error(std::exception_ptr ep, void *ctx)
{
    auto &c = *(Context *)ctx;

    PrintException(ep);

    c.body = nullptr;
    c.error = true;
}

static bool
my_sink_fd_send_error(int error, void *ctx)
{
    auto &c = *(Context *)ctx;

    fprintf(stderr, "%s\n", strerror(error));

    c.body = nullptr;
    c.error = true;

    return true;
}

static constexpr SinkFdHandler my_sink_fd_handler = {
    .input_eof = my_sink_fd_input_eof,
    .input_error = my_sink_fd_input_error,
    .send_error = my_sink_fd_send_error,
};

/*
 * http_response_handler
 *
 */

void
Context::OnHttpResponse(http_status_t status,
                        gcc_unused StringMap &&headers,
                        UnusedIstreamPtr _body) noexcept
{
    fprintf(stderr, "status: %s\n", http_status_to_string(status));

    if (_body) {
        struct pool &pool = root_pool;
        body = sink_fd_new(event_loop, pool,
                           std::move(_body),
                           FileDescriptor(STDOUT_FILENO),
                           guess_fd_type(STDOUT_FILENO),
                           my_sink_fd_handler, this);
        sink_fd_read(body);
    }
}

void
Context::OnHttpError(std::exception_ptr ep) noexcept
{
    PrintException(ep);

    error = true;
}

static Istream *
request_body(EventLoop &event_loop, struct pool &pool)
{
    struct stat st;
    return fstat(0, &st) == 0 && S_ISREG(st.st_mode)
        ? istream_file_fd_new(event_loop, pool,
                              "/dev/stdin", UniqueFileDescriptor(STDIN_FILENO),
                              FdType::FD_FILE, -1)
        : nullptr;
}

int
main(int argc, char **argv)
try {
    SetLogLevel(5);

    StaticArray<const char *, 64> params;

    if (argc < 3) {
        fprintf(stderr, "Usage: run_was PATH URI [--parameter a=b ...]\n");
        return EXIT_FAILURE;
    }

    const char *uri = argv[2];

    for (int i = 3; i < argc;) {
        if (strcmp(argv[i], "--parameter") == 0 ||
            strcmp(argv[i], "-p") == 0) {
            ++i;
            if (i >= argc)
                throw std::runtime_error("Parameter value missing");

            if (params.full())
                throw std::runtime_error("Too many parameters");

            params.push_back(argv[i++]);
        } else
            throw std::runtime_error("Unrecognized parameter");
    }

    direct_global_init();

    SpawnConfig spawn_config;

    const ScopeFbPoolInit fb_pool_init;

    ChildOptions child_options;

    Context context;
    ChildProcessRegistry child_process_registry(context.event_loop);
    child_process_registry.SetVolatile();
    LocalSpawnService spawn_service(spawn_config, child_process_registry);

    context.process = was_launch(spawn_service, "was",
                                 argv[1], nullptr,
                                 child_options, {}, nullptr);

    was_client_request(context.root_pool, context.event_loop, nullptr,
                       context.process.control,
                       context.process.input,
                       context.process.output,
                       context,
                       HTTP_METHOD_GET, uri,
                       nullptr,
                       nullptr, nullptr,
                       *strmap_new(context.root_pool),
                       UnusedIstreamPtr(request_body(context.event_loop,
                                                     context.root_pool)),
                       { (const char *const*)params.raw(), params.size() },
                       context, context.cancel_ptr);

    context.event_loop.Dispatch();

    return context.error;
} catch (const std::exception &e) {
    PrintException(e);
    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_LOG_SUM_EXP_SIGNED_HPP
#define STAN_MATH_PRIM_FUN_LOG_SUM_EXP_SIGNED_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/log1p_exp.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {

template <typename T1, typename T2,
          require_all_stan_scalar_t<T1, T2>* = nullptr>
inline std::tuple<return_type_t<T1, T2>, int>
  log_sum_exp_signed(const T1& a, int a_sign, const T2& b, int b_sign) {
  if (a_sign == b_sign) {
    return std::make_tuple(log_sum_exp(a, b), a_sign);
  }
  bool a_larger = (value_of_rec(a) > value_of_rec(b));
  return std::make_tuple(
    a_larger ? log_diff_exp(a, b) : log_diff_exp(b, a),
    a_larger ? a_sign : b_sign);
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>Update doc<commit_after>#ifndef STAN_MATH_PRIM_FUN_LOG_SUM_EXP_SIGNED_HPP
#define STAN_MATH_PRIM_FUN_LOG_SUM_EXP_SIGNED_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/fun/constants.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/log1p_exp.hpp>
#include <cmath>
#include <vector>

namespace stan {
namespace math {

/**
 * Calculates the log sum of exponentials without overflow,
 * accounting for the signs of the inputs
 *
 * @tparam T1 type of the first variable
 * @tparam T2 type of the second variable
 * @param a the first variable
 * @param a_sign sign of the first variable
 * @param b the second variable
 * @param b_sign sign of the second variable
 */
template <typename T1, typename T2,
          require_all_stan_scalar_t<T1, T2>* = nullptr>
inline std::tuple<return_type_t<T1, T2>, int>
  log_sum_exp_signed(const T1& a, int a_sign, const T2& b, int b_sign) {
  if (a_sign == b_sign) {
    return std::make_tuple(log_sum_exp(a, b), a_sign);
  }
  bool a_larger = (a > b);
  return std::make_tuple(
    a_larger ? log_diff_exp(a, b) : log_diff_exp(b, a),
    a_larger ? a_sign : b_sign);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#include <stan/math/prim/scal.hpp>
#include <test/unit/util.hpp>
#include <gtest/gtest.h>
#include <limits>

TEST(prob_transform, locscale) {
  EXPECT_FLOAT_EQ(2.0 - 5.0 * 1.0,
                  stan::math::locscale_constrain(-1.0, 2.0, 5.0));

  EXPECT_FLOAT_EQ(1.7, stan::math::locscale_constrain(
                           1.7, 0,
                           1));
}
TEST(prob_transform, locscale_j) {
  double lp = -17.0;
  double L = 2.0;
  double U = 5.0;
  double x = -1.0;
  EXPECT_FLOAT_EQ(L +  U * x,
                  stan::math::locscale_constrain(x, L, U, lp));
  EXPECT_FLOAT_EQ(-17.0 + log(U),
                  lp);

  double lp1 = -12.9;
  EXPECT_FLOAT_EQ(1.7, stan::math::locscale_constrain(
                           1.7, 0, 1, lp1));
  EXPECT_FLOAT_EQ(-12.9, lp1);
}
TEST(ProbTransform, locscaleException) {
  using stan::math::locscale_constrain;
  EXPECT_THROW(locscale_constrain(5.0, 1.0, 0.0), std::domain_error);
  EXPECT_NO_THROW(locscale_constrain(5.0, 1.0, 0.01));
  double lp = 12;
  EXPECT_THROW(locscale_constrain(5.0, 1.0, 0.0, lp), std::domain_error);
  EXPECT_NO_THROW(locscale_constrain(5.0, 1.0, 0.01, lp));
}
TEST(prob_transform, locscale_f) {
  double L = -10.0;
  double U = 27.0;
  double y = 3.0;
  EXPECT_FLOAT_EQ(y,
                  stan::math::locscale_constrain(
                    stan::math::locscale_free(y, L, U), L, U));
  EXPECT_FLOAT_EQ(y,
                  stan::math::locscale_free(
                    stan::math::locscale_constrain(y, L, U), L, U));
  L = 0.0;
  U = 1.0;
  y = 3.0;
  EXPECT_FLOAT_EQ(y,
                  stan::math::locscale_constrain(
                    stan::math::locscale_free(y, L, U), L, U));
  EXPECT_FLOAT_EQ(y,
                  stan::math::locscale_free(
                    stan::math::locscale_constrain(y, L, U), L, U));
}
TEST(prob_transform, locscale_f_exception) {
  double L = -10.0;
  double U = -27.0;
  EXPECT_THROW(stan::math::locscale_free(L - 0.01, L, U), std::domain_error);
}
<commit_msg>[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (tags/RELEASE_500/final)<commit_after>#include <stan/math/prim/scal.hpp>
#include <test/unit/util.hpp>
#include <gtest/gtest.h>
#include <limits>

TEST(prob_transform, locscale) {
  EXPECT_FLOAT_EQ(2.0 - 5.0 * 1.0,
                  stan::math::locscale_constrain(-1.0, 2.0, 5.0));

  EXPECT_FLOAT_EQ(1.7, stan::math::locscale_constrain(1.7, 0, 1));
}
TEST(prob_transform, locscale_j) {
  double lp = -17.0;
  double L = 2.0;
  double U = 5.0;
  double x = -1.0;
  EXPECT_FLOAT_EQ(L + U * x, stan::math::locscale_constrain(x, L, U, lp));
  EXPECT_FLOAT_EQ(-17.0 + log(U), lp);

  double lp1 = -12.9;
  EXPECT_FLOAT_EQ(1.7, stan::math::locscale_constrain(1.7, 0, 1, lp1));
  EXPECT_FLOAT_EQ(-12.9, lp1);
}
TEST(ProbTransform, locscaleException) {
  using stan::math::locscale_constrain;
  EXPECT_THROW(locscale_constrain(5.0, 1.0, 0.0), std::domain_error);
  EXPECT_NO_THROW(locscale_constrain(5.0, 1.0, 0.01));
  double lp = 12;
  EXPECT_THROW(locscale_constrain(5.0, 1.0, 0.0, lp), std::domain_error);
  EXPECT_NO_THROW(locscale_constrain(5.0, 1.0, 0.01, lp));
}
TEST(prob_transform, locscale_f) {
  double L = -10.0;
  double U = 27.0;
  double y = 3.0;
  EXPECT_FLOAT_EQ(y, stan::math::locscale_constrain(
                         stan::math::locscale_free(y, L, U), L, U));
  EXPECT_FLOAT_EQ(y, stan::math::locscale_free(
                         stan::math::locscale_constrain(y, L, U), L, U));
  L = 0.0;
  U = 1.0;
  y = 3.0;
  EXPECT_FLOAT_EQ(y, stan::math::locscale_constrain(
                         stan::math::locscale_free(y, L, U), L, U));
  EXPECT_FLOAT_EQ(y, stan::math::locscale_free(
                         stan::math::locscale_constrain(y, L, U), L, U));
}
TEST(prob_transform, locscale_f_exception) {
  double L = -10.0;
  double U = -27.0;
  EXPECT_THROW(stan::math::locscale_free(L - 0.01, L, U), std::domain_error);
}
<|endoftext|>


<commit_before>#include <limits.h>
#include <iostream>
#include <fstream>
#include <set>
#include <utility>
#include "pt.h"
#include "species.h"
#include "stratum.h"
#include "forest.h"
#include "location.h"
#include "ffm_io.h"
#include "layer.h"
#include "ffm_settings.h"
#include "ffm_util.h"

using namespace ffm_settings;
using std::vector;
using std::set;
using std::cout;
using std::endl;

void process(std::string inPath, std::ostream &outputStream, bool paramsFlag) {

  std::pair<Results::OutputLevelType, int> prelimPars = prelimParseInputTextFile(inPath);

  Results::OutputLevelType outputLevel = std::get<0>(prelimPars);
  int numIter = std::get<1>(prelimPars);

  bool monteCarlo = (outputLevel == Results::MONTE_CARLO);

  if (!monteCarlo) {
    Location loc = parseInputTextFile(inPath, false);

    if (paramsFlag)
      outputStream << loc.printToString() << endl;

    Results res = loc.results();

    outputStream << res.printToString(outputLevel) << endl;
  }
  else {
    for (int i = 0; i < numIter; ) {
      Location loc = parseInputTextFile(inPath, true);

      if (!loc.empty()) {
        if (i == 0) outputStream << printMonteCarloHeader(loc);

        Results res = loc.results();

        outputStream << printMonteCarloInputs(loc);
        outputStream << printMonteCarloResults(res) << endl;

        i++ ;
      }
    }
  }

}

int main(int argc, char *argv[]) {
  std::string usage("usage: ffm input_file [output_file] [-p]");

  if (argc < 2) {
    cout << usage << endl;
    return 0;
  }

  // collect the inPath and the optional outPath and flag arguments
  bool paramsFlag;
  std::string flag_str("-p");
  std::string inPath;
  std::string outPath;

  for (int i = 1; i < argc; i++) {
    std::string arg( argv[i] );

    if (arg.compare(0, flag_str.size(), flag_str) == 0)
      paramsFlag = true;
    else if (inPath.empty())
      inPath = arg;
    else if (outPath.empty())
      outPath = arg;
  }

  if (inPath.empty()) {
    cout << usage << endl;
    return 0;
  }

  std::ostream* fp = &cout;
  std::ofstream fout;
  if( !outPath.empty()) {
    fout.open(outPath);
    fp = &fout;
  }

  process(inPath, *fp, paramsFlag);
  if (!outPath.empty()) fout.close();

  return 0;
}

<commit_msg>Added -d command line flag. When this is supplied, and it is a monte-carlo run, the program writes the current generated parameters to the file debug_mc_params.csv before processing that iteration.<commit_after>#include <limits.h>
#include <iostream>
#include <fstream>
#include <set>
#include <utility>
#include "pt.h"
#include "species.h"
#include "stratum.h"
#include "forest.h"
#include "location.h"
#include "ffm_io.h"
#include "layer.h"
#include "ffm_settings.h"
#include "ffm_util.h"

using namespace ffm_settings;
using std::vector;
using std::set;
using std::cout;
using std::endl;

void process(std::string inPath, std::ostream &outputStream, bool paramsFlag, bool debugFlag) {

  std::pair<Results::OutputLevelType, int> prelimPars = prelimParseInputTextFile(inPath);

  Results::OutputLevelType outputLevel = std::get<0>(prelimPars);
  int numIter = std::get<1>(prelimPars);

  bool monteCarlo = (outputLevel == Results::MONTE_CARLO);

  if (!monteCarlo) {
    Location loc = parseInputTextFile(inPath, false);

    if (paramsFlag)
      outputStream << loc.printToString() << endl;

    Results res = loc.results();

    outputStream << res.printToString(outputLevel) << endl;
  }
  else {
    for (int i = 0; i < numIter; ) {
      Location loc = parseInputTextFile(inPath, true);

      if (!loc.empty()) {
        if (i == 0) outputStream << printMonteCarloHeader(loc);

        Results res = loc.results();

        outputStream << printMonteCarloInputs(loc);

        if (debugFlag) {
          std::ofstream debugstrm("debug_mc_params.csv", std::ofstream::out);
          debugstrm << printMonteCarloHeader(loc);
          debugstrm << printMonteCarloInputs(loc);
          debugstrm.close();
        }

        outputStream << printMonteCarloResults(res) << endl;

        i++ ;
      }
    }
  }

}

int main(int argc, char *argv[]) {
  std::string usage("usage: ffm input_file [output_file] [-p] [-d]");

  if (argc < 2) {
    cout << usage << endl;
    return 0;
  }

  // collect the inPath and the optional outPath and flag arguments
  bool paramsFlag = false;
  bool debugFlag = false;
  std::string params_flag_str("-p");
  std::string debug_flag_str("-d");
  std::string inPath;
  std::string outPath;

  for (int i = 1; i < argc; i++) {
    std::string arg( argv[i] );

    if (arg.compare(0, params_flag_str.size(), params_flag_str) == 0)
      paramsFlag = true;
    else if (arg.compare(0, debug_flag_str.size(), debug_flag_str) == 0)
      debugFlag = true;
    else if (inPath.empty())
      inPath = arg;
    else if (outPath.empty())
      outPath = arg;
  }

  if (inPath.empty()) {
    cout << usage << endl;
    return 0;
  }

  std::ostream* fp = &cout;
  std::ofstream fout;
  if( !outPath.empty()) {
    fout.open(outPath);
    fp = &fout;
  }

  process(inPath, *fp, paramsFlag, debugFlag);
  if (!outPath.empty()) fout.close();

  return 0;
}

<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"

#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <poll.h>
#include <stdio.h>
#include <unistd.h>

#include <cmath>
#include <limits>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/device_util_linux.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"

namespace {

const int kMaxTrackingId = 0xffff;  // TRKID_MAX in kernel.

struct TouchCalibration {
  int bezel_left;
  int bezel_right;
  int bezel_top;
  int bezel_bottom;
};

void GetTouchCalibration(TouchCalibration* cal) {
  std::vector<std::string> parts;
  if (Tokenize(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
                   switches::kTouchCalibration),
               ",", &parts) >= 4) {
    if (!base::StringToInt(parts[0], &cal->bezel_left))
      LOG(ERROR) << "Incorrect left border calibration value passed.";
    if (!base::StringToInt(parts[1], &cal->bezel_right))
      LOG(ERROR) << "Incorrect right border calibration value passed.";
    if (!base::StringToInt(parts[2], &cal->bezel_top))
      LOG(ERROR) << "Incorrect top border calibration value passed.";
    if (!base::StringToInt(parts[3], &cal->bezel_bottom))
      LOG(ERROR) << "Incorrect bottom border calibration value passed.";
  }
}

int32_t AbsCodeToMtCode(int32_t code) {
  switch (code) {
    case ABS_X:
      return ABS_MT_POSITION_X;
    case ABS_Y:
      return ABS_MT_POSITION_Y;
    case ABS_PRESSURE:
      return ABS_MT_PRESSURE;
    case ABS_DISTANCE:
      return ABS_MT_DISTANCE;
    default:
      return -1;
  }
}

}  // namespace

namespace ui {

TouchEventConverterEvdev::TouchEventConverterEvdev(
    int fd,
    base::FilePath path,
    int id,
    InputDeviceType type,
    const EventDeviceInfo& devinfo,
    DeviceEventDispatcherEvdev* dispatcher)
    : EventConverterEvdev(fd,
                          path,
                          id,
                          type,
                          devinfo.name(),
                          devinfo.vendor_id(),
                          devinfo.product_id()),
      dispatcher_(dispatcher),
      syn_dropped_(false),
      has_mt_(false),
      touch_points_(0),
      next_tracking_id_(0),
      current_slot_(0) {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kExtraTouchNoiseFiltering)) {
    touch_noise_finder_.reset(new TouchNoiseFinder);
  }
}

TouchEventConverterEvdev::~TouchEventConverterEvdev() {
  Stop();
  close(fd_);
}

void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
  has_mt_ = info.HasMultitouch();

  if (has_mt_) {
    pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE);
    pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE);
    x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X);
    x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1;
    y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
    y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
    touch_points_ =
        std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, kNumTouchEvdevSlots);
    current_slot_ = info.GetAbsValue(ABS_MT_SLOT);
  } else {
    pressure_min_ = info.GetAbsMinimum(ABS_PRESSURE);
    pressure_max_ = info.GetAbsMaximum(ABS_PRESSURE);
    x_min_tuxels_ = info.GetAbsMinimum(ABS_X);
    x_num_tuxels_ = info.GetAbsMaximum(ABS_X) - x_min_tuxels_ + 1;
    y_min_tuxels_ = info.GetAbsMinimum(ABS_Y);
    y_num_tuxels_ = info.GetAbsMaximum(ABS_Y) - y_min_tuxels_ + 1;
    touch_points_ = 1;
    current_slot_ = 0;
  }

  // Apply --touch-calibration.
  if (type() == INPUT_DEVICE_INTERNAL) {
    TouchCalibration cal = {};
    GetTouchCalibration(&cal);
    x_min_tuxels_ += cal.bezel_left;
    x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
    y_min_tuxels_ += cal.bezel_top;
    y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;

    VLOG(1) << "applying touch calibration: "
            << base::StringPrintf("[%d, %d, %d, %d]", cal.bezel_left,
                                  cal.bezel_right, cal.bezel_top,
                                  cal.bezel_bottom);
  }

  events_.resize(touch_points_);

  if (has_mt_) {
    for (size_t i = 0; i < events_.size(); ++i) {
      events_[i].x = info.GetAbsMtSlotValue(ABS_MT_POSITION_X, i);
      events_[i].y = info.GetAbsMtSlotValue(ABS_MT_POSITION_Y, i);
      events_[i].tracking_id = info.GetAbsMtSlotValue(ABS_MT_TRACKING_ID, i);
      events_[i].touching = (events_[i].tracking_id >= 0);
      events_[i].slot = i;

      // Dirty the slot so we'll update the consumer at the first opportunity.
      // We can't dispatch here as this is currently called on the worker pool.
      // TODO(spang): Move initialization off worker pool.
      events_[i].altered = true;

      // Optional bits.
      events_[i].radius_x =
          info.GetAbsMtSlotValueWithDefault(ABS_MT_TOUCH_MAJOR, i, 0) / 2.0f;
      events_[i].radius_y =
          info.GetAbsMtSlotValueWithDefault(ABS_MT_TOUCH_MINOR, i, 0) / 2.0f;
      events_[i].pressure =
          ScalePressure(info.GetAbsMtSlotValue(ABS_MT_PRESSURE, i));
    }
  } else {
    // TODO(spang): Add key state to EventDeviceInfo to allow initial contact.
    events_[0].x = 0;
    events_[0].y = 0;
    events_[0].tracking_id = -1;
    events_[0].touching = false;
    events_[0].slot = 0;
    events_[0].radius_x = 0;
    events_[0].radius_y = 0;
    events_[0].pressure = 0;
  }
}

bool TouchEventConverterEvdev::Reinitialize() {
  EventDeviceInfo info;
  if (info.Initialize(fd_)) {
    Initialize(info);
    return true;
  }
  return false;
}

bool TouchEventConverterEvdev::HasTouchscreen() const {
  return true;
}

gfx::Size TouchEventConverterEvdev::GetTouchscreenSize() const {
  return gfx::Size(x_num_tuxels_, y_num_tuxels_);
}

int TouchEventConverterEvdev::GetTouchPoints() const {
  return touch_points_;
}

void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
  input_event inputs[kNumTouchEvdevSlots * 6 + 1];
  ssize_t read_size = read(fd, inputs, sizeof(inputs));
  if (read_size < 0) {
    if (errno == EINTR || errno == EAGAIN)
      return;
    if (errno != ENODEV)
      PLOG(ERROR) << "error reading device " << path_.value();
    Stop();
    return;
  }

  if (ignore_events_)
    return;

  for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
    if (!has_mt_) {
      // Emulate the device as an MT device with only 1 slot by inserting extra
      // MT protocol events in the stream.
      EmulateMultitouchEvent(inputs[i]);
    }

    ProcessMultitouchEvent(inputs[i]);
  }
}

void TouchEventConverterEvdev::ProcessMultitouchEvent(
    const input_event& input) {
  if (input.type == EV_SYN) {
    ProcessSyn(input);
  } else if (syn_dropped_) {
    // Do nothing. This branch indicates we have lost sync with the driver.
  } else if (input.type == EV_ABS) {
    if (events_.size() <= current_slot_) {
      LOG(ERROR) << "current_slot_ (" << current_slot_
                 << ") >= events_.size() (" << events_.size() << ")";
    } else {
      ProcessAbs(input);
    }
  } else if (input.type == EV_KEY) {
    ProcessKey(input);
  } else {
    NOTIMPLEMENTED() << "invalid type: " << input.type;
  }
}

void TouchEventConverterEvdev::EmulateMultitouchEvent(
    const input_event& event) {
  input_event emulated_event = event;

  if (event.type == EV_ABS) {
    emulated_event.code = AbsCodeToMtCode(event.code);
    if (emulated_event.code >= 0)
      ProcessMultitouchEvent(emulated_event);
  } else if (event.type == EV_KEY && event.code == BTN_TOUCH) {
    emulated_event.type = EV_ABS;
    emulated_event.code = ABS_MT_TRACKING_ID;
    emulated_event.value = event.value ? NextTrackingId() : -1;
    ProcessMultitouchEvent(emulated_event);
  }
}

void TouchEventConverterEvdev::ProcessKey(const input_event& input) {
  switch (input.code) {
    case BTN_TOUCH:
      break;
    default:
      NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
  }
}

void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
  switch (input.code) {
    case ABS_MT_TOUCH_MAJOR:
      // TODO(spang): If we have all of major, minor, and orientation,
      // we can scale the ellipse correctly. However on the Pixel we get
      // neither minor nor orientation, so this is all we can do.
      events_[current_slot_].radius_x = input.value / 2.0f;
      break;
    case ABS_MT_TOUCH_MINOR:
      events_[current_slot_].radius_y = input.value / 2.0f;
      break;
    case ABS_MT_POSITION_X:
      events_[current_slot_].x = input.value;
      break;
    case ABS_MT_POSITION_Y:
      events_[current_slot_].y = input.value;
      break;
    case ABS_MT_TRACKING_ID:
      if (input.value < 0) {
        events_[current_slot_].touching = false;
      } else {
        events_[current_slot_].touching = true;
        events_[current_slot_].cancelled = false;
      }
      events_[current_slot_].tracking_id = input.value;
      break;
    case ABS_MT_PRESSURE:
      events_[current_slot_].pressure = ScalePressure(input.value);
      break;
    case ABS_MT_SLOT:
      if (input.value >= 0 &&
          static_cast<size_t>(input.value) < events_.size()) {
        current_slot_ = input.value;
      } else {
        LOG(ERROR) << "invalid touch event index: " << input.value;
        return;
      }
      break;
    default:
      DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
      return;
  }
  events_[current_slot_].altered = true;
}

void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
  switch (input.code) {
    case SYN_REPORT:
      if (syn_dropped_) {
        // Have to re-initialize.
        if (Reinitialize()) {
          syn_dropped_ = false;
        } else {
          LOG(ERROR) << "failed to re-initialize device info";
        }
      } else {
        ReportEvents(EventConverterEvdev::TimeDeltaFromInputEvent(input));
      }
      break;
    case SYN_DROPPED:
      // Some buffer has overrun. We ignore all events up to and
      // including the next SYN_REPORT.
      syn_dropped_ = true;
      break;
    default:
      NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
  }
}

EventType TouchEventConverterEvdev::GetEventTypeForTouch(
    const InProgressTouchEvdev& touch) {
  if (touch.cancelled)
    return ET_UNKNOWN;

  if (touch_noise_finder_ && touch_noise_finder_->SlotHasNoise(touch.slot)) {
    if (touch.touching && !touch.was_touching)
      return ET_UNKNOWN;
    return ET_TOUCH_CANCELLED;
  }

  if (touch.touching)
    return touch.was_touching ? ET_TOUCH_MOVED : ET_TOUCH_PRESSED;
  return touch.was_touching ? ET_TOUCH_RELEASED : ET_UNKNOWN;
}

void TouchEventConverterEvdev::ReportEvent(const InProgressTouchEvdev& event,
                                           EventType event_type,
                                           const base::TimeDelta& timestamp) {
  dispatcher_->DispatchTouchEvent(TouchEventParams(
      input_device_.id, event.slot, event_type, gfx::PointF(event.x, event.y),
      gfx::Vector2dF(event.radius_x, event.radius_y), event.pressure,
      timestamp));
}

void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
  if (touch_noise_finder_)
    touch_noise_finder_->HandleTouches(events_, delta);

  for (size_t i = 0; i < events_.size(); i++) {
    InProgressTouchEvdev* event = &events_[i];
    if (!event->altered)
      continue;

    EventType event_type = GetEventTypeForTouch(*event);
    if (event_type == ET_UNKNOWN || event_type == ET_TOUCH_CANCELLED)
      event->cancelled = true;

    if (event_type != ET_UNKNOWN)
      ReportEvent(*event, event_type, delta);

    event->was_touching = event->touching;
    event->altered = false;
  }
}

float TouchEventConverterEvdev::ScalePressure(int32_t value) {
  float pressure = value - pressure_min_;
  if (pressure_max_ - pressure_min_)
    pressure /= pressure_max_ - pressure_min_;
  return pressure;
}

int TouchEventConverterEvdev::NextTrackingId() {
  return next_tracking_id_++ & kMaxTrackingId;
}

}  // namespace ui
<commit_msg>ozone: evdev: Always supply a default value for touch axes<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/ozone/evdev/touch_event_converter_evdev.h"

#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <poll.h>
#include <stdio.h>
#include <unistd.h>

#include <cmath>
#include <limits>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/device_util_linux.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_switches.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/touch_evdev_types.h"
#include "ui/events/ozone/evdev/touch_noise/touch_noise_finder.h"

namespace {

const int kMaxTrackingId = 0xffff;  // TRKID_MAX in kernel.

struct TouchCalibration {
  int bezel_left;
  int bezel_right;
  int bezel_top;
  int bezel_bottom;
};

void GetTouchCalibration(TouchCalibration* cal) {
  std::vector<std::string> parts;
  if (Tokenize(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
                   switches::kTouchCalibration),
               ",", &parts) >= 4) {
    if (!base::StringToInt(parts[0], &cal->bezel_left))
      LOG(ERROR) << "Incorrect left border calibration value passed.";
    if (!base::StringToInt(parts[1], &cal->bezel_right))
      LOG(ERROR) << "Incorrect right border calibration value passed.";
    if (!base::StringToInt(parts[2], &cal->bezel_top))
      LOG(ERROR) << "Incorrect top border calibration value passed.";
    if (!base::StringToInt(parts[3], &cal->bezel_bottom))
      LOG(ERROR) << "Incorrect bottom border calibration value passed.";
  }
}

int32_t AbsCodeToMtCode(int32_t code) {
  switch (code) {
    case ABS_X:
      return ABS_MT_POSITION_X;
    case ABS_Y:
      return ABS_MT_POSITION_Y;
    case ABS_PRESSURE:
      return ABS_MT_PRESSURE;
    case ABS_DISTANCE:
      return ABS_MT_DISTANCE;
    default:
      return -1;
  }
}

}  // namespace

namespace ui {

TouchEventConverterEvdev::TouchEventConverterEvdev(
    int fd,
    base::FilePath path,
    int id,
    InputDeviceType type,
    const EventDeviceInfo& devinfo,
    DeviceEventDispatcherEvdev* dispatcher)
    : EventConverterEvdev(fd,
                          path,
                          id,
                          type,
                          devinfo.name(),
                          devinfo.vendor_id(),
                          devinfo.product_id()),
      dispatcher_(dispatcher),
      syn_dropped_(false),
      has_mt_(false),
      touch_points_(0),
      next_tracking_id_(0),
      current_slot_(0) {
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kExtraTouchNoiseFiltering)) {
    touch_noise_finder_.reset(new TouchNoiseFinder);
  }
}

TouchEventConverterEvdev::~TouchEventConverterEvdev() {
  Stop();
  close(fd_);
}

void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
  has_mt_ = info.HasMultitouch();

  if (has_mt_) {
    pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE);
    pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE);
    x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X);
    x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1;
    y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
    y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
    touch_points_ =
        std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, kNumTouchEvdevSlots);
    current_slot_ = info.GetAbsValue(ABS_MT_SLOT);
  } else {
    pressure_min_ = info.GetAbsMinimum(ABS_PRESSURE);
    pressure_max_ = info.GetAbsMaximum(ABS_PRESSURE);
    x_min_tuxels_ = info.GetAbsMinimum(ABS_X);
    x_num_tuxels_ = info.GetAbsMaximum(ABS_X) - x_min_tuxels_ + 1;
    y_min_tuxels_ = info.GetAbsMinimum(ABS_Y);
    y_num_tuxels_ = info.GetAbsMaximum(ABS_Y) - y_min_tuxels_ + 1;
    touch_points_ = 1;
    current_slot_ = 0;
  }

  // Apply --touch-calibration.
  if (type() == INPUT_DEVICE_INTERNAL) {
    TouchCalibration cal = {};
    GetTouchCalibration(&cal);
    x_min_tuxels_ += cal.bezel_left;
    x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
    y_min_tuxels_ += cal.bezel_top;
    y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;

    VLOG(1) << "applying touch calibration: "
            << base::StringPrintf("[%d, %d, %d, %d]", cal.bezel_left,
                                  cal.bezel_right, cal.bezel_top,
                                  cal.bezel_bottom);
  }

  events_.resize(touch_points_);

  if (has_mt_) {
    for (size_t i = 0; i < events_.size(); ++i) {
      events_[i].x = info.GetAbsMtSlotValueWithDefault(ABS_MT_POSITION_X, i, 0);
      events_[i].y = info.GetAbsMtSlotValueWithDefault(ABS_MT_POSITION_Y, i, 0);
      events_[i].tracking_id =
          info.GetAbsMtSlotValueWithDefault(ABS_MT_TRACKING_ID, i, -1);
      events_[i].touching = (events_[i].tracking_id >= 0);
      events_[i].slot = i;

      // Dirty the slot so we'll update the consumer at the first opportunity.
      // We can't dispatch here as this is currently called on the worker pool.
      // TODO(spang): Move initialization off worker pool.
      events_[i].altered = true;

      // Optional bits.
      events_[i].radius_x =
          info.GetAbsMtSlotValueWithDefault(ABS_MT_TOUCH_MAJOR, i, 0) / 2.0f;
      events_[i].radius_y =
          info.GetAbsMtSlotValueWithDefault(ABS_MT_TOUCH_MINOR, i, 0) / 2.0f;
      events_[i].pressure = ScalePressure(
          info.GetAbsMtSlotValueWithDefault(ABS_MT_PRESSURE, i, 0));
    }
  } else {
    // TODO(spang): Add key state to EventDeviceInfo to allow initial contact.
    events_[0].x = 0;
    events_[0].y = 0;
    events_[0].tracking_id = -1;
    events_[0].touching = false;
    events_[0].slot = 0;
    events_[0].radius_x = 0;
    events_[0].radius_y = 0;
    events_[0].pressure = 0;
  }
}

bool TouchEventConverterEvdev::Reinitialize() {
  EventDeviceInfo info;
  if (info.Initialize(fd_)) {
    Initialize(info);
    return true;
  }
  return false;
}

bool TouchEventConverterEvdev::HasTouchscreen() const {
  return true;
}

gfx::Size TouchEventConverterEvdev::GetTouchscreenSize() const {
  return gfx::Size(x_num_tuxels_, y_num_tuxels_);
}

int TouchEventConverterEvdev::GetTouchPoints() const {
  return touch_points_;
}

void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
  input_event inputs[kNumTouchEvdevSlots * 6 + 1];
  ssize_t read_size = read(fd, inputs, sizeof(inputs));
  if (read_size < 0) {
    if (errno == EINTR || errno == EAGAIN)
      return;
    if (errno != ENODEV)
      PLOG(ERROR) << "error reading device " << path_.value();
    Stop();
    return;
  }

  if (ignore_events_)
    return;

  for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
    if (!has_mt_) {
      // Emulate the device as an MT device with only 1 slot by inserting extra
      // MT protocol events in the stream.
      EmulateMultitouchEvent(inputs[i]);
    }

    ProcessMultitouchEvent(inputs[i]);
  }
}

void TouchEventConverterEvdev::ProcessMultitouchEvent(
    const input_event& input) {
  if (input.type == EV_SYN) {
    ProcessSyn(input);
  } else if (syn_dropped_) {
    // Do nothing. This branch indicates we have lost sync with the driver.
  } else if (input.type == EV_ABS) {
    if (events_.size() <= current_slot_) {
      LOG(ERROR) << "current_slot_ (" << current_slot_
                 << ") >= events_.size() (" << events_.size() << ")";
    } else {
      ProcessAbs(input);
    }
  } else if (input.type == EV_KEY) {
    ProcessKey(input);
  } else {
    NOTIMPLEMENTED() << "invalid type: " << input.type;
  }
}

void TouchEventConverterEvdev::EmulateMultitouchEvent(
    const input_event& event) {
  input_event emulated_event = event;

  if (event.type == EV_ABS) {
    emulated_event.code = AbsCodeToMtCode(event.code);
    if (emulated_event.code >= 0)
      ProcessMultitouchEvent(emulated_event);
  } else if (event.type == EV_KEY && event.code == BTN_TOUCH) {
    emulated_event.type = EV_ABS;
    emulated_event.code = ABS_MT_TRACKING_ID;
    emulated_event.value = event.value ? NextTrackingId() : -1;
    ProcessMultitouchEvent(emulated_event);
  }
}

void TouchEventConverterEvdev::ProcessKey(const input_event& input) {
  switch (input.code) {
    case BTN_TOUCH:
      break;
    default:
      NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
  }
}

void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
  switch (input.code) {
    case ABS_MT_TOUCH_MAJOR:
      // TODO(spang): If we have all of major, minor, and orientation,
      // we can scale the ellipse correctly. However on the Pixel we get
      // neither minor nor orientation, so this is all we can do.
      events_[current_slot_].radius_x = input.value / 2.0f;
      break;
    case ABS_MT_TOUCH_MINOR:
      events_[current_slot_].radius_y = input.value / 2.0f;
      break;
    case ABS_MT_POSITION_X:
      events_[current_slot_].x = input.value;
      break;
    case ABS_MT_POSITION_Y:
      events_[current_slot_].y = input.value;
      break;
    case ABS_MT_TRACKING_ID:
      if (input.value < 0) {
        events_[current_slot_].touching = false;
      } else {
        events_[current_slot_].touching = true;
        events_[current_slot_].cancelled = false;
      }
      events_[current_slot_].tracking_id = input.value;
      break;
    case ABS_MT_PRESSURE:
      events_[current_slot_].pressure = ScalePressure(input.value);
      break;
    case ABS_MT_SLOT:
      if (input.value >= 0 &&
          static_cast<size_t>(input.value) < events_.size()) {
        current_slot_ = input.value;
      } else {
        LOG(ERROR) << "invalid touch event index: " << input.value;
        return;
      }
      break;
    default:
      DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
      return;
  }
  events_[current_slot_].altered = true;
}

void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
  switch (input.code) {
    case SYN_REPORT:
      if (syn_dropped_) {
        // Have to re-initialize.
        if (Reinitialize()) {
          syn_dropped_ = false;
        } else {
          LOG(ERROR) << "failed to re-initialize device info";
        }
      } else {
        ReportEvents(EventConverterEvdev::TimeDeltaFromInputEvent(input));
      }
      break;
    case SYN_DROPPED:
      // Some buffer has overrun. We ignore all events up to and
      // including the next SYN_REPORT.
      syn_dropped_ = true;
      break;
    default:
      NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
  }
}

EventType TouchEventConverterEvdev::GetEventTypeForTouch(
    const InProgressTouchEvdev& touch) {
  if (touch.cancelled)
    return ET_UNKNOWN;

  if (touch_noise_finder_ && touch_noise_finder_->SlotHasNoise(touch.slot)) {
    if (touch.touching && !touch.was_touching)
      return ET_UNKNOWN;
    return ET_TOUCH_CANCELLED;
  }

  if (touch.touching)
    return touch.was_touching ? ET_TOUCH_MOVED : ET_TOUCH_PRESSED;
  return touch.was_touching ? ET_TOUCH_RELEASED : ET_UNKNOWN;
}

void TouchEventConverterEvdev::ReportEvent(const InProgressTouchEvdev& event,
                                           EventType event_type,
                                           const base::TimeDelta& timestamp) {
  dispatcher_->DispatchTouchEvent(TouchEventParams(
      input_device_.id, event.slot, event_type, gfx::PointF(event.x, event.y),
      gfx::Vector2dF(event.radius_x, event.radius_y), event.pressure,
      timestamp));
}

void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
  if (touch_noise_finder_)
    touch_noise_finder_->HandleTouches(events_, delta);

  for (size_t i = 0; i < events_.size(); i++) {
    InProgressTouchEvdev* event = &events_[i];
    if (!event->altered)
      continue;

    EventType event_type = GetEventTypeForTouch(*event);
    if (event_type == ET_UNKNOWN || event_type == ET_TOUCH_CANCELLED)
      event->cancelled = true;

    if (event_type != ET_UNKNOWN)
      ReportEvent(*event, event_type, delta);

    event->was_touching = event->touching;
    event->altered = false;
  }
}

float TouchEventConverterEvdev::ScalePressure(int32_t value) {
  float pressure = value - pressure_min_;
  if (pressure_max_ - pressure_min_)
    pressure /= pressure_max_ - pressure_min_;
  return pressure;
}

int TouchEventConverterEvdev::NextTrackingId() {
  return next_tracking_id_++ & kMaxTrackingId;
}

}  // namespace ui
<|endoftext|>


<commit_before>
#pragma once

/**
 * AttributeModel.hpp
 * Purpose: An abstract base model for indexed attributes.
 *
 * @author Kevin A. Naudé
 * @version 1.1
 */

#include <string>
#include <vector>
#include <cstdlib>
#include <Random.hpp>

namespace kn
{

    class AttributeModel
    {
    public:
        virtual ~AttributeModel() {}

        virtual std::size_t count() const
        {
            return 0;
        }

        virtual int relation(std::size_t idA, std::size_t idB) const
        {
            return 0;
        }

        virtual double similarity(std::size_t idA, std::size_t idB) const
        {
            return (relation(idA, idB) == 0) ? 1.0 : 0.0;
        }
    };

    class NullAttributeModel : public AttributeModel {};

    template <typename T>
    class VectorAttributeModel : public AttributeModel
    {
    private:
        std::vector<T> attributes;

    public:
        VectorAttributeModel(std::vector<T> attrs)
            : attributes(attrs)
        {
        }

        virtual int relation(std::size_t idA, std::size_t idB) const
        {
            if ((idA == idB) || (attributes[idA] == attributes[idB]))
                return 0;
            else
            if (attributes[idA] < attributes[idB])
                return -1;
            else
                return +1;
        }
    };

}
<commit_msg>Improved compatibility to remove warnings.<commit_after>
#pragma once

/**
 * AttributeModel.hpp
 * Purpose: An abstract base model for indexed attributes.
 *
 * @author Kevin A. Naudé
 * @version 1.1
 */

#include <string>
#include <vector>
#include <cstdlib>
#include <Random.hpp>

namespace kn
{

    class AttributeModel
    {
    public:
        virtual ~AttributeModel() {}

        virtual std::size_t count() const
        {
            return 0;
        }

        virtual int relation(std::size_t idA, std::size_t idB) const
        {
            if (idA == idB)
                return 0;
            else
            if (idA < idB)
                return -1;
            else
                return +1;
        }

        virtual double similarity(std::size_t idA, std::size_t idB) const
        {
            return (relation(idA, idB) == 0) ? 1.0 : 0.0;
        }
    };

    class NullAttributeModel : public AttributeModel {};

    template <typename T>
    class VectorAttributeModel : public AttributeModel
    {
    private:
        std::vector<T> attributes;

    public:
        VectorAttributeModel(std::vector<T> attrs)
            : attributes(attrs)
        {
        }

        virtual int relation(std::size_t idA, std::size_t idB) const
        {
            if ((idA == idB) || (attributes[idA] == attributes[idB]))
                return 0;
            else
            if (attributes[idA] < attributes[idB])
                return -1;
            else
                return +1;
        }
    };

}
<|endoftext|>