<commit_before>/* ========================================================================= *
 *                                                                           *
 *                               OpenMesh                                    *
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openmesh.org                               *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenMesh.                                            *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * 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 COPYRIGHT HOLDER *
 * 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.              *
 *                                                                           *
 * ========================================================================= */

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS VectorT
//
//=============================================================================

// Don't parse this header file with doxygen since
// for some reason (obviously due to a bug in doxygen,
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
// macro expansion and preprocessor defines
// don't work properly.

#if (_MSC_VER >= 1900 || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
#include "Vector11T.hh"
#else
#ifndef DOXYGEN

#ifndef OPENMESH_VECTOR_HH
#define OPENMESH_VECTOR_HH

//== INCLUDES =================================================================

#include <OpenMesh/Core/System/config.h>
#include <ostream>
#include <cmath>
#include <cassert>
#include <cstring>

#if defined(__GNUC__) && defined(__SSE__)
#include <xmmintrin.h>
#endif

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== CLASS DEFINITION =========================================================

/** The N values of the template Scalar type are the only data members
    of the class VectorT<Scalar,N>. This guarantees 100% compatibility
    with arrays of type Scalar and size N, allowing us to define the
    cast operators to and from arrays and array pointers.

    In addition, this class will be specialized for Vec4f to be 16 bit
    aligned, so that aligned SSE instructions can be used on these
    vectors.
*/
template<typename Scalar, int N> class VectorDataT {
    public:
        Scalar values_[N];
};

#if defined(__GNUC__) && defined(__SSE__)

/// This specialization enables us to use aligned SSE instructions.
template<> class VectorDataT<float, 4> {
    public:
        union {
            __m128 m128;
            float values_[4];
        };
};

#endif

//== CLASS DEFINITION =========================================================

#define DIM               N
#define TEMPLATE_HEADER   template <typename Scalar, int N>
#define CLASSNAME         VectorT
#define DERIVED           VectorDataT<Scalar,N>
#define unroll(expr)      for (int i=0; i<N; ++i) expr(i)

/** \class VectorT VectorT.hh <OpenMesh/Core/Math/VectorT.hh>
    A vector is an array of \<N\> values of type \<Scalar\>.
    The actual data is stored in an VectorDataT, this class just adds
    the necessary operators.
*/
#include "VectorT_inc.hh"

#undef  DIM
#undef  TEMPLATE_HEADER
#undef  CLASSNAME
#undef  DERIVED
#undef  unroll

//== PARTIAL TEMPLATE SPECIALIZATIONS =========================================
#if OM_PARTIAL_SPECIALIZATION

#define TEMPLATE_HEADER        template <typename Scalar>
#define CLASSNAME              VectorT<Scalar,DIM>
#define DERIVED                VectorDataT<Scalar,DIM>

#define DIM                    2
#define unroll(expr)           expr(0) expr(1)
#define unroll_comb(expr, op)  expr(0) op expr(1)
#define unroll_csv(expr)       expr(0), expr(1)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    3
#define unroll(expr)           expr(0) expr(1) expr(2)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2)
#define unroll_csv(expr)       expr(0), expr(1), expr(2)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    4
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    5
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3) expr(4)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3) op expr(4)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3), expr(4)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    6
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3) expr(4) expr(5)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3) op expr(4) op expr(5)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3), expr(4), expr(5)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#undef  TEMPLATE_HEADER
#undef  CLASSNAME
#undef  DERIVED

//== FULL TEMPLATE SPECIALIZATIONS ============================================
#else

/// cross product for Vec3f
template<>
inline VectorT<float,3>
VectorT<float,3>::operator%(const VectorT<float,3>& _rhs) const
{
   return
     VectorT<float,3>(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1],
		      values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2],
		      values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]);
}

/// cross product for Vec3d
template<>
inline VectorT<double,3>
VectorT<double,3>::operator%(const VectorT<double,3>& _rhs) const
{
 return
   VectorT<double,3>(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1],
		     values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2],
		     values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]);
}

#endif

//== GLOBAL FUNCTIONS =========================================================

/// \relates OpenMesh::VectorT
/// scalar * vector
template<typename Scalar1, typename Scalar2,int N>
inline VectorT<Scalar1,N> operator*(Scalar2 _s, const VectorT<Scalar1,N> _v) {
  return _v*_s;
}

/// \relates OpenMesh::VectorT
/// symmetric version of the dot product
template<typename Scalar, int N>
inline Scalar
dot(const VectorT<Scalar,N>& _v1, const VectorT<Scalar,N>& _v2) {
  return (_v1 | _v2);
}

/// \relates OpenMesh::VectorT
/// symmetric version of the cross product
template<typename Scalar, int N>
inline VectorT<Scalar,N>
cross(const VectorT<Scalar,N>& _v1, const VectorT<Scalar,N>& _v2) {
  return (_v1 % _v2);
}

//== TYPEDEFS =================================================================

/** 1-byte signed vector */
typedef VectorT<signed char,1> Vec1c;
/** 1-byte unsigned vector */
typedef VectorT<unsigned char,1> Vec1uc;
/** 1-short signed vector */
typedef VectorT<signed short int,1> Vec1s;
/** 1-short unsigned vector */
typedef VectorT<unsigned short int,1> Vec1us;
/** 1-int signed vector */
typedef VectorT<signed int,1> Vec1i;
/** 1-int unsigned vector */
typedef VectorT<unsigned int,1> Vec1ui;
/** 1-float vector */
typedef VectorT<float,1> Vec1f;
/** 1-double vector */
typedef VectorT<double,1> Vec1d;

/** 2-byte signed vector */
typedef VectorT<signed char,2> Vec2c;
/** 2-byte unsigned vector */
typedef VectorT<unsigned char,2> Vec2uc;
/** 2-short signed vector */
typedef VectorT<signed short int,2> Vec2s;
/** 2-short unsigned vector */
typedef VectorT<unsigned short int,2> Vec2us;
/** 2-int signed vector */
typedef VectorT<signed int,2> Vec2i;
/** 2-int unsigned vector */
typedef VectorT<unsigned int,2> Vec2ui;
/** 2-float vector */
typedef VectorT<float,2> Vec2f;
/** 2-double vector */
typedef VectorT<double,2> Vec2d;

/** 3-byte signed vector */
typedef VectorT<signed char,3> Vec3c;
/** 3-byte unsigned vector */
typedef VectorT<unsigned char,3> Vec3uc;
/** 3-short signed vector */
typedef VectorT<signed short int,3> Vec3s;
/** 3-short unsigned vector */
typedef VectorT<unsigned short int,3> Vec3us;
/** 3-int signed vector */
typedef VectorT<signed int,3> Vec3i;
/** 3-int unsigned vector */
typedef VectorT<unsigned int,3> Vec3ui;
/** 3-float vector */
typedef VectorT<float,3> Vec3f;
/** 3-double vector */
typedef VectorT<double,3> Vec3d;
/** 3-bool vector */
typedef VectorT<bool,3> Vec3b;

/** 4-byte signed vector */
typedef VectorT<signed char,4> Vec4c;
/** 4-byte unsigned vector */
typedef VectorT<unsigned char,4> Vec4uc;
/** 4-short signed vector */
typedef VectorT<signed short int,4> Vec4s;
/** 4-short unsigned vector */
typedef VectorT<unsigned short int,4> Vec4us;
/** 4-int signed vector */
typedef VectorT<signed int,4> Vec4i;
/** 4-int unsigned vector */
typedef VectorT<unsigned int,4> Vec4ui;
/** 4-float vector */
typedef VectorT<float,4> Vec4f;
/** 4-double vector */
typedef VectorT<double,4> Vec4d;

/** 5-byte signed vector */
typedef VectorT<signed char, 5> Vec5c;
/** 5-byte unsigned vector */
typedef VectorT<unsigned char, 5> Vec5uc;
/** 5-short signed vector */
typedef VectorT<signed short int, 5> Vec5s;
/** 5-short unsigned vector */
typedef VectorT<unsigned short int, 5> Vec5us;
/** 5-int signed vector */
typedef VectorT<signed int, 5> Vec5i;
/** 5-int unsigned vector */
typedef VectorT<unsigned int, 5> Vec5ui;
/** 5-float vector */
typedef VectorT<float, 5> Vec5f;
/** 5-double vector */
typedef VectorT<double, 5> Vec5d;

/** 6-byte signed vector */
typedef VectorT<signed char,6> Vec6c;
/** 6-byte unsigned vector */
typedef VectorT<unsigned char,6> Vec6uc;
/** 6-short signed vector */
typedef VectorT<signed short int,6> Vec6s;
/** 6-short unsigned vector */
typedef VectorT<unsigned short int,6> Vec6us;
/** 6-int signed vector */
typedef VectorT<signed int,6> Vec6i;
/** 6-int unsigned vector */
typedef VectorT<unsigned int,6> Vec6ui;
/** 6-float vector */
typedef VectorT<float,6> Vec6f;
/** 6-double vector */
typedef VectorT<double,6> Vec6d;

//=============================================================================
} // namespace OpenMesh
//=============================================================================

#endif // OPENMESH_VECTOR_HH defined
//=============================================================================
#endif // DOXYGEN
#endif // C++11
<commit_msg>take VectorT argument by reference for non-member vector scalar multiplication (fixes #12)<commit_after>/* ========================================================================= *
 *                                                                           *
 *                               OpenMesh                                    *
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openmesh.org                               *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenMesh.                                            *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * 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 COPYRIGHT HOLDER *
 * 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.              *
 *                                                                           *
 * ========================================================================= */

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS VectorT
//
//=============================================================================

// Don't parse this header file with doxygen since
// for some reason (obviously due to a bug in doxygen,
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
// macro expansion and preprocessor defines
// don't work properly.

#if (_MSC_VER >= 1900 || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
#include "Vector11T.hh"
#else
#ifndef DOXYGEN

#ifndef OPENMESH_VECTOR_HH
#define OPENMESH_VECTOR_HH

//== INCLUDES =================================================================

#include <OpenMesh/Core/System/config.h>
#include <ostream>
#include <cmath>
#include <cassert>
#include <cstring>

#if defined(__GNUC__) && defined(__SSE__)
#include <xmmintrin.h>
#endif

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== CLASS DEFINITION =========================================================

/** The N values of the template Scalar type are the only data members
    of the class VectorT<Scalar,N>. This guarantees 100% compatibility
    with arrays of type Scalar and size N, allowing us to define the
    cast operators to and from arrays and array pointers.

    In addition, this class will be specialized for Vec4f to be 16 bit
    aligned, so that aligned SSE instructions can be used on these
    vectors.
*/
template<typename Scalar, int N> class VectorDataT {
    public:
        Scalar values_[N];
};

#if defined(__GNUC__) && defined(__SSE__)

/// This specialization enables us to use aligned SSE instructions.
template<> class VectorDataT<float, 4> {
    public:
        union {
            __m128 m128;
            float values_[4];
        };
};

#endif

//== CLASS DEFINITION =========================================================

#define DIM               N
#define TEMPLATE_HEADER   template <typename Scalar, int N>
#define CLASSNAME         VectorT
#define DERIVED           VectorDataT<Scalar,N>
#define unroll(expr)      for (int i=0; i<N; ++i) expr(i)

/** \class VectorT VectorT.hh <OpenMesh/Core/Math/VectorT.hh>
    A vector is an array of \<N\> values of type \<Scalar\>.
    The actual data is stored in an VectorDataT, this class just adds
    the necessary operators.
*/
#include "VectorT_inc.hh"

#undef  DIM
#undef  TEMPLATE_HEADER
#undef  CLASSNAME
#undef  DERIVED
#undef  unroll

//== PARTIAL TEMPLATE SPECIALIZATIONS =========================================
#if OM_PARTIAL_SPECIALIZATION

#define TEMPLATE_HEADER        template <typename Scalar>
#define CLASSNAME              VectorT<Scalar,DIM>
#define DERIVED                VectorDataT<Scalar,DIM>

#define DIM                    2
#define unroll(expr)           expr(0) expr(1)
#define unroll_comb(expr, op)  expr(0) op expr(1)
#define unroll_csv(expr)       expr(0), expr(1)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    3
#define unroll(expr)           expr(0) expr(1) expr(2)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2)
#define unroll_csv(expr)       expr(0), expr(1), expr(2)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    4
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    5
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3) expr(4)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3) op expr(4)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3), expr(4)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#define DIM                    6
#define unroll(expr)           expr(0) expr(1) expr(2) expr(3) expr(4) expr(5)
#define unroll_comb(expr, op)  expr(0) op expr(1) op expr(2) op expr(3) op expr(4) op expr(5)
#define unroll_csv(expr)       expr(0), expr(1), expr(2), expr(3), expr(4), expr(5)
#include "VectorT_inc.hh"
#undef  DIM
#undef  unroll
#undef  unroll_comb
#undef  unroll_csv

#undef  TEMPLATE_HEADER
#undef  CLASSNAME
#undef  DERIVED

//== FULL TEMPLATE SPECIALIZATIONS ============================================
#else

/// cross product for Vec3f
template<>
inline VectorT<float,3>
VectorT<float,3>::operator%(const VectorT<float,3>& _rhs) const
{
   return
     VectorT<float,3>(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1],
		      values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2],
		      values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]);
}

/// cross product for Vec3d
template<>
inline VectorT<double,3>
VectorT<double,3>::operator%(const VectorT<double,3>& _rhs) const
{
 return
   VectorT<double,3>(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1],
		     values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2],
		     values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]);
}

#endif

//== GLOBAL FUNCTIONS =========================================================

/// \relates OpenMesh::VectorT
/// scalar * vector
template<typename Scalar1, typename Scalar2,int N>
inline VectorT<Scalar1,N> operator*(Scalar2 _s, const VectorT<Scalar1,N>& _v) {
  return _v*_s;
}

/// \relates OpenMesh::VectorT
/// symmetric version of the dot product
template<typename Scalar, int N>
inline Scalar
dot(const VectorT<Scalar,N>& _v1, const VectorT<Scalar,N>& _v2) {
  return (_v1 | _v2);
}

/// \relates OpenMesh::VectorT
/// symmetric version of the cross product
template<typename Scalar, int N>
inline VectorT<Scalar,N>
cross(const VectorT<Scalar,N>& _v1, const VectorT<Scalar,N>& _v2) {
  return (_v1 % _v2);
}

//== TYPEDEFS =================================================================

/** 1-byte signed vector */
typedef VectorT<signed char,1> Vec1c;
/** 1-byte unsigned vector */
typedef VectorT<unsigned char,1> Vec1uc;
/** 1-short signed vector */
typedef VectorT<signed short int,1> Vec1s;
/** 1-short unsigned vector */
typedef VectorT<unsigned short int,1> Vec1us;
/** 1-int signed vector */
typedef VectorT<signed int,1> Vec1i;
/** 1-int unsigned vector */
typedef VectorT<unsigned int,1> Vec1ui;
/** 1-float vector */
typedef VectorT<float,1> Vec1f;
/** 1-double vector */
typedef VectorT<double,1> Vec1d;

/** 2-byte signed vector */
typedef VectorT<signed char,2> Vec2c;
/** 2-byte unsigned vector */
typedef VectorT<unsigned char,2> Vec2uc;
/** 2-short signed vector */
typedef VectorT<signed short int,2> Vec2s;
/** 2-short unsigned vector */
typedef VectorT<unsigned short int,2> Vec2us;
/** 2-int signed vector */
typedef VectorT<signed int,2> Vec2i;
/** 2-int unsigned vector */
typedef VectorT<unsigned int,2> Vec2ui;
/** 2-float vector */
typedef VectorT<float,2> Vec2f;
/** 2-double vector */
typedef VectorT<double,2> Vec2d;

/** 3-byte signed vector */
typedef VectorT<signed char,3> Vec3c;
/** 3-byte unsigned vector */
typedef VectorT<unsigned char,3> Vec3uc;
/** 3-short signed vector */
typedef VectorT<signed short int,3> Vec3s;
/** 3-short unsigned vector */
typedef VectorT<unsigned short int,3> Vec3us;
/** 3-int signed vector */
typedef VectorT<signed int,3> Vec3i;
/** 3-int unsigned vector */
typedef VectorT<unsigned int,3> Vec3ui;
/** 3-float vector */
typedef VectorT<float,3> Vec3f;
/** 3-double vector */
typedef VectorT<double,3> Vec3d;
/** 3-bool vector */
typedef VectorT<bool,3> Vec3b;

/** 4-byte signed vector */
typedef VectorT<signed char,4> Vec4c;
/** 4-byte unsigned vector */
typedef VectorT<unsigned char,4> Vec4uc;
/** 4-short signed vector */
typedef VectorT<signed short int,4> Vec4s;
/** 4-short unsigned vector */
typedef VectorT<unsigned short int,4> Vec4us;
/** 4-int signed vector */
typedef VectorT<signed int,4> Vec4i;
/** 4-int unsigned vector */
typedef VectorT<unsigned int,4> Vec4ui;
/** 4-float vector */
typedef VectorT<float,4> Vec4f;
/** 4-double vector */
typedef VectorT<double,4> Vec4d;

/** 5-byte signed vector */
typedef VectorT<signed char, 5> Vec5c;
/** 5-byte unsigned vector */
typedef VectorT<unsigned char, 5> Vec5uc;
/** 5-short signed vector */
typedef VectorT<signed short int, 5> Vec5s;
/** 5-short unsigned vector */
typedef VectorT<unsigned short int, 5> Vec5us;
/** 5-int signed vector */
typedef VectorT<signed int, 5> Vec5i;
/** 5-int unsigned vector */
typedef VectorT<unsigned int, 5> Vec5ui;
/** 5-float vector */
typedef VectorT<float, 5> Vec5f;
/** 5-double vector */
typedef VectorT<double, 5> Vec5d;

/** 6-byte signed vector */
typedef VectorT<signed char,6> Vec6c;
/** 6-byte unsigned vector */
typedef VectorT<unsigned char,6> Vec6uc;
/** 6-short signed vector */
typedef VectorT<signed short int,6> Vec6s;
/** 6-short unsigned vector */
typedef VectorT<unsigned short int,6> Vec6us;
/** 6-int signed vector */
typedef VectorT<signed int,6> Vec6i;
/** 6-int unsigned vector */
typedef VectorT<unsigned int,6> Vec6ui;
/** 6-float vector */
typedef VectorT<float,6> Vec6f;
/** 6-double vector */
typedef VectorT<double,6> Vec6d;

//=============================================================================
} // namespace OpenMesh
//=============================================================================

#endif // OPENMESH_VECTOR_HH defined
//=============================================================================
#endif // DOXYGEN
#endif // C++11
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "sos.h"
#include "datatarget.h"
#include "corhdr.h"
#include "cor.h"
#include "dacprivate.h"
#include "sospriv.h"
#include "corerror.h"

#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)

DataTarget::DataTarget(void) :
    m_ref(0)
{
}

STDMETHODIMP
DataTarget::QueryInterface(
    THIS_
    ___in REFIID InterfaceId,
    ___out PVOID* Interface
    )
{
    if (InterfaceId == IID_IUnknown ||
        InterfaceId == IID_ICLRDataTarget)
    {
        *Interface = (ICLRDataTarget*)this;
        AddRef();
        return S_OK;
    }
    else if (InterfaceId == IID_ICorDebugDataTarget4)
    {
        *Interface = (ICorDebugDataTarget4*)this;
        AddRef();
        return S_OK;
    }
    else
    {
        *Interface = NULL;
        return E_NOINTERFACE;
    }
}

STDMETHODIMP_(ULONG)
DataTarget::AddRef(
    THIS
    )
{
    LONG ref = InterlockedIncrement(&m_ref);
    return ref;
}

STDMETHODIMP_(ULONG)
DataTarget::Release(
    THIS
    )
{
    LONG ref = InterlockedDecrement(&m_ref);
    if (ref == 0)
    {
        delete this;
    }
    return ref;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetMachineType(
    /* [out] */ ULONG32 *machine)
{
    if (g_ExtControl == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtControl->GetExecutingProcessorType(machine);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetPointerSize(
    /* [out] */ ULONG32 *size)
{
#if defined(SOS_TARGET_AMD64) || defined(SOS_TARGET_ARM64)
    *size = 8;
#elif defined(SOS_TARGET_ARM)
    *size = 4;
#else
  #error Unsupported architecture
#endif

    return S_OK;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetImageBase(
    /* [string][in] */ LPCWSTR name,
    /* [out] */ CLRDATA_ADDRESS *base)
{
    if (g_ExtSymbols == NULL)
    {
        return E_UNEXPECTED;
    }
    CHAR lpstr[MAX_LONGPATH];
    int name_length = WideCharToMultiByte(CP_ACP, 0, name, -1, lpstr, MAX_LONGPATH, NULL, NULL);
    if (name_length == 0)
    {
        return E_FAIL;
    }
    return g_ExtSymbols->GetModuleByModuleName(lpstr, 0, NULL, base);
}

HRESULT STDMETHODCALLTYPE
DataTarget::ReadVirtual(
    /* [in] */ CLRDATA_ADDRESS address,
    /* [length_is][size_is][out] */ PBYTE buffer,
    /* [in] */ ULONG32 request,
    /* [optional][out] */ ULONG32 *done)
{
    if (g_ExtData == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtData->ReadVirtual(address, (PVOID)buffer, request, done);
}

HRESULT STDMETHODCALLTYPE
DataTarget::WriteVirtual(
    /* [in] */ CLRDATA_ADDRESS address,
    /* [size_is][in] */ PBYTE buffer,
    /* [in] */ ULONG32 request,
    /* [optional][out] */ ULONG32 *done)
{
    if (g_ExtData == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtData->WriteVirtual(address, (PVOID)buffer, request, done);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetTLSValue(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 index,
    /* [out] */ CLRDATA_ADDRESS* value)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::SetTLSValue(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 index,
    /* [in] */ CLRDATA_ADDRESS value)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetCurrentThreadID(
    /* [out] */ ULONG32* threadID)
{
    if (g_ExtSystem == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtSystem->GetCurrentThreadSystemId(threadID);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetThreadContext(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 contextFlags,
    /* [in] */ ULONG32 contextSize,
    /* [out, size_is(contextSize)] */ PBYTE context)
{
    if (g_ExtSystem == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtSystem->GetThreadContextById(threadID, contextFlags, contextSize, context);
}

HRESULT STDMETHODCALLTYPE
DataTarget::SetThreadContext(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 contextSize,
    /* [out, size_is(contextSize)] */ PBYTE context)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::Request(
    /* [in] */ ULONG32 reqCode,
    /* [in] */ ULONG32 inBufferSize,
    /* [size_is][in] */ BYTE *inBuffer,
    /* [in] */ ULONG32 outBufferSize,
    /* [size_is][out] */ BYTE *outBuffer)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::VirtualUnwind(
    /* [in] */ DWORD threadId,
    /* [in] */ ULONG32 contextSize,
    /* [in, out, size_is(contextSize)] */ PBYTE context)
{
    if (g_ExtServices == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
}
<commit_msg>[x86/Linux][SOS] Fix DataTarget::GetPointerSize for x86 (#8473)<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "sos.h"
#include "datatarget.h"
#include "corhdr.h"
#include "cor.h"
#include "dacprivate.h"
#include "sospriv.h"
#include "corerror.h"

#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)

DataTarget::DataTarget(void) :
    m_ref(0)
{
}

STDMETHODIMP
DataTarget::QueryInterface(
    THIS_
    ___in REFIID InterfaceId,
    ___out PVOID* Interface
    )
{
    if (InterfaceId == IID_IUnknown ||
        InterfaceId == IID_ICLRDataTarget)
    {
        *Interface = (ICLRDataTarget*)this;
        AddRef();
        return S_OK;
    }
    else if (InterfaceId == IID_ICorDebugDataTarget4)
    {
        *Interface = (ICorDebugDataTarget4*)this;
        AddRef();
        return S_OK;
    }
    else
    {
        *Interface = NULL;
        return E_NOINTERFACE;
    }
}

STDMETHODIMP_(ULONG)
DataTarget::AddRef(
    THIS
    )
{
    LONG ref = InterlockedIncrement(&m_ref);
    return ref;
}

STDMETHODIMP_(ULONG)
DataTarget::Release(
    THIS
    )
{
    LONG ref = InterlockedDecrement(&m_ref);
    if (ref == 0)
    {
        delete this;
    }
    return ref;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetMachineType(
    /* [out] */ ULONG32 *machine)
{
    if (g_ExtControl == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtControl->GetExecutingProcessorType(machine);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetPointerSize(
    /* [out] */ ULONG32 *size)
{
#if defined(SOS_TARGET_AMD64) || defined(SOS_TARGET_ARM64)
    *size = 8;
#elif defined(SOS_TARGET_ARM) || defined(SOS_TARGET_X86)
    *size = 4;
#else
  #error Unsupported architecture
#endif

    return S_OK;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetImageBase(
    /* [string][in] */ LPCWSTR name,
    /* [out] */ CLRDATA_ADDRESS *base)
{
    if (g_ExtSymbols == NULL)
    {
        return E_UNEXPECTED;
    }
    CHAR lpstr[MAX_LONGPATH];
    int name_length = WideCharToMultiByte(CP_ACP, 0, name, -1, lpstr, MAX_LONGPATH, NULL, NULL);
    if (name_length == 0)
    {
        return E_FAIL;
    }
    return g_ExtSymbols->GetModuleByModuleName(lpstr, 0, NULL, base);
}

HRESULT STDMETHODCALLTYPE
DataTarget::ReadVirtual(
    /* [in] */ CLRDATA_ADDRESS address,
    /* [length_is][size_is][out] */ PBYTE buffer,
    /* [in] */ ULONG32 request,
    /* [optional][out] */ ULONG32 *done)
{
    if (g_ExtData == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtData->ReadVirtual(address, (PVOID)buffer, request, done);
}

HRESULT STDMETHODCALLTYPE
DataTarget::WriteVirtual(
    /* [in] */ CLRDATA_ADDRESS address,
    /* [size_is][in] */ PBYTE buffer,
    /* [in] */ ULONG32 request,
    /* [optional][out] */ ULONG32 *done)
{
    if (g_ExtData == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtData->WriteVirtual(address, (PVOID)buffer, request, done);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetTLSValue(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 index,
    /* [out] */ CLRDATA_ADDRESS* value)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::SetTLSValue(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 index,
    /* [in] */ CLRDATA_ADDRESS value)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetCurrentThreadID(
    /* [out] */ ULONG32* threadID)
{
    if (g_ExtSystem == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtSystem->GetCurrentThreadSystemId(threadID);
}

HRESULT STDMETHODCALLTYPE
DataTarget::GetThreadContext(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 contextFlags,
    /* [in] */ ULONG32 contextSize,
    /* [out, size_is(contextSize)] */ PBYTE context)
{
    if (g_ExtSystem == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtSystem->GetThreadContextById(threadID, contextFlags, contextSize, context);
}

HRESULT STDMETHODCALLTYPE
DataTarget::SetThreadContext(
    /* [in] */ ULONG32 threadID,
    /* [in] */ ULONG32 contextSize,
    /* [out, size_is(contextSize)] */ PBYTE context)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::Request(
    /* [in] */ ULONG32 reqCode,
    /* [in] */ ULONG32 inBufferSize,
    /* [size_is][in] */ BYTE *inBuffer,
    /* [in] */ ULONG32 outBufferSize,
    /* [size_is][out] */ BYTE *outBuffer)
{
    return E_NOTIMPL;
}

HRESULT STDMETHODCALLTYPE
DataTarget::VirtualUnwind(
    /* [in] */ DWORD threadId,
    /* [in] */ ULONG32 contextSize,
    /* [in, out, size_is(contextSize)] */ PBYTE context)
{
    if (g_ExtServices == NULL)
    {
        return E_UNEXPECTED;
    }
    return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <vector>

using namespace std;

vector< vector<int> > adj;
vector<bool> visited;

bool check(int v, int parent = -1) {
  visited[v] = true;

  for (int i: adj[v]) {
    if ( ! visited[i]) {
      if (check(i, v)) {
        return true;
      }
    } else if (i != parent) {
      return true;
    }
  }

  return false;
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  adj.resize(n), visited.resize(n);

  for (int i = 0; i < m; ++i) {
    int u, v;
    scanf("%d%d", &u, &v);
    --u, --v;
    adj[u].push_back(v), adj[v].push_back(u);
  }

  for (int i = 0; i < n; ++i) {
    if ( ! visited[i] && check(i)) {
      printf("There is a cycle\n");
      return 0;
    }
  }

  printf("No cycles\n");
  return 0;
}
<commit_msg>Update cycle detection algorithm for undirected graphs.<commit_after>#include <cstdio>
#include <vector>

using namespace std;

vector< vector<int> > adj;
vector<bool> visited, rec_stack;

bool check(int v, int parent = -1) {
  if ( ! visited[v]) {
    rec_stack[v] = visited[v] = true;

    for (int i: adj[v]) {
      if ( ! visited[i] && check(i, v)) {
        return true;
      }

      if (rec_stack[i] && i != parent) {
        return true;
      }
    }
  }

  return rec_stack[v] = false;
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  adj.resize(n), visited.resize(n), rec_stack.resize(n);

  for (int i = 0; i < m; ++i) {
    int u, v;
    scanf("%d%d", &u, &v);
    --u, --v;
    adj[u].push_back(v), adj[v].push_back(u);
  }

  for (int i = 0; i < n; ++i) {
    if (check(i)) {
      printf("There is a cycle\n");
      return 0;
    }
  }

  printf("No cycles\n");
  return 0;
}
<|endoftext|>


<commit_before>#ifndef TRACKING_ALLOCATOR_HPP_
#define TRACKING_ALLOCATOR_HPP_

#include <cstddef>
#include <memory>
#include <functional>

class tracking_allocator_factory_t;

// Base class for our allocators.
//
// We need this, because the allocator used forms part of the type for types like
// `std::map` and `std::string`.  As a result, if we were to use `tracking_allocator`
// and `unbounded_allocator` directly, the type of `datum_t` would need to be
// parameterized by the allocator used, which would suck.
template <class T, class Allocator=std::allocator<T> >
class rethinkdb_allocator_t {
public:
    typedef T value_type;
    typedef std::allocator_traits<rethinkdb_allocator_t<T, Allocator> > traits;

    explicit rethinkdb_allocator_t(Allocator _original) : original(_original) {}
    virtual ~rethinkdb_allocator_t() {}

    virtual T* allocate(size_t n) = 0;
    virtual T* allocate(size_t n, const void *hint) = 0;
    virtual void deallocate(T* region, size_t n) = 0;

    void dispose_of(T *ptr) {
        traits::destroy(*this, ptr);
        traits::deallocate(*this, ptr, 1);
    }

    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const = 0;
    bool operator !=(const rethinkdb_allocator_t<T, Allocator> &other) const {
        return !(*this == other);
    }

    virtual size_t max_size() const = 0;

    enum class allocator_types_t {
        UNBOUNDED,
        TRACKING,
    };
    virtual allocator_types_t type() const = 0;

    // function interface
    void operator() (T *ptr) { deallocate(ptr, 1); }
protected:
    Allocator original;
};

// Minimal definitions required to use `std::allocator_traits` and also keep track of
// the amount of memory allocated.
template <class T, class Allocator=std::allocator<T> >
class tracking_allocator_t : public rethinkdb_allocator_t<T, Allocator> {
public:
    tracking_allocator_t(Allocator _original,
                       std::shared_ptr<tracking_allocator_factory_t> _parent)
        : rethinkdb_allocator_t<T, Allocator>(_original), parent(_parent) {}
    tracking_allocator_t(Allocator _original,
                       std::weak_ptr<tracking_allocator_factory_t> _parent)
        : rethinkdb_allocator_t<T, Allocator>(_original), parent(_parent) {}
    explicit tracking_allocator_t(const tracking_allocator_t<T, Allocator> &allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator), parent(allocator._parent) {}
    explicit tracking_allocator_t(tracking_allocator_t<T, Allocator> &&allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator), parent(allocator._parent) {}
    virtual ~tracking_allocator_t() {}

    virtual T* allocate(size_t n);
    virtual T* allocate(size_t n, const void *hint);
    virtual void deallocate(T* region, size_t n);

    bool operator ==(const tracking_allocator_t<T, Allocator> &other) const {
        return parent.lock() == other.parent.lock();
    }
    bool operator !=(const tracking_allocator_t<T, Allocator> &other) const {
        return parent.lock() != other.parent.lock();
    }
    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const
    {
        if (other.type() == rethinkdb_allocator_t<T, Allocator>::allocator_types_t::TRACKING)
            return parent.lock() ==
                static_cast<tracking_allocator_t<T, Allocator> &>
                (const_cast<rethinkdb_allocator_t<T, Allocator> &>(other)).parent.lock();
        else
            return false;
    }

    virtual size_t max_size() const;
    virtual typename rethinkdb_allocator_t<T, Allocator>::allocator_types_t type() const {
        return rethinkdb_allocator_t<T, Allocator>::allocator_types_t::TRACKING;
    }

    std::weak_ptr<tracking_allocator_factory_t> parent;
};

// Thin shell around the standard allocator.  We need this so the type
// of `datum_t` doesn't change.
template <class T, class Allocator=std::allocator<T> >
class unbounded_allocator_t : public rethinkdb_allocator_t<T, Allocator> {
public:
    unbounded_allocator_t(Allocator _original)
        : rethinkdb_allocator_t<T, Allocator>(_original) {}
    unbounded_allocator_t(const unbounded_allocator_t<T> &allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator.original) {}
    unbounded_allocator_t(unbounded_allocator_t<T> &&allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator.original) {}
    virtual ~unbounded_allocator_t() {}

    virtual T* allocate(size_t n) {
        return this->original.allocate(n);
    }
    virtual T* allocate(size_t n, const void *hint) {
        return this->original.allocate(n, hint);
    }
    virtual void deallocate(T* region, size_t n) {
        this->original.deallocate(region, n);
    }

    bool operator ==(const tracking_allocator_t<T, Allocator> &) const { return true; }
    bool operator !=(const tracking_allocator_t<T, Allocator> &) const { return false; }
    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const
    {
        if (other.type()
            == rethinkdb_allocator_t<T, Allocator>::allocator_types::UNBOUNDED)
            return true;
        else
            return false;
    }
    virtual size_t max_size() const { return std::numeric_limits<size_t>::max(); }
    virtual typename rethinkdb_allocator_t<T, Allocator>::allocator_types_t type() const {
        return rethinkdb_allocator_t<T, Allocator>::allocator_types_t::UNBOUNDED;
    }
};

class tracking_allocator_factory_t {
public:
    tracking_allocator_factory_t(size_t total_bytes) : available(total_bytes) {}

    bool debit(size_t bytes) {
        if (available >= bytes) {
            available -= bytes;
            return true;
        } else {
            return false;
        }
    }
    void credit(size_t bytes) {
        available += bytes;
    }
    size_t left() const {
        return available;
    }
private:
    size_t available;
};

template <class T, class Allocator, class... Args>
T* make(std::allocator_arg_t, Allocator &alloc, Args&&... args) {
    T* result = std::allocator_traits<Allocator>::allocate(alloc, 1);
    std::allocator_traits<Allocator>::construct(alloc, result, std::forward<Args>(args)...);
    return result;
}

#endif /* TRACKING_ALLOCATOR_HPP_ */
<commit_msg>Move this to toplevel<commit_after>#ifndef TRACKING_ALLOCATOR_HPP_
#define TRACKING_ALLOCATOR_HPP_

#include <cstddef>
#include <memory>
#include <functional>

class tracking_allocator_factory_t;

enum class allocator_types_t {
    UNBOUNDED,
    TRACKING,
};

// Base class for our allocators.
//
// We need this, because the allocator used forms part of the type for types like
// `std::map` and `std::string`.  As a result, if we were to use `tracking_allocator`
// and `unbounded_allocator` directly, the type of `datum_t` would need to be
// parameterized by the allocator used, which would suck.
template <class T, class Allocator=std::allocator<T> >
class rethinkdb_allocator_t {
public:
    typedef T value_type;
    typedef std::allocator_traits<rethinkdb_allocator_t<T, Allocator> > traits;

    explicit rethinkdb_allocator_t(Allocator _original) : original(_original) {}
    virtual ~rethinkdb_allocator_t() {}

    virtual T* allocate(size_t n) = 0;
    virtual T* allocate(size_t n, const void *hint) = 0;
    virtual void deallocate(T* region, size_t n) = 0;

    void dispose_of(T *ptr) {
        traits::destroy(*this, ptr);
        traits::deallocate(*this, ptr, 1);
    }

    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const = 0;
    bool operator !=(const rethinkdb_allocator_t<T, Allocator> &other) const {
        return !(*this == other);
    }

    virtual size_t max_size() const = 0;

    virtual allocator_types_t type() const = 0;

    // function interface
    void operator() (T *ptr) { deallocate(ptr, 1); }
protected:
    Allocator original;
};

// Minimal definitions required to use `std::allocator_traits` and also keep track of
// the amount of memory allocated.
template <class T, class Allocator=std::allocator<T> >
class tracking_allocator_t : public rethinkdb_allocator_t<T, Allocator> {
public:
    tracking_allocator_t(Allocator _original,
                       std::shared_ptr<tracking_allocator_factory_t> _parent)
        : rethinkdb_allocator_t<T, Allocator>(_original), parent(_parent) {}
    tracking_allocator_t(Allocator _original,
                       std::weak_ptr<tracking_allocator_factory_t> _parent)
        : rethinkdb_allocator_t<T, Allocator>(_original), parent(_parent) {}
    explicit tracking_allocator_t(const tracking_allocator_t<T, Allocator> &allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator), parent(allocator._parent) {}
    explicit tracking_allocator_t(tracking_allocator_t<T, Allocator> &&allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator), parent(allocator._parent) {}
    virtual ~tracking_allocator_t() {}

    virtual T* allocate(size_t n);
    virtual T* allocate(size_t n, const void *hint);
    virtual void deallocate(T* region, size_t n);

    bool operator ==(const tracking_allocator_t<T, Allocator> &other) const {
        return parent.lock() == other.parent.lock();
    }
    bool operator !=(const tracking_allocator_t<T, Allocator> &other) const {
        return parent.lock() != other.parent.lock();
    }
    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const {
        if (other.type() == allocator_types_t::TRACKING) {
            return parent.lock() ==
                static_cast<const tracking_allocator_t<T, Allocator> &>(other)
                .parent.lock();
        } else {
            return false;
        }
    }

    virtual size_t max_size() const;
    virtual typename allocator_types_t type() const {
        return allocator_types_t::TRACKING;
    }

    std::weak_ptr<tracking_allocator_factory_t> parent;
};

// Thin shell around the standard allocator.  We need this so the type
// of `datum_t` doesn't change.
template <class T, class Allocator=std::allocator<T> >
class unbounded_allocator_t : public rethinkdb_allocator_t<T, Allocator> {
public:
    unbounded_allocator_t(Allocator _original)
        : rethinkdb_allocator_t<T, Allocator>(_original) {}
    unbounded_allocator_t(const unbounded_allocator_t<T> &allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator.original) {}
    unbounded_allocator_t(unbounded_allocator_t<T> &&allocator)
        : rethinkdb_allocator_t<T, Allocator>(allocator.original) {}
    virtual ~unbounded_allocator_t() {}

    virtual T* allocate(size_t n) {
        return this->original.allocate(n);
    }
    virtual T* allocate(size_t n, const void *hint) {
        return this->original.allocate(n, hint);
    }
    virtual void deallocate(T* region, size_t n) {
        this->original.deallocate(region, n);
    }

    bool operator ==(const tracking_allocator_t<T, Allocator> &) const { return true; }
    bool operator !=(const tracking_allocator_t<T, Allocator> &) const { return false; }
    virtual bool operator ==(const rethinkdb_allocator_t<T, Allocator> &other) const
    {
        if (other.type()
            == rethinkdb_allocator_t<T, Allocator>::allocator_types::UNBOUNDED)
            return true;
        else
            return false;
    }
    virtual size_t max_size() const { return std::numeric_limits<size_t>::max(); }
    virtual typename allocator_types_t type() const {
        return allocator_types_t::UNBOUNDED;
    }
};

class tracking_allocator_factory_t {
public:
    tracking_allocator_factory_t(size_t total_bytes) : available(total_bytes) {}

    bool debit(size_t bytes) {
        if (available >= bytes) {
            available -= bytes;
            return true;
        } else {
            return false;
        }
    }
    void credit(size_t bytes) {
        available += bytes;
    }
    size_t left() const {
        return available;
    }
private:
    size_t available;
};

template <class T, class Allocator, class... Args>
T* make(std::allocator_arg_t, Allocator &alloc, Args&&... args) {
    T* result = std::allocator_traits<Allocator>::allocate(alloc, 1);
    std::allocator_traits<Allocator>::construct(alloc, result, std::forward<Args>(args)...);
    return result;
}

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


<commit_before>#include <stdio.h>
#include <queue>
#include <vector>
#include <utility>
#include <iostream>
#include <string>
#include <stack>

using namespace std;

stack<string> lv1;
stack<string> lv2;
stack<string> lv3;

string temp;
int templv;
int temptime=0;
int usernum;
int users=0;
int read(int now){
	if(now < temptime) return 0;

	do{
		printf("test\n");
		if(temp.empty()){

		}else{

			switch(templv){
				case 1:
					lv1.push(temp);break;
				case 2:
					lv2.push(temp);break;
				case 3:
					lv3.push(temp);break;
			}
		}
		if(users<usernum)
			cin >>temptime>>templv>>temp;
		else
			return 0;
		users++;
	}while(temptime<=now);

}
int main(int argc, char const *argv[])
{
		int time;
		scanf("%d%d",&usernum,&time);
		for (int i = 0; i < time; ++i)
		{
			read(i);
			cout<<i<<"\n"<<lv1.size()<<lv2.size()<<lv3.size()<<endl;

		}

	return 0;
}<commit_msg>update uoj2254<commit_after>#include <stdio.h>
#include <queue>
#include <vector>
#include <utility>
#include <iostream>
#include <string>
#include <stack>

using namespace std;

stack<string> lv1;
stack<string> lv2;
stack<string> lv3;

string temp;
int templv;
int temptime=0;
int usernum;
int users=0;
int read(int now){
	if(now < temptime) return 0;

	do{
		printf("test\n");
		if(temp.empty()){

		}else{

			switch(templv){
				case 1:
					lv1.push(temp);break;
				case 2:
					lv2.push(temp);break;
				case 3:
					lv3.push(temp);break;
			}
		}
		if(users<usernum)
			cin >>temptime>>templv>>temp;
			users++;
		else
			return 0;
	}while(temptime<=now);

}
int main(int argc, char const *argv[])
{
		int time;
		scanf("%d%d",&usernum,&time);
		for (int i = 0; i < time; ++i)
		{
			read(i);
			cout<<i<<"\n"<<lv1.size()<<lv2.size()<<lv3.size()<<endl;

		}

	return 0;
}<|endoftext|>


<commit_before>#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>

#include "blackhole/sink/files/rotation/config.hpp"
#include "blackhole/sink/files/rotation/counter.hpp"
#include "blackhole/sink/files/rotation/naming/filter.hpp"
#include "blackhole/sink/files/rotation/timer.hpp"
#include "blackhole/sink/files/rotation/watcher.hpp"

namespace blackhole {

namespace sink {

//! Tag for file sinks with no rotation.
class NoRotation;

template<class Backend, class Watcher, class Timer = rotation::timer_t>
class rotator_t {
    rotation::config_t<Watcher> config;
    Backend& backend;
    Timer m_timer;
    rotation::naming::basename_t generator;
    rotation::counter_t counter;
    Watcher watcher;
public:
    static const char* name() {
        return "rotate";
    }

    rotator_t(const rotation::config_t<Watcher>& config, Backend& backend) :
        config(config),
        backend(backend),
        generator(config.pattern),
        counter(rotation::counter_t::from_string(boost::algorithm::replace_all_copy(config.pattern, "%(filename)s", backend.filename()))),
        watcher(config.watcher)
    {}

    Timer& timer() {
        return m_timer;
    }

    bool necessary(const std::string& message) const {
        return watcher(backend, message);
    }

    void rotate() const {
        backend.flush();
        backend.close();
        rollover();
        backend.open();
    }

private:
    void rollover() const {
        const std::string& filename = backend.filename();
        const std::string& basename = generator.transform(filename);

        if (counter.valid()) {
            rollover(backend.listdir(), basename);
        }

        if (backend.exists(filename)) {
            backend.rename(filename, backup_filename(basename));
        }
    }

    void rollover(std::vector<std::string> filenames, const std::string& pattern) const {
        filenames.erase(std::remove_if(filenames.begin(),
                                       filenames.end(),
                                       rotation::naming::filter_t(pattern)),
                        filenames.end());
        std::sort(filenames.begin(), filenames.end(),
                  rotation::naming::comparator::time::descending<Backend>(backend));
        if (filenames.size() > static_cast<std::size_t>(config.backups - 1)) {
            filenames.erase(filenames.begin() + config.backups - 1, filenames.end());
        }

        for (int n = filenames.size() - 1; n >= 0; --n) {
            const std::string& filename = filenames.at(n);
            if (backend.exists(filename)) {
                backend.rename(filename, counter.next(filename, n + 1));
            }
        }
    }

    std::string backup_filename(const std::string& pattern) const {
        std::string filename = pattern;
        boost::algorithm::replace_all(filename, "%N", "1");
        std::time_t time = m_timer.current();
        char buf[128];
        if (strftime(buf, 128, filename.data(), std::gmtime(&time)) == 0) {
            // Do nothing.
        }

        return std::string(buf);
    }
};

} // namespace sink

} // namespace blackhole
<commit_msg>[Tasks] One task more.<commit_after>#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>

#include "blackhole/sink/files/rotation/config.hpp"
#include "blackhole/sink/files/rotation/counter.hpp"
#include "blackhole/sink/files/rotation/naming/filter.hpp"
#include "blackhole/sink/files/rotation/timer.hpp"
#include "blackhole/sink/files/rotation/watcher.hpp"

namespace blackhole {

namespace sink {

//! Tag for file sinks with no rotation.
class NoRotation;

template<class Backend, class Watcher, class Timer = rotation::timer_t>
class rotator_t {
    rotation::config_t<Watcher> config;
    Backend& backend;
    Timer m_timer;
    rotation::naming::basename_t generator;
    rotation::counter_t counter;
    Watcher watcher;
public:
    static const char* name() {
        return "rotate";
    }

    rotator_t(const rotation::config_t<Watcher>& config, Backend& backend) :
        config(config),
        backend(backend),
        generator(config.pattern),
        counter(rotation::counter_t::from_string(boost::algorithm::replace_all_copy(config.pattern, "%(filename)s", backend.filename()))),
        watcher(config.watcher)
    {}

    //!@todo: Isolate.
    Timer& timer() {
        return m_timer;
    }

    bool necessary(const std::string& message) const {
        return watcher(backend, message);
    }

    void rotate() const {
        backend.flush();
        backend.close();
        rollover();
        backend.open();
    }

private:
    void rollover() const {
        const std::string& filename = backend.filename();
        const std::string& basename = generator.transform(filename);

        if (counter.valid()) {
            rollover(backend.listdir(), basename);
        }

        if (backend.exists(filename)) {
            backend.rename(filename, backup_filename(basename));
        }
    }

    void rollover(std::vector<std::string> filenames, const std::string& pattern) const {
        filenames.erase(std::remove_if(filenames.begin(),
                                       filenames.end(),
                                       rotation::naming::filter_t(pattern)),
                        filenames.end());
        std::sort(filenames.begin(), filenames.end(),
                  rotation::naming::comparator::time::descending<Backend>(backend));
        if (filenames.size() > static_cast<std::size_t>(config.backups - 1)) {
            filenames.erase(filenames.begin() + config.backups - 1, filenames.end());
        }

        for (int n = filenames.size() - 1; n >= 0; --n) {
            const std::string& filename = filenames.at(n);
            if (backend.exists(filename)) {
                backend.rename(filename, counter.next(filename, n + 1));
            }
        }
    }

    std::string backup_filename(const std::string& pattern) const {
        std::string filename = pattern;
        boost::algorithm::replace_all(filename, "%N", "1");
        std::time_t time = m_timer.current();
        char buf[128];
        if (strftime(buf, 128, filename.data(), std::gmtime(&time)) == 0) {
            // Do nothing.
        }

        return std::string(buf);
    }
};

} // namespace sink

} // namespace blackhole
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Bitcoin developers
// Copyright (c) 2012 Litecoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("Satoshi");

// Client version number
#define CLIENT_VERSION_SUFFIX   "-lgc"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "$Format:%h$"
#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define STRINGIFY(s) #s

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<commit_msg>Update version.cpp<commit_after>// Copyright (c) 2012 The Bitcoin developers
// Copyright (c) 2012 Litecoin Developers
// Copyright (c) 2013-2014 Ivan Lenev
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("Satoshi");

// Client version number
#define CLIENT_VERSION_SUFFIX   "-lgc"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "$Format:%h$"
#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define STRINGIFY(s) #s

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" STRINGIFY(maj) "." STRINGIFY(min) "." STRINGIFY(rev) "." STRINGIFY(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<|endoftext|>


<commit_before>#include <algorithm>
#include <vector>

#include "caffe/layers/batch_norm_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void BatchNormLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  BatchNormParameter param = this->layer_param_.batch_norm_param();
  moving_average_fraction_ = param.moving_average_fraction();
  use_global_stats_ = this->phase_ == TEST;
  if (param.has_use_global_stats())
    use_global_stats_ = param.use_global_stats();
  if (bottom[0]->num_axes() == 1)
    channels_ = 1;
  else
    channels_ = bottom[0]->shape(1);
  eps_ = param.eps();
  if (this->blobs_.size() > 0) {
    LOG(INFO) << "Skipping parameter initialization";
  } else {
    this->blobs_.resize(3);
    vector<int> sz;
    sz.push_back(channels_);
    this->blobs_[0].reset(new Blob<Dtype>(sz));
    this->blobs_[1].reset(new Blob<Dtype>(sz));
    sz[0]=1;
    this->blobs_[2].reset(new Blob<Dtype>(sz));
    for (int i = 0; i < 3; ++i) {
      caffe_set(this->blobs_[i]->count(), Dtype(0),
                this->blobs_[i]->mutable_cpu_data());
    }
  }
  // Mask statistics from optimization by setting local learning rates
  // for mean, variance, and the bias correction to zero.
  CHECK_EQ(this->layer_param_.param_size(), 0)
      << "Cannot configure batch normalization statistics as layer parameters.";
  for (int i = 0; i < this->blobs_.size(); ++i) {
    ParamSpec* fixed_param_spec = this->layer_param_.add_param();
    fixed_param_spec->set_lr_mult(0.);
  }
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  if (bottom[0]->num_axes() >= 1)
    CHECK_EQ(bottom[0]->shape(1), channels_);
  top[0]->ReshapeLike(*bottom[0]);

  vector<int> sz;
  sz.push_back(channels_);
  mean_.Reshape(sz);
  variance_.Reshape(sz);
  temp_.ReshapeLike(*bottom[0]);
  x_norm_.ReshapeLike(*bottom[0]);
  sz[0]=bottom[0]->shape(0);
  batch_sum_multiplier_.Reshape(sz);

  int spatial_dim = bottom[0]->count()/(channels_*bottom[0]->shape(0));
  if (spatial_sum_multiplier_.num_axes() == 0 ||
      spatial_sum_multiplier_.shape(0) != spatial_dim) {
    sz[0] = spatial_dim;
    spatial_sum_multiplier_.Reshape(sz);
    Dtype* multiplier_data = spatial_sum_multiplier_.mutable_cpu_data();
    caffe_set(spatial_sum_multiplier_.count(), Dtype(1), multiplier_data);
  }

  int numbychans = channels_*bottom[0]->shape(0);
  if (num_by_chans_.num_axes() == 0 ||
      num_by_chans_.shape(0) != numbychans) {
    sz[0] = numbychans;
    num_by_chans_.Reshape(sz);
    caffe_set(batch_sum_multiplier_.count(), Dtype(1),
        batch_sum_multiplier_.mutable_cpu_data());
  }
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* top_data = top[0]->mutable_cpu_data();
  int num = bottom[0]->shape(0);
  int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_);

  if (bottom[0] != top[0]) {
    caffe_copy(bottom[0]->count(), bottom_data, top_data);
  }

  if (use_global_stats_) {
    // use the stored mean/variance estimates.
    const Dtype scale_factor = this->blobs_[2]->cpu_data()[0] == 0 ?
        0 : 1 / this->blobs_[2]->cpu_data()[0];
    caffe_cpu_scale(variance_.count(), scale_factor,
        this->blobs_[0]->cpu_data(), mean_.mutable_cpu_data());
    caffe_cpu_scale(variance_.count(), scale_factor,
        this->blobs_[1]->cpu_data(), variance_.mutable_cpu_data());
  } else {
    // compute mean
    caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim,
        1. / (num * spatial_dim), bottom_data,
        spatial_sum_multiplier_.cpu_data(), 0.,
        num_by_chans_.mutable_cpu_data());
    caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
        num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
        mean_.mutable_cpu_data());
  }

  // subtract mean
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, -1, num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 1., top_data);

  if (!use_global_stats_) {
    // compute variance using var(X) = E((X-EX)^2)
    caffe_powx(top[0]->count(), top_data, Dtype(2),
        temp_.mutable_cpu_data());  // (X-EX)^2
    caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim,
        1. / (num * spatial_dim), temp_.cpu_data(),
        spatial_sum_multiplier_.cpu_data(), 0.,
        num_by_chans_.mutable_cpu_data());
    caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
        num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
        variance_.mutable_cpu_data());  // E((X_EX)^2)

    // compute and save moving average
    this->blobs_[2]->mutable_cpu_data()[0] *= moving_average_fraction_;
    this->blobs_[2]->mutable_cpu_data()[0] += 1;
    caffe_cpu_axpby(mean_.count(), Dtype(1), mean_.cpu_data(),
        moving_average_fraction_, this->blobs_[0]->mutable_cpu_data());
    int m = bottom[0]->count()/channels_;
    Dtype bias_correction_factor = m > 1 ? Dtype(m)/(m-1) : 1;
    caffe_cpu_axpby(variance_.count(), bias_correction_factor,
        variance_.cpu_data(), moving_average_fraction_,
        this->blobs_[1]->mutable_cpu_data());
  }

  // normalize variance
  caffe_add_scalar(variance_.count(), eps_, variance_.mutable_cpu_data());
  caffe_powx(variance_.count(), variance_.cpu_data(), Dtype(0.5),
             variance_.mutable_cpu_data());

  // replicate variance to input size
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), variance_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 0., temp_.mutable_cpu_data());
  caffe_div(temp_.count(), top_data, temp_.cpu_data(), top_data);
  // TODO(cdoersch): The caching is only needed because later in-place layers
  //                 might clobber the data.  Can we skip this if they won't?
  caffe_copy(x_norm_.count(), top_data,
      x_norm_.mutable_cpu_data());
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down,
    const vector<Blob<Dtype>*>& bottom) {
  const Dtype* top_diff;
  if (bottom[0] != top[0]) {
    top_diff = top[0]->cpu_diff();
  } else {
    caffe_copy(x_norm_.count(), top[0]->cpu_diff(), x_norm_.mutable_cpu_diff());
    top_diff = x_norm_.cpu_diff();
  }
  Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
  if (use_global_stats_) {
    caffe_div(temp_.count(), top_diff, temp_.cpu_data(), bottom_diff);
    return;
  }
  const Dtype* top_data = x_norm_.cpu_data();
  int num = bottom[0]->shape()[0];
  int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_);
  // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then
  //
  // dE(Y)/dX =
  //   (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y)
  //     ./ sqrt(var(X) + eps)
  //
  // where \cdot and ./ are hadamard product and elementwise division,
  // respectively, dE/dY is the top diff, and mean/var/sum are all computed
  // along all dimensions except the channels dimension.  In the above
  // equation, the operations allow for expansion (i.e. broadcast) along all
  // dimensions except the channels dimension where required.

  // sum(dE/dY \cdot Y)
  caffe_mul(temp_.count(), top_data, top_diff, bottom_diff);
  caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1.,
      bottom_diff, spatial_sum_multiplier_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
      num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
      mean_.mutable_cpu_data());

  // reshape (broadcast) the above
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 0., bottom_diff);

  // sum(dE/dY \cdot Y) \cdot Y
  caffe_mul(temp_.count(), top_data, bottom_diff, bottom_diff);

  // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y
  caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1.,
      top_diff, spatial_sum_multiplier_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
      num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
      mean_.mutable_cpu_data());
  // reshape (broadcast) the above to make
  // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num * channels_,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 1., bottom_diff);

  // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y
  caffe_cpu_axpby(temp_.count(), Dtype(1), top_diff,
      Dtype(-1. / (num * spatial_dim)), bottom_diff);

  // note: temp_ still contains sqrt(var(X)+eps), computed during the forward
  // pass.
  caffe_div(temp_.count(), bottom_diff, temp_.cpu_data(), bottom_diff);
}

#ifdef CPU_ONLY
STUB_GPU(BatchNormLayer);
#endif

INSTANTIATE_CLASS(BatchNormLayer);
REGISTER_LAYER_CLASS(BatchNorm);
}  // namespace caffe
<commit_msg>slightly relax batch norm check<commit_after>#include <algorithm>
#include <vector>

#include "caffe/layers/batch_norm_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void BatchNormLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  BatchNormParameter param = this->layer_param_.batch_norm_param();
  moving_average_fraction_ = param.moving_average_fraction();
  use_global_stats_ = this->phase_ == TEST;
  if (param.has_use_global_stats())
    use_global_stats_ = param.use_global_stats();
  if (bottom[0]->num_axes() == 1)
    channels_ = 1;
  else
    channels_ = bottom[0]->shape(1);
  eps_ = param.eps();
  if (this->blobs_.size() > 0) {
    LOG(INFO) << "Skipping parameter initialization";
  } else {
    this->blobs_.resize(3);
    vector<int> sz;
    sz.push_back(channels_);
    this->blobs_[0].reset(new Blob<Dtype>(sz));
    this->blobs_[1].reset(new Blob<Dtype>(sz));
    sz[0]=1;
    this->blobs_[2].reset(new Blob<Dtype>(sz));
    for (int i = 0; i < 3; ++i) {
      caffe_set(this->blobs_[i]->count(), Dtype(0),
                this->blobs_[i]->mutable_cpu_data());
    }
  }
  // Mask statistics from optimization by setting local learning rates
  // for mean, variance, and the bias correction to zero.
  for (int i = 0; i < this->blobs_.size(); ++i) {
    if (this->layer_param_.param_size() == i) {
      ParamSpec* fixed_param_spec = this->layer_param_.add_param();
      fixed_param_spec->set_lr_mult(0.f);
    } else {
      CHECK_EQ(this->layer_param_.param(i).lr_mult(), 0.f)
          << "Cannot configure batch normalization statistics as layer "
          << "parameters.";
    }
  }
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
  if (bottom[0]->num_axes() >= 1)
    CHECK_EQ(bottom[0]->shape(1), channels_);
  top[0]->ReshapeLike(*bottom[0]);

  vector<int> sz;
  sz.push_back(channels_);
  mean_.Reshape(sz);
  variance_.Reshape(sz);
  temp_.ReshapeLike(*bottom[0]);
  x_norm_.ReshapeLike(*bottom[0]);
  sz[0]=bottom[0]->shape(0);
  batch_sum_multiplier_.Reshape(sz);

  int spatial_dim = bottom[0]->count()/(channels_*bottom[0]->shape(0));
  if (spatial_sum_multiplier_.num_axes() == 0 ||
      spatial_sum_multiplier_.shape(0) != spatial_dim) {
    sz[0] = spatial_dim;
    spatial_sum_multiplier_.Reshape(sz);
    Dtype* multiplier_data = spatial_sum_multiplier_.mutable_cpu_data();
    caffe_set(spatial_sum_multiplier_.count(), Dtype(1), multiplier_data);
  }

  int numbychans = channels_*bottom[0]->shape(0);
  if (num_by_chans_.num_axes() == 0 ||
      num_by_chans_.shape(0) != numbychans) {
    sz[0] = numbychans;
    num_by_chans_.Reshape(sz);
    caffe_set(batch_sum_multiplier_.count(), Dtype(1),
        batch_sum_multiplier_.mutable_cpu_data());
  }
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    const vector<Blob<Dtype>*>& top) {
  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* top_data = top[0]->mutable_cpu_data();
  int num = bottom[0]->shape(0);
  int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_);

  if (bottom[0] != top[0]) {
    caffe_copy(bottom[0]->count(), bottom_data, top_data);
  }

  if (use_global_stats_) {
    // use the stored mean/variance estimates.
    const Dtype scale_factor = this->blobs_[2]->cpu_data()[0] == 0 ?
        0 : 1 / this->blobs_[2]->cpu_data()[0];
    caffe_cpu_scale(variance_.count(), scale_factor,
        this->blobs_[0]->cpu_data(), mean_.mutable_cpu_data());
    caffe_cpu_scale(variance_.count(), scale_factor,
        this->blobs_[1]->cpu_data(), variance_.mutable_cpu_data());
  } else {
    // compute mean
    caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim,
        1. / (num * spatial_dim), bottom_data,
        spatial_sum_multiplier_.cpu_data(), 0.,
        num_by_chans_.mutable_cpu_data());
    caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
        num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
        mean_.mutable_cpu_data());
  }

  // subtract mean
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, -1, num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 1., top_data);

  if (!use_global_stats_) {
    // compute variance using var(X) = E((X-EX)^2)
    caffe_powx(top[0]->count(), top_data, Dtype(2),
        temp_.mutable_cpu_data());  // (X-EX)^2
    caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim,
        1. / (num * spatial_dim), temp_.cpu_data(),
        spatial_sum_multiplier_.cpu_data(), 0.,
        num_by_chans_.mutable_cpu_data());
    caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
        num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
        variance_.mutable_cpu_data());  // E((X_EX)^2)

    // compute and save moving average
    this->blobs_[2]->mutable_cpu_data()[0] *= moving_average_fraction_;
    this->blobs_[2]->mutable_cpu_data()[0] += 1;
    caffe_cpu_axpby(mean_.count(), Dtype(1), mean_.cpu_data(),
        moving_average_fraction_, this->blobs_[0]->mutable_cpu_data());
    int m = bottom[0]->count()/channels_;
    Dtype bias_correction_factor = m > 1 ? Dtype(m)/(m-1) : 1;
    caffe_cpu_axpby(variance_.count(), bias_correction_factor,
        variance_.cpu_data(), moving_average_fraction_,
        this->blobs_[1]->mutable_cpu_data());
  }

  // normalize variance
  caffe_add_scalar(variance_.count(), eps_, variance_.mutable_cpu_data());
  caffe_powx(variance_.count(), variance_.cpu_data(), Dtype(0.5),
             variance_.mutable_cpu_data());

  // replicate variance to input size
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), variance_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 0., temp_.mutable_cpu_data());
  caffe_div(temp_.count(), top_data, temp_.cpu_data(), top_data);
  // TODO(cdoersch): The caching is only needed because later in-place layers
  //                 might clobber the data.  Can we skip this if they won't?
  caffe_copy(x_norm_.count(), top_data,
      x_norm_.mutable_cpu_data());
}

template <typename Dtype>
void BatchNormLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down,
    const vector<Blob<Dtype>*>& bottom) {
  const Dtype* top_diff;
  if (bottom[0] != top[0]) {
    top_diff = top[0]->cpu_diff();
  } else {
    caffe_copy(x_norm_.count(), top[0]->cpu_diff(), x_norm_.mutable_cpu_diff());
    top_diff = x_norm_.cpu_diff();
  }
  Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
  if (use_global_stats_) {
    caffe_div(temp_.count(), top_diff, temp_.cpu_data(), bottom_diff);
    return;
  }
  const Dtype* top_data = x_norm_.cpu_data();
  int num = bottom[0]->shape()[0];
  int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_);
  // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then
  //
  // dE(Y)/dX =
  //   (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y)
  //     ./ sqrt(var(X) + eps)
  //
  // where \cdot and ./ are hadamard product and elementwise division,
  // respectively, dE/dY is the top diff, and mean/var/sum are all computed
  // along all dimensions except the channels dimension.  In the above
  // equation, the operations allow for expansion (i.e. broadcast) along all
  // dimensions except the channels dimension where required.

  // sum(dE/dY \cdot Y)
  caffe_mul(temp_.count(), top_data, top_diff, bottom_diff);
  caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1.,
      bottom_diff, spatial_sum_multiplier_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
      num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
      mean_.mutable_cpu_data());

  // reshape (broadcast) the above
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 0., bottom_diff);

  // sum(dE/dY \cdot Y) \cdot Y
  caffe_mul(temp_.count(), top_data, bottom_diff, bottom_diff);

  // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y
  caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1.,
      top_diff, spatial_sum_multiplier_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1.,
      num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0.,
      mean_.mutable_cpu_data());
  // reshape (broadcast) the above to make
  // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1,
      batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0.,
      num_by_chans_.mutable_cpu_data());
  caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num * channels_,
      spatial_dim, 1, 1., num_by_chans_.cpu_data(),
      spatial_sum_multiplier_.cpu_data(), 1., bottom_diff);

  // dE/dY - mean(dE/dY)-mean(dE/dY \cdot Y) \cdot Y
  caffe_cpu_axpby(temp_.count(), Dtype(1), top_diff,
      Dtype(-1. / (num * spatial_dim)), bottom_diff);

  // note: temp_ still contains sqrt(var(X)+eps), computed during the forward
  // pass.
  caffe_div(temp_.count(), bottom_diff, temp_.cpu_data(), bottom_diff);
}

#ifdef CPU_ONLY
STUB_GPU(BatchNormLayer);
#endif

INSTANTIATE_CLASS(BatchNormLayer);
REGISTER_LAYER_CLASS(BatchNorm);
}  // namespace caffe
<|endoftext|>


<commit_before>#include "core/enum.h"

#include <iostream>
#include <set>
#include <utility>
#include <cassert>

#include "core/assert.h"
#include "core/proto.h"
#include "core/str.h"
#include "core/stringmerger.h"
#include "core/stringutils.h"
#include "enum.pb.h"

EnumType::EnumType(std::string name)
    : name_(std::move(name))
    , isAdding_(true)
    , nextIndex_(1)
{
}

EnumType::~EnumType()
{
  ASSERT(!isAdding_);
}

std::string
EnumType::ToString(size_t v) const
{
  ASSERT(v < nextIndex_);
  auto f = valueToName_.find(v);
  if(f != valueToName_.end())
  {
    return f->second;
  }

  // ASSERT(false && "Invalid index");
  const auto values =
      StringMerger::EnglishOr().Generate(MapToStringVector(nameToValue_));
  const std::string invalid = Str() << "<invalid value " << v << " of "
                                    << values << ">";
  return invalid;
}

const EnumValue
EnumType::ToEnum(const std::string& name)
{
  NameToValue::const_iterator r = nameToValue_.find(name);
  if(r != nameToValue_.end())
  {
    return EnumValue(this, r->second);
  }

  if(!isAdding_)
  {
    std::cerr << "Enum value doesnt exist, " << name << "\n";
    return EnumValue(this, 0);
  }
  const size_t id = nextIndex_;
  AddEnum(name);
  return EnumValue(this, id);
}

void
EnumType::AddEnums(const std::vector<std::string>& names)
{
  ASSERT(isAdding_);
  std::set<std::string> valid_names;
  for(const auto& name : names)
  {
    AddEnum(name);
    valid_names.insert(name);
  }

  // validate all names against true names
  for(const auto& name : nameToValue_)
  {
    const bool missing = valid_names.find(name.first) == valid_names.end();
    if(missing)
    {
      std::cerr << "Enum " << name_ << " was registered with name "
                << name.first << " but that is invalid.\n";
    }
  }

  isAdding_ = false;
}

void
EnumType::AddEnum(const std::string& name)
{
  ASSERT(isAdding_);
  NameToValue::const_iterator r = nameToValue_.find(name);
  if(r != nameToValue_.end())
  {
    return;
  }
  const size_t id = nextIndex_;
  ++nextIndex_;
  valueToName_.insert(ValueToName::value_type(id, name));
  nameToValue_.insert(NameToValue::value_type(name, id));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Enum Value

EnumValue::EnumValue(EnumType* t, size_t v)
    : type_(t)
    , value_(v)
{
}

const std::string
EnumValue::ToString() const
{
  return type_->ToString(value_);
}

const size_t
EnumValue::ToValue() const
{
  return value_;
}

bool
EnumValue::operator==(const EnumValue& other) const
{
  ASSERT(type_ == other.type_);
  return value_ == other.value_;
}

bool
EnumValue::operator!=(const EnumValue& other) const
{
  return !(*this == other);
}

bool
EnumValue::operator<(const EnumValue& other) const
{
  ASSERT(type_ == other.type_);
  return value_ < other.value_;
}

std::ostream&
operator<<(std::ostream& s, const EnumValue& v)
{
  s << v.ToString();
  return s;
}

void
LoadEnumType(EnumType* type, FileSystem* fs, const std::string& path)
{
  ASSERT(type);

  enumlist::Enumroot root;
  const std::string  load_error = LoadProtoJson(fs, &root, path);

  std::vector<std::string> names;

  if(!load_error.empty())
  {
    std::cerr << "Failed to load enums " << path << ": " << load_error << "\n";
  }
  else
  {
    for(const auto& name : root.name())
    {
      names.push_back(name);
    }
  }

  type->AddEnums(names);
}
<commit_msg>trying to fix assert compile error in protobuf<commit_after>#include "core/enum.h"

#include <iostream>
#include <set>
#include <utility>

#include "core/assert.h"
#include "core/proto.h"
#include "core/str.h"
#include "core/stringmerger.h"
#include "core/stringutils.h"

#ifdef assert
#undef assert
#endif
#include <cassert>

#include "enum.pb.h"

EnumType::EnumType(std::string name)
    : name_(std::move(name))
    , isAdding_(true)
    , nextIndex_(1)
{
}

EnumType::~EnumType()
{
  ASSERT(!isAdding_);
}

std::string
EnumType::ToString(size_t v) const
{
  ASSERT(v < nextIndex_);
  auto f = valueToName_.find(v);
  if(f != valueToName_.end())
  {
    return f->second;
  }

  // ASSERT(false && "Invalid index");
  const auto values =
      StringMerger::EnglishOr().Generate(MapToStringVector(nameToValue_));
  const std::string invalid = Str() << "<invalid value " << v << " of "
                                    << values << ">";
  return invalid;
}

const EnumValue
EnumType::ToEnum(const std::string& name)
{
  NameToValue::const_iterator r = nameToValue_.find(name);
  if(r != nameToValue_.end())
  {
    return EnumValue(this, r->second);
  }

  if(!isAdding_)
  {
    std::cerr << "Enum value doesnt exist, " << name << "\n";
    return EnumValue(this, 0);
  }
  const size_t id = nextIndex_;
  AddEnum(name);
  return EnumValue(this, id);
}

void
EnumType::AddEnums(const std::vector<std::string>& names)
{
  ASSERT(isAdding_);
  std::set<std::string> valid_names;
  for(const auto& name : names)
  {
    AddEnum(name);
    valid_names.insert(name);
  }

  // validate all names against true names
  for(const auto& name : nameToValue_)
  {
    const bool missing = valid_names.find(name.first) == valid_names.end();
    if(missing)
    {
      std::cerr << "Enum " << name_ << " was registered with name "
                << name.first << " but that is invalid.\n";
    }
  }

  isAdding_ = false;
}

void
EnumType::AddEnum(const std::string& name)
{
  ASSERT(isAdding_);
  NameToValue::const_iterator r = nameToValue_.find(name);
  if(r != nameToValue_.end())
  {
    return;
  }
  const size_t id = nextIndex_;
  ++nextIndex_;
  valueToName_.insert(ValueToName::value_type(id, name));
  nameToValue_.insert(NameToValue::value_type(name, id));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Enum Value

EnumValue::EnumValue(EnumType* t, size_t v)
    : type_(t)
    , value_(v)
{
}

const std::string
EnumValue::ToString() const
{
  return type_->ToString(value_);
}

const size_t
EnumValue::ToValue() const
{
  return value_;
}

bool
EnumValue::operator==(const EnumValue& other) const
{
  ASSERT(type_ == other.type_);
  return value_ == other.value_;
}

bool
EnumValue::operator!=(const EnumValue& other) const
{
  return !(*this == other);
}

bool
EnumValue::operator<(const EnumValue& other) const
{
  ASSERT(type_ == other.type_);
  return value_ < other.value_;
}

std::ostream&
operator<<(std::ostream& s, const EnumValue& v)
{
  s << v.ToString();
  return s;
}

void
LoadEnumType(EnumType* type, FileSystem* fs, const std::string& path)
{
  ASSERT(type);

  enumlist::Enumroot root;
  const std::string  load_error = LoadProtoJson(fs, &root, path);

  std::vector<std::string> names;

  if(!load_error.empty())
  {
    std::cerr << "Failed to load enums " << path << ": " << load_error << "\n";
  }
  else
  {
    for(const auto& name : root.name())
    {
      names.push_back(name);
    }
  }

  type->AddEnums(names);
}
<|endoftext|>