<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/include/mexplus_eos_types.hpp
 *
 * Copyright 2016 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef MEXPLUS_EOS_TYPES_HPP_
#define MEXPLUS_EOS_TYPES_HPP_

#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"

#include "mexplus/mxarray.h"

#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/mat4x4.hpp"

#include "Eigen/Core"

#include "mex.h"

/**
 * @file
 * @brief Contains mexplus template specialisations to convert eos data
 * structures into Matlab.
 *
 * Note 1: These all copy the data, which I believe might be necessary, since
 * Matlab may unload a mex module (with all its allocated data) at any given
 * time.
 * Note 2: They all return double vectors and matrices, even when the data given
 * are floats. We can think about changing that if it's a speed issue, however,
 * I think double is Matlab's default data type.
 */

namespace mexplus {

/**
 * @brief Converts a glm::tquat<float> to a Matlab vector.
 *
 * @param[in] quat The quaternion to convert.
 * @return An 1x4 Matlab vector.
 */
template<>
mxArray* MxArray::from(const glm::tquat<float>& quat)
{
	MxArray out_array(MxArray::Numeric<double>(1, 4));
	for (int c = 0; c < 4; ++c) {
		out_array.set(c, quat[c]);
	}
	return out_array.release();
};

/**
 * @brief Converts a glm::tmat4x4<float> to a Matlab matrix.
 *
 * @param[in] mat The matrix to convert.
 * @return A 4x4 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const glm::tmat4x4<float>& mat)
{
	MxArray out_array(MxArray::Numeric<double>(4, 4));
	for (int r = 0; r < 4; ++r) {
		for (int c = 0; c < 4; ++c) {
			out_array.set(r, c, mat[c][r]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec2<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec2's to an n x 2 Matlab matrix,
 * where n is data.size(). It is mainly used to pass texture coordinates of
 * a Mesh to Matlab.
 *
 * We specialise for std::vector<glm::tvec2<float>> directly (and not for
 * glm::tvec2<float>) because otherwise a cell array of vec2's would be
 * generated. Luckily, even if a tvec2 specialisation was to exist too,
 * this one would take precedence to convert a vector<tvec2>.
 *
 * @param[in] data The data to convert.
 * @return An n x 2 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec2<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 2));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 2; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec3<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec3's to an n x 3 Matlab matrix,
 * where n is data.size(). It is mainly used to pass vertex colour data of
 * a Mesh to Matlab.
 *
 * See template<> mxArray* MxArray::from(const std::vector<glm::tvec2<float>>&)
 * for more details.
 *
 * @param[in] data The data to convert.
 * @return An n x 3 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec3<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 3));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 3; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec4<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec4's to an n x 4 Matlab matrix,
 * where n is data.size(). It is mainly used to pass vertex data of a Mesh
 * to Matlab.
 *
 * See template<> mxArray* MxArray::from(const std::vector<glm::tvec2<float>>&)
 * for more details.
 *
 * @param[in] data The data to convert.
 * @return An n x 4 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec4<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 4));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 4; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of std::array<int, 3> to a Matlab matrix.
 *
 * This function converts a whole vector of array<int, 3>'s to an n x 3 Matlab
 * matrix, where n is data.size(). It is mainly used to pass triangle indices
 * data of a Mesh to Matlab.
 *
 * We specialise for vector<array<int, 3>> directly (and not for array<int, 3>)
 * because otherwise a cell array of arrays would be generated. Luckily, even
 * if an array<int, 3> specialisation was to exist too, this one would take
 * precedence to convert a vector<array<int, 3>>.
 *
 * @param[in] data The data to convert.
 * @return An n x 3 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<std::array<int, 3>>& data)
{
	MxArray out_array(MxArray::Numeric<int>(data.size(), 3));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 3; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Define a template specialisation for eos::render::Mesh.
 *
 * This converts an eos::render::Mesh into a Matlab struct.
 *
 * @param[in] mesh The Mesh that will be returned to Matlab.
 * @return An mxArray containing a Matlab struct with all vertex, colour, texcoords and triangle data.
 */
template<>
mxArray* MxArray::from(const eos::core::Mesh& mesh)
{
	// C++ counts the vertex indices starting at zero, Matlab starts counting
	// at one - therefore, add +1 to all triangle indices:
	auto tvi_1based = mesh.tvi;
	for (auto&& t : tvi_1based) {
		for (auto&& idx : t) {
			idx += 1;
		}
	}
	// Same for tci:
	auto tci_1based = mesh.tci;
	for (auto&& t : tci_1based) {
		for (auto&& idx : t) {
			idx += 1;
		}
	}

	MxArray out_array(MxArray::Struct());
	out_array.set("vertices", mesh.vertices);
	out_array.set("colors", mesh.colors);
	out_array.set("texcoords", mesh.texcoords);
	out_array.set("tvi", tvi_1based);
	out_array.set("tci", tci_1based);

	return out_array.release();
};

/**
 * @brief Define a template specialisation for eos::fitting::RenderingParameters.
 *
 * This converts an eos::fitting::RenderingParameters into a Matlab struct.
 *
 * @param[in] rendering_parameters The RenderingParameters that will be returned to Matlab.
 * @return An mxArray containing a Matlab struct with all required parameters.
 */
template<>
mxArray* MxArray::from(const eos::fitting::RenderingParameters& rendering_parameters) {

	MxArray out_array(MxArray::Struct());

	const std::string camera_type = [&rendering_parameters]() {
		if (rendering_parameters.get_camera_type() == eos::fitting::CameraType::Orthographic)
		{
			return "Orthographic";
		}
		else if (rendering_parameters.get_camera_type() == eos::fitting::CameraType::Perspective) {
			return "Perspective";
		}
		else {
			return "unknown";
		}
	}();

	// Since we don't expose get_opencv_viewport(), and Matlab doesn't have glm::project()
	// anyway, we'll make a 4x4 viewport matrix available. Matlab seems to have the same
	// convention as OpenCV (top-left is the image origin).
	auto viewport = eos::fitting::get_opencv_viewport(rendering_parameters.get_screen_width(), rendering_parameters.get_screen_height());
	glm::mat4x4 viewport_matrix; // Identity matrix
	viewport_matrix[0][0] = 0.5f * viewport[2];
	viewport_matrix[3][0] = 0.5f * viewport[2] + viewport[0];
	viewport_matrix[1][1] = 0.5f * viewport[3];
	viewport_matrix[3][1] = 0.5f * viewport[3] + viewport[1];
	viewport_matrix[2][2] = 0.5f;
	viewport_matrix[3][2] = 0.5f;

	out_array.set("camera_type", camera_type);
	out_array.set("rotation_quaternion", rendering_parameters.get_rotation());
	out_array.set("modelview", rendering_parameters.get_modelview());
	out_array.set("projection", rendering_parameters.get_projection());
	out_array.set("viewport", viewport_matrix);
	out_array.set("screen_width", rendering_parameters.get_screen_width());
	out_array.set("screen_height", rendering_parameters.get_screen_height());

	return out_array.release();
};

} /* namespace mexplus */

#endif /* MEXPLUS_EOS_TYPES_HPP_ */
<commit_msg>Added missing includes<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: matlab/include/mexplus_eos_types.hpp
 *
 * Copyright 2016 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef MEXPLUS_EOS_TYPES_HPP_
#define MEXPLUS_EOS_TYPES_HPP_

#include "eos/core/Mesh.hpp"
#include "eos/fitting/RenderingParameters.hpp"

#include "mexplus/mxarray.h"

#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"
#include "glm/gtc/quaternion.hpp"
#include "glm/mat4x4.hpp"

#include "Eigen/Core"

#include "mex.h"

#include <array>
#include <vector>

/**
 * @file
 * @brief Contains mexplus template specialisations to convert eos data
 * structures into Matlab.
 *
 * Note 1: These all copy the data, which I believe might be necessary, since
 * Matlab may unload a mex module (with all its allocated data) at any given
 * time.
 * Note 2: They all return double vectors and matrices, even when the data given
 * are floats. We can think about changing that if it's a speed issue, however,
 * I think double is Matlab's default data type.
 */

namespace mexplus {

/**
 * @brief Converts a glm::tquat<float> to a Matlab vector.
 *
 * @param[in] quat The quaternion to convert.
 * @return An 1x4 Matlab vector.
 */
template<>
mxArray* MxArray::from(const glm::tquat<float>& quat)
{
	MxArray out_array(MxArray::Numeric<double>(1, 4));
	for (int c = 0; c < 4; ++c) {
		out_array.set(c, quat[c]);
	}
	return out_array.release();
};

/**
 * @brief Converts a glm::tmat4x4<float> to a Matlab matrix.
 *
 * @param[in] mat The matrix to convert.
 * @return A 4x4 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const glm::tmat4x4<float>& mat)
{
	MxArray out_array(MxArray::Numeric<double>(4, 4));
	for (int r = 0; r < 4; ++r) {
		for (int c = 0; c < 4; ++c) {
			out_array.set(r, c, mat[c][r]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec2<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec2's to an n x 2 Matlab matrix,
 * where n is data.size(). It is mainly used to pass texture coordinates of
 * a Mesh to Matlab.
 *
 * We specialise for std::vector<glm::tvec2<float>> directly (and not for
 * glm::tvec2<float>) because otherwise a cell array of vec2's would be
 * generated. Luckily, even if a tvec2 specialisation was to exist too,
 * this one would take precedence to convert a vector<tvec2>.
 *
 * @param[in] data The data to convert.
 * @return An n x 2 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec2<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 2));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 2; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec3<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec3's to an n x 3 Matlab matrix,
 * where n is data.size(). It is mainly used to pass vertex colour data of
 * a Mesh to Matlab.
 *
 * See template<> mxArray* MxArray::from(const std::vector<glm::tvec2<float>>&)
 * for more details.
 *
 * @param[in] data The data to convert.
 * @return An n x 3 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec3<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 3));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 3; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of glm::tvec4<float> to a Matlab matrix.
 *
 * This function converts a whole vector of vec4's to an n x 4 Matlab matrix,
 * where n is data.size(). It is mainly used to pass vertex data of a Mesh
 * to Matlab.
 *
 * See template<> mxArray* MxArray::from(const std::vector<glm::tvec2<float>>&)
 * for more details.
 *
 * @param[in] data The data to convert.
 * @return An n x 4 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<glm::tvec4<float>>& data)
{
	MxArray out_array(MxArray::Numeric<double>(data.size(), 4));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 4; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Converts an std::vector of std::array<int, 3> to a Matlab matrix.
 *
 * This function converts a whole vector of array<int, 3>'s to an n x 3 Matlab
 * matrix, where n is data.size(). It is mainly used to pass triangle indices
 * data of a Mesh to Matlab.
 *
 * We specialise for vector<array<int, 3>> directly (and not for array<int, 3>)
 * because otherwise a cell array of arrays would be generated. Luckily, even
 * if an array<int, 3> specialisation was to exist too, this one would take
 * precedence to convert a vector<array<int, 3>>.
 *
 * @param[in] data The data to convert.
 * @return An n x 3 Matlab matrix.
 */
template<>
mxArray* MxArray::from(const std::vector<std::array<int, 3>>& data)
{
	MxArray out_array(MxArray::Numeric<int>(data.size(), 3));
	for (int r = 0; r < data.size(); ++r) {
		for (int c = 0; c < 3; ++c) {
			out_array.set(r, c, data[r][c]);
		}
	}
	return out_array.release();
};

/**
 * @brief Define a template specialisation for eos::render::Mesh.
 *
 * This converts an eos::render::Mesh into a Matlab struct.
 *
 * @param[in] mesh The Mesh that will be returned to Matlab.
 * @return An mxArray containing a Matlab struct with all vertex, colour, texcoords and triangle data.
 */
template<>
mxArray* MxArray::from(const eos::core::Mesh& mesh)
{
	// C++ counts the vertex indices starting at zero, Matlab starts counting
	// at one - therefore, add +1 to all triangle indices:
	auto tvi_1based = mesh.tvi;
	for (auto&& t : tvi_1based) {
		for (auto&& idx : t) {
			idx += 1;
		}
	}
	// Same for tci:
	auto tci_1based = mesh.tci;
	for (auto&& t : tci_1based) {
		for (auto&& idx : t) {
			idx += 1;
		}
	}

	MxArray out_array(MxArray::Struct());
	out_array.set("vertices", mesh.vertices);
	out_array.set("colors", mesh.colors);
	out_array.set("texcoords", mesh.texcoords);
	out_array.set("tvi", tvi_1based);
	out_array.set("tci", tci_1based);

	return out_array.release();
};

/**
 * @brief Define a template specialisation for eos::fitting::RenderingParameters.
 *
 * This converts an eos::fitting::RenderingParameters into a Matlab struct.
 *
 * @param[in] rendering_parameters The RenderingParameters that will be returned to Matlab.
 * @return An mxArray containing a Matlab struct with all required parameters.
 */
template<>
mxArray* MxArray::from(const eos::fitting::RenderingParameters& rendering_parameters) {

	MxArray out_array(MxArray::Struct());

	const std::string camera_type = [&rendering_parameters]() {
		if (rendering_parameters.get_camera_type() == eos::fitting::CameraType::Orthographic)
		{
			return "Orthographic";
		}
		else if (rendering_parameters.get_camera_type() == eos::fitting::CameraType::Perspective) {
			return "Perspective";
		}
		else {
			return "unknown";
		}
	}();

	// Since we don't expose get_opencv_viewport(), and Matlab doesn't have glm::project()
	// anyway, we'll make a 4x4 viewport matrix available. Matlab seems to have the same
	// convention as OpenCV (top-left is the image origin).
	auto viewport = eos::fitting::get_opencv_viewport(rendering_parameters.get_screen_width(), rendering_parameters.get_screen_height());
	glm::mat4x4 viewport_matrix; // Identity matrix
	viewport_matrix[0][0] = 0.5f * viewport[2];
	viewport_matrix[3][0] = 0.5f * viewport[2] + viewport[0];
	viewport_matrix[1][1] = 0.5f * viewport[3];
	viewport_matrix[3][1] = 0.5f * viewport[3] + viewport[1];
	viewport_matrix[2][2] = 0.5f;
	viewport_matrix[3][2] = 0.5f;

	out_array.set("camera_type", camera_type);
	out_array.set("rotation_quaternion", rendering_parameters.get_rotation());
	out_array.set("modelview", rendering_parameters.get_modelview());
	out_array.set("projection", rendering_parameters.get_projection());
	out_array.set("viewport", viewport_matrix);
	out_array.set("screen_width", rendering_parameters.get_screen_width());
	out_array.set("screen_height", rendering_parameters.get_screen_height());

	return out_array.release();
};

} /* namespace mexplus */

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


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#ifndef _OCTREE_HPP_
#define _OCTREE_HPP_

#include <boost/format.hpp>
#include <boost/utility.hpp>
#include <vector>
#include <iostream>
#include <deque>

namespace mapnik {

   typedef uint8_t byte ;
   struct rgb
   {
         byte r;
         byte g;
         byte b;
         rgb(byte r_, byte b_, byte g_)
            : r(r_), g(g_), b(b_) {}
   };

   struct RGBPolicy
   {
         const static unsigned MAX_LEVELS = 6;
         inline static unsigned index_from_level(unsigned level, rgb const& c)
         {
            unsigned shift = (MAX_LEVELS + 1) - level;
            return (((c.r >> shift) & 1) << 2)
               | (((c.g >> shift) & 1) << 1)
               | ((c.b >> shift) & 1);
         }
   };

   template <typename T, typename InsertPolicy = RGBPolicy >
   class octree : private boost::noncopyable
   {
         struct node
         {
               node ()
                  :  reds(0),
                     greens(0),
                     blues(0),
                     count(0),
                     count2(0),
                     index(0)
               {
                  memset(&children_[0],0,sizeof(children_));
               }

               ~node ()
               {
                  for (unsigned i = 0;i < 8; ++i) {
                     if (children_[i] != 0) delete children_[i],children_[i]=0;
                  }
               }

               bool is_leaf() const { return count == 0; }
               node * children_[8];
               unsigned reds;
               unsigned greens;
               unsigned blues;
               unsigned count;
               unsigned count2;
               uint8_t  index;
         };
         struct node_cmp
         {
               bool operator() ( const node * lhs,const node* rhs) const
               {
                  return lhs->count2 < rhs->count2;
               }
         };

         std::deque<node*> reducible_[InsertPolicy::MAX_LEVELS];
         unsigned max_colors_;
         unsigned colors_;
         unsigned leaf_level_;

      public:
         explicit octree(unsigned max_colors=256)
            : max_colors_(max_colors),
              colors_(0),
              leaf_level_(InsertPolicy::MAX_LEVELS),
              root_(new node())
         {}

         ~octree() { delete root_;}

         void insert(T const& data)
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (true) {
               cur_node->count2++;

               if ( cur_node->count > 0 || level == leaf_level_)
               {
                  cur_node->reds   += data.r;
                  cur_node->greens += data.g;
                  cur_node->blues  += data.b;
                  cur_node->count  += 1;
                  if (cur_node->count == 1) ++colors_;
                  //if (colors_ >= max_colors_ - 1)
                  //reduce();
                  break;
               }

               unsigned idx = InsertPolicy::index_from_level(level,data);
               if (cur_node->children_[idx] == 0) {
                  cur_node->children_[idx] = new node();
                  if (level < leaf_level_-1)
                  {
                     reducible_[level+1].push_back(cur_node->children_[idx]);
                  }
               }
               cur_node = cur_node->children_[idx];
               ++level;
            }
         }

         int quantize(rgb const& c) const
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (cur_node)
            {
               if (cur_node->count != 0) return cur_node->index;
               unsigned idx = InsertPolicy::index_from_level(level,c);
               cur_node = cur_node->children_[idx];
               ++level;
            }
            return -1;
         }

         void create_palette(std::vector<rgb> & palette)
         {
            reduce();
            palette.reserve(colors_);
            create_palette(palette, root_);
         }

         void reduce()
         {
            // sort reducible
            for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
            {
               std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
            }

            while ( colors_ >= max_colors_ - 1)
            {
               while (leaf_level_ >0  && reducible_[leaf_level_-1].size() == 0)
               {
                  --leaf_level_;
               }

               if (leaf_level_ < 1) continue;

               if ( reducible_[leaf_level_-1].size() == 0) return;

               typename std::deque<node*>::iterator pos = reducible_[leaf_level_-1].begin();
               node * cur_node = *pos;
               unsigned num_children = 0;
               for (unsigned idx=0; idx < 8; ++idx)
               {
                  if (cur_node->children_[idx] != 0)
                  {
                     ++num_children;
                     cur_node->reds   += cur_node->children_[idx]->reds;
                     cur_node->greens += cur_node->children_[idx]->greens;
                     cur_node->blues  += cur_node->children_[idx]->blues;
                     cur_node->count  += cur_node->children_[idx]->count;
                     delete cur_node->children_[idx], cur_node->children_[idx]=0;
                  }
               }

               reducible_[leaf_level_-1].erase(pos);
               if (num_children > 0 )
               {
                  colors_ -= (num_children - 1);
               }
            }
         }

         void create_palette(std::vector<rgb> & palette, node * itr) const
         {
            if (itr->count != 0)
            {
               unsigned count = itr->count;
               palette.push_back(rgb(uint8_t(itr->reds/float(count)),
                                     uint8_t(itr->greens/float(count)),
                                     uint8_t(itr->blues/float(count))));
               itr->index = palette.size() - 1;
            }
            for (unsigned i=0; i < 8 ;++i)
            {
               if (itr->children_[i] != 0)
                  create_palette(palette, itr->children_[i]);
            }
         }
      private:
         node * root_;
   };
} // namespace mapnik

#endif /* _OCTREE_HPP_ */
<commit_msg>+ add missing header cstdint.hpp<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#ifndef _OCTREE_HPP_
#define _OCTREE_HPP_

// boost
#include <boost/cstdint.hpp>
#include <boost/format.hpp>
#include <boost/utility.hpp>

// stl
#include <vector>
#include <iostream>
#include <deque>

namespace mapnik {

   typedef uint8_t byte ;
   struct rgb
   {
         byte r;
         byte g;
         byte b;
         rgb(byte r_, byte b_, byte g_)
            : r(r_), g(g_), b(b_) {}
   };

   struct RGBPolicy
   {
         const static unsigned MAX_LEVELS = 6;
         inline static unsigned index_from_level(unsigned level, rgb const& c)
         {
            unsigned shift = (MAX_LEVELS + 1) - level;
            return (((c.r >> shift) & 1) << 2)
               | (((c.g >> shift) & 1) << 1)
               | ((c.b >> shift) & 1);
         }
   };

   template <typename T, typename InsertPolicy = RGBPolicy >
   class octree : private boost::noncopyable
   {
         struct node
         {
               node ()
                  :  reds(0),
                     greens(0),
                     blues(0),
                     count(0),
                     count2(0),
                     index(0)
               {
                  memset(&children_[0],0,sizeof(children_));
               }

               ~node ()
               {
                  for (unsigned i = 0;i < 8; ++i) {
                     if (children_[i] != 0) delete children_[i],children_[i]=0;
                  }
               }

               bool is_leaf() const { return count == 0; }
               node * children_[8];
               unsigned reds;
               unsigned greens;
               unsigned blues;
               unsigned count;
               unsigned count2;
               uint8_t  index;
         };
         struct node_cmp
         {
               bool operator() ( const node * lhs,const node* rhs) const
               {
                  return lhs->count2 < rhs->count2;
               }
         };

         std::deque<node*> reducible_[InsertPolicy::MAX_LEVELS];
         unsigned max_colors_;
         unsigned colors_;
         unsigned leaf_level_;

      public:
         explicit octree(unsigned max_colors=256)
            : max_colors_(max_colors),
              colors_(0),
              leaf_level_(InsertPolicy::MAX_LEVELS),
              root_(new node())
         {}

         ~octree() { delete root_;}

         void insert(T const& data)
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (true) {
               cur_node->count2++;

               if ( cur_node->count > 0 || level == leaf_level_)
               {
                  cur_node->reds   += data.r;
                  cur_node->greens += data.g;
                  cur_node->blues  += data.b;
                  cur_node->count  += 1;
                  if (cur_node->count == 1) ++colors_;
                  //if (colors_ >= max_colors_ - 1)
                  //reduce();
                  break;
               }

               unsigned idx = InsertPolicy::index_from_level(level,data);
               if (cur_node->children_[idx] == 0) {
                  cur_node->children_[idx] = new node();
                  if (level < leaf_level_-1)
                  {
                     reducible_[level+1].push_back(cur_node->children_[idx]);
                  }
               }
               cur_node = cur_node->children_[idx];
               ++level;
            }
         }

         int quantize(rgb const& c) const
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (cur_node)
            {
               if (cur_node->count != 0) return cur_node->index;
               unsigned idx = InsertPolicy::index_from_level(level,c);
               cur_node = cur_node->children_[idx];
               ++level;
            }
            return -1;
         }

         void create_palette(std::vector<rgb> & palette)
         {
            reduce();
            palette.reserve(colors_);
            create_palette(palette, root_);
         }

         void reduce()
         {
            // sort reducible
            for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
            {
               std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
            }

            while ( colors_ >= max_colors_ - 1)
            {
               while (leaf_level_ >0  && reducible_[leaf_level_-1].size() == 0)
               {
                  --leaf_level_;
               }

               if (leaf_level_ < 1) continue;

               if ( reducible_[leaf_level_-1].size() == 0) return;

               typename std::deque<node*>::iterator pos = reducible_[leaf_level_-1].begin();
               node * cur_node = *pos;
               unsigned num_children = 0;
               for (unsigned idx=0; idx < 8; ++idx)
               {
                  if (cur_node->children_[idx] != 0)
                  {
                     ++num_children;
                     cur_node->reds   += cur_node->children_[idx]->reds;
                     cur_node->greens += cur_node->children_[idx]->greens;
                     cur_node->blues  += cur_node->children_[idx]->blues;
                     cur_node->count  += cur_node->children_[idx]->count;
                     delete cur_node->children_[idx], cur_node->children_[idx]=0;
                  }
               }

               reducible_[leaf_level_-1].erase(pos);
               if (num_children > 0 )
               {
                  colors_ -= (num_children - 1);
               }
            }
         }

         void create_palette(std::vector<rgb> & palette, node * itr) const
         {
            if (itr->count != 0)
            {
               unsigned count = itr->count;
               palette.push_back(rgb(uint8_t(itr->reds/float(count)),
                                     uint8_t(itr->greens/float(count)),
                                     uint8_t(itr->blues/float(count))));
               itr->index = palette.size() - 1;
            }
            for (unsigned i=0; i < 8 ;++i)
            {
               if (itr->children_[i] != 0)
                  create_palette(palette, itr->children_[i]);
            }
         }
      private:
         node * root_;
   };
} // namespace mapnik

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


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * Copyright (c) 2015 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef INCLUDED_MDDS_TRIE_MAP_HPP
#define INCLUDED_MDDS_TRIE_MAP_HPP

#include <vector>
#include <string>
#include <deque>
#include <map>

namespace mdds {

namespace trie {

/**
 * String trait that uses std::string as the key type.
 */
struct std_string_trait
{
    typedef std::string string_type;
    typedef std::string buffer_type;
    typedef char char_type;

    static buffer_type init_buffer(const char_type* str, size_t length)
    {
        return buffer_type(str, length);
    }

    static void push_back(buffer_type& buffer, char_type c)
    {
        buffer.push_back(c);
    }

    static void pop_back(buffer_type& buffer)
    {
        buffer.pop_back();
    }

    static string_type to_string(const buffer_type& buf)
    {
        return buf;
    }
};

}

template<typename _KeyTrait, typename _ValueT>
class packed_trie_map;

/**
 * Trie map provides storage for multiple key-value pairs where keys are
 * either strings, or otherwise consist of arrays of characters.  The keys
 * are stored in an ordered tree structure known as trie, or sometimes
 * referred to as prefix tree.
 */
template<typename _KeyTrait, typename _ValueT>
class trie_map
{
    friend class packed_trie_map<_KeyTrait, _ValueT>;

public:
    typedef packed_trie_map<_KeyTrait, _ValueT> packed_type;
    typedef _KeyTrait key_trait_type;
    typedef typename key_trait_type::string_type string_type;
    typedef typename key_trait_type::buffer_type buffer_type;
    typedef typename key_trait_type::char_type   char_type;
    typedef _ValueT value_type;
    typedef size_t size_type;
    typedef std::pair<string_type, value_type> key_value_type;

private:

    struct trie_node
    {
        typedef std::map<char_type, trie_node> children_type;

        children_type children;
        value_type value;
        bool has_value;

        trie_node() : has_value(false) {}
    };

public:

    trie_map() = delete;

    /**
     * Constructor.
     *
     * @param null_value null value to return when the find method fails to
     *                   find a matching entry.
     */
    trie_map(value_type null_value);

    /**
     * Insert a new key-value pair.
     *
     * @param key pointer to the first character of a character array that
     *            stores key value.
     * @param len length of the character array storing the key.
     * @param value value to associate with the key.
     */
    void insert(const char_type* key, size_type len, const value_type& value);

    /**
     * Erase a key and the value associated with it.
     *
     * @param key pointer to the first character of a character array that
     *            stores key value.
     * @param len length of the character array storing the key.
     *
     * @return true if a key is erased, false otherwise.
     */
    bool erase(const char_type* key, size_type len);

    /**
     * Find a value associated with a specified string key.
     *
     * @param input pointer to a C-style string whose value represents the key
     *              to match.
     * @param len length of the matching string value.
     *
     * @return value associated with the key, or the null value in case the
     *         key is not found.
     */
    value_type find(const char_type* input, size_type len) const;

    /**
     * Retrieve all key-value pairs whose keys start with specified prefix.
     * You can also retrieve all key-value pairs by passing a null prefix and
     * a length of zero.
     *
     * @param prefix pointer to a C-style string whose value represents the
     *               prefix to match.
     * @param len length of the prefix value to match.
     *
     * @return list of all matching key-value pairs sorted by the key in
     *         ascending order.
     */
    std::vector<key_value_type> prefix_search(const char_type* prefix, size_type len) const;

    /**
     * Return the number of entries in the map.
     *
     * @return the number of entries in the map.
     */
    size_type size() const;

    /**
     * Empty the container.
     */
    void clear();

    /**
     * Create a compressed and immutable version of the container which
     * provides better search performance and requires much less memory
     * footprint.
     *
     * @return an instance of mdds::packed_trie_map with the same content.
     */
    packed_type pack() const;

private:
    void insert_into_tree(
        trie_node& node, const char_type* key, const char_type* key_end, const value_type& value);

    const trie_node* find_prefix_node(
        const trie_node& node, const char_type* prefix, const char_type* prefix_end) const;

    void fill_child_node_items(
        std::vector<key_value_type>& items, buffer_type& buffer, const trie_node& node) const;

    void count_values(size_type& n, const trie_node& node) const;

private:
    value_type m_null_value;
    trie_node m_root;
};

/**
 * An immutable trie container that packs its content into a contiguous
 * array to achieve both space efficiency and lookup performance.  The user
 * of this data structure must provide a pre-constructed list of key-value
 * entries that are sorted by the key in ascending order, or construct from
 * an instance of mdds::trie_map.
 *
 * Note that, since this container is immutable, the content of the
 * container cannot be modified once constructed.
 */
template<typename _KeyTrait, typename _ValueT>
class packed_trie_map
{
public:
    typedef _KeyTrait key_trait_type;
    typedef typename key_trait_type::string_type string_type;
    typedef typename key_trait_type::buffer_type buffer_type;
    typedef typename key_trait_type::char_type   char_type;
    typedef _ValueT value_type;
    typedef size_t size_type;
    typedef std::pair<string_type, value_type> key_value_type;

    /**
     * Single key-value entry.  Caller must provide at compile time a static
     * array of these entries.
     */
    struct entry
    {
        const char_type* key;
        size_type keylen;
        value_type value;

        entry(const char_type* _key, size_type _keylen, value_type _value) :
            key(_key), keylen(_keylen), value(_value) {}
    };

private:
    struct trie_node
    {
        char_type key;
        const value_type* value;

        std::deque<trie_node*> children;

        trie_node(char_type _key) : key(_key), value(nullptr) {}
    };

    typedef std::deque<trie_node> node_pool_type;
    typedef std::vector<uintptr_t> packed_type;
    typedef std::deque<value_type> value_store_type;
    typedef std::vector<std::tuple<size_t, char_type>> child_offsets_type;

public:

    packed_trie_map() = delete;

    /**
     * Constructor that initializes the content from a static list of
     * key-value entries.  The caller must ensure that the key-value
     * entries are sorted in ascending order, else the behavior is undefined.
     *
     * @param entries pointer to the array of key-value entries.
     * @param entry_size size of the key-value entry array.
     * @param null_value null value to return when the find method fails to
     *                   find a matching entry.
     */
    packed_trie_map(const entry* entries, size_type entry_size, value_type null_value);

    /**
     * Constructor to allow construction of an instance from the content of a
     * mdds::trie_map instance.
     *
     * @param other mdds::trie_map instance to build content from.
     */
    packed_trie_map(const trie_map<key_trait_type, value_type>& other);

    /**
     * Find a value associated with a specified string key.
     *
     * @param input pointer to a C-style string whose value represents the key
     *              to match.
     * @param len length of the matching string value.
     *
     * @return value associated with the key, or the null value in case the
     *         key is not found.
     */
    value_type find(const char_type* input, size_type len) const;

    /**
     * Retrieve all key-value pairs whose keys start with specified prefix.
     * You can also retrieve all key-value pairs by passing a null prefix and
     * a length of zero.
     *
     * @param prefix pointer to a C-style string whose value represents the
     *               prefix to match.
     * @param len length of the prefix value to match.
     *
     * @return list of all matching key-value pairs sorted by the key in
     *         ascending order.
     */
    std::vector<key_value_type> prefix_search(const char_type* prefix, size_type len) const;

    /**
     * Return the number of entries in the map.
     *
     * @return the number of entries in the map.
     */
    size_type size() const;

private:
    void traverse_range(
        trie_node& root, node_pool_type& node_pool, const entry* start, const entry* end,
        size_type pos);

    size_type compact_node(const trie_node& node);
    size_type compact_node(const typename trie_map<_KeyTrait, _ValueT>::trie_node& node);

    void push_child_offsets(size_type offset, const child_offsets_type& child_offsets);

    void compact(const trie_node& root);
    void compact(const typename trie_map<_KeyTrait, _ValueT>::trie_node& root);

    const uintptr_t* find_prefix_node(
        const uintptr_t* p, const char_type* prefix, const char_type* prefix_end) const;

    void fill_child_node_items(
        std::vector<key_value_type>& items, buffer_type& buffer, const uintptr_t* p) const;

#ifdef MDDS_TRIE_MAP_DEBUG
    void dump_node(buffer_type& buffer, const trie_node& node) const;
    void dump_trie(const trie_node& root) const;
    void dump_packed_trie(const std::vector<uintptr_t>& packed) const;
#endif

private:
    value_type m_null_value;
    size_type m_entry_size;

    value_store_type m_value_store;
    packed_type m_packed;
};

}

#include "trie_map_def.inl"

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>More method docs for trie_map's.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * Copyright (c) 2015 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef INCLUDED_MDDS_TRIE_MAP_HPP
#define INCLUDED_MDDS_TRIE_MAP_HPP

#include <vector>
#include <string>
#include <deque>
#include <map>

namespace mdds {

namespace trie {

/**
 * String trait that uses std::string as the key type.  This trait can be
 * used with mdds::trie_map or mdds::packed_trie_map.
 */
struct std_string_trait
{
    /** type used to store a final string content. */
    typedef std::string string_type;

    /**
     * type used to build an intermediate string value, from which a final
     * string object is to be created.
     */
    typedef std::string buffer_type;

    /**
     * type that represents a single character inside a string or a buffer
     * object.  A string object is expected to store a series of characters of
     * this type.
     */
    typedef char char_type;

    /**
     * Function called to create and initialize a buffer object from a given
     * initial string value.
     *
     * @param str pointer to the first character of string value.
     * @param length length of the string value.
     *
     * @return buffer object containing the specified string value.
     */
    static buffer_type init_buffer(const char_type* str, size_t length)
    {
        return buffer_type(str, length);
    }

    /**
     * Function called to append a single character to the end of a string
     * buffer.
     *
     * @param buffer buffer object to append character to.
     * @param c character to append to the buffer.
     */
    static void push_back(buffer_type& buffer, char_type c)
    {
        buffer.push_back(c);
    }

    /**
     * Function called to remove a single character from the tail of an
     * existing string buffer.
     *
     * @param buffer buffer object to remove character from.
     */
    static void pop_back(buffer_type& buffer)
    {
        buffer.pop_back();
    }

    /**
     * Function called to create a final string object from an existing
     * buffer.
     *
     * @param buf buffer object to create a final string object from.
     *
     * @return string object whose content is created from the buffer object.
     */
    static string_type to_string(const buffer_type& buf)
    {
        return buf;
    }
};

}

template<typename _KeyTrait, typename _ValueT>
class packed_trie_map;

/**
 * Trie map provides storage for multiple key-value pairs where keys are
 * either strings, or otherwise consist of arrays of characters.  The keys
 * are stored in an ordered tree structure known as trie, or sometimes
 * referred to as prefix tree.
 */
template<typename _KeyTrait, typename _ValueT>
class trie_map
{
    friend class packed_trie_map<_KeyTrait, _ValueT>;

public:
    typedef packed_trie_map<_KeyTrait, _ValueT> packed_type;
    typedef _KeyTrait key_trait_type;
    typedef typename key_trait_type::string_type string_type;
    typedef typename key_trait_type::buffer_type buffer_type;
    typedef typename key_trait_type::char_type   char_type;
    typedef _ValueT value_type;
    typedef size_t size_type;
    typedef std::pair<string_type, value_type> key_value_type;

private:

    struct trie_node
    {
        typedef std::map<char_type, trie_node> children_type;

        children_type children;
        value_type value;
        bool has_value;

        trie_node() : has_value(false) {}
    };

public:

    /**
     * Not implemented.
     */
    trie_map() = delete;

    /**
     * Constructor.
     *
     * @param null_value null value to return when the find method fails to
     *                   find a matching entry.
     */
    trie_map(value_type null_value);

    /**
     * Insert a new key-value pair.
     *
     * @param key pointer to the first character of a character array that
     *            stores key value.
     * @param len length of the character array storing the key.
     * @param value value to associate with the key.
     */
    void insert(const char_type* key, size_type len, const value_type& value);

    /**
     * Erase a key and the value associated with it.
     *
     * @param key pointer to the first character of a character array that
     *            stores key value.
     * @param len length of the character array storing the key.
     *
     * @return true if a key is erased, false otherwise.
     */
    bool erase(const char_type* key, size_type len);

    /**
     * Find a value associated with a specified string key.
     *
     * @param input pointer to a C-style string whose value represents the key
     *              to match.
     * @param len length of the matching string value.
     *
     * @return value associated with the key, or the null value in case the
     *         key is not found.
     */
    value_type find(const char_type* input, size_type len) const;

    /**
     * Retrieve all key-value pairs whose keys start with specified prefix.
     * You can also retrieve all key-value pairs by passing a null prefix and
     * a length of zero.
     *
     * @param prefix pointer to a C-style string whose value represents the
     *               prefix to match.
     * @param len length of the prefix value to match.
     *
     * @return list of all matching key-value pairs sorted by the key in
     *         ascending order.
     */
    std::vector<key_value_type> prefix_search(const char_type* prefix, size_type len) const;

    /**
     * Return the number of entries in the map.
     *
     * @return the number of entries in the map.
     */
    size_type size() const;

    /**
     * Empty the container.
     */
    void clear();

    /**
     * Create a compressed and immutable version of the container which
     * provides better search performance and requires much less memory
     * footprint.
     *
     * @return an instance of mdds::packed_trie_map with the same content.
     */
    packed_type pack() const;

private:
    void insert_into_tree(
        trie_node& node, const char_type* key, const char_type* key_end, const value_type& value);

    const trie_node* find_prefix_node(
        const trie_node& node, const char_type* prefix, const char_type* prefix_end) const;

    void fill_child_node_items(
        std::vector<key_value_type>& items, buffer_type& buffer, const trie_node& node) const;

    void count_values(size_type& n, const trie_node& node) const;

private:
    value_type m_null_value;
    trie_node m_root;
};

/**
 * An immutable trie container that packs its content into a contiguous
 * array to achieve both space efficiency and lookup performance.  The user
 * of this data structure must provide a pre-constructed list of key-value
 * entries that are sorted by the key in ascending order, or construct from
 * an instance of mdds::trie_map.
 *
 * Note that, since this container is immutable, the content of the
 * container cannot be modified once constructed.
 */
template<typename _KeyTrait, typename _ValueT>
class packed_trie_map
{
public:
    typedef _KeyTrait key_trait_type;
    typedef typename key_trait_type::string_type string_type;
    typedef typename key_trait_type::buffer_type buffer_type;
    typedef typename key_trait_type::char_type   char_type;
    typedef _ValueT value_type;
    typedef size_t size_type;
    typedef std::pair<string_type, value_type> key_value_type;

    /**
     * Single key-value entry.  Caller must provide at compile time a static
     * array of these entries.
     */
    struct entry
    {
        const char_type* key;
        size_type keylen;
        value_type value;

        entry(const char_type* _key, size_type _keylen, value_type _value) :
            key(_key), keylen(_keylen), value(_value) {}
    };

private:
    struct trie_node
    {
        char_type key;
        const value_type* value;

        std::deque<trie_node*> children;

        trie_node(char_type _key) : key(_key), value(nullptr) {}
    };

    typedef std::deque<trie_node> node_pool_type;
    typedef std::vector<uintptr_t> packed_type;
    typedef std::deque<value_type> value_store_type;
    typedef std::vector<std::tuple<size_t, char_type>> child_offsets_type;

public:

    /**
     * Not implemented.
     */
    packed_trie_map() = delete;

    /**
     * Constructor that initializes the content from a static list of
     * key-value entries.  The caller must ensure that the key-value
     * entries are sorted in ascending order, else the behavior is undefined.
     *
     * @param entries pointer to the array of key-value entries.
     * @param entry_size size of the key-value entry array.
     * @param null_value null value to return when the find method fails to
     *                   find a matching entry.
     */
    packed_trie_map(const entry* entries, size_type entry_size, value_type null_value);

    /**
     * Constructor to allow construction of an instance from the content of a
     * mdds::trie_map instance.
     *
     * @param other mdds::trie_map instance to build content from.
     */
    packed_trie_map(const trie_map<key_trait_type, value_type>& other);

    /**
     * Find a value associated with a specified string key.
     *
     * @param input pointer to a C-style string whose value represents the key
     *              to match.
     * @param len length of the matching string value.
     *
     * @return value associated with the key, or the null value in case the
     *         key is not found.
     */
    value_type find(const char_type* input, size_type len) const;

    /**
     * Retrieve all key-value pairs whose keys start with specified prefix.
     * You can also retrieve all key-value pairs by passing a null prefix and
     * a length of zero.
     *
     * @param prefix pointer to a C-style string whose value represents the
     *               prefix to match.
     * @param len length of the prefix value to match.
     *
     * @return list of all matching key-value pairs sorted by the key in
     *         ascending order.
     */
    std::vector<key_value_type> prefix_search(const char_type* prefix, size_type len) const;

    /**
     * Return the number of entries in the map.
     *
     * @return the number of entries in the map.
     */
    size_type size() const;

private:
    void traverse_range(
        trie_node& root, node_pool_type& node_pool, const entry* start, const entry* end,
        size_type pos);

    size_type compact_node(const trie_node& node);
    size_type compact_node(const typename trie_map<_KeyTrait, _ValueT>::trie_node& node);

    void push_child_offsets(size_type offset, const child_offsets_type& child_offsets);

    void compact(const trie_node& root);
    void compact(const typename trie_map<_KeyTrait, _ValueT>::trie_node& root);

    const uintptr_t* find_prefix_node(
        const uintptr_t* p, const char_type* prefix, const char_type* prefix_end) const;

    void fill_child_node_items(
        std::vector<key_value_type>& items, buffer_type& buffer, const uintptr_t* p) const;

#ifdef MDDS_TRIE_MAP_DEBUG
    void dump_node(buffer_type& buffer, const trie_node& node) const;
    void dump_trie(const trie_node& root) const;
    void dump_packed_trie(const std::vector<uintptr_t>& packed) const;
#endif

private:
    value_type m_null_value;
    size_type m_entry_size;

    value_store_type m_value_store;
    packed_type m_packed;
};

}

#include "trie_map_def.inl"

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/**
 *	\file
 */

#include <rleahylib/rleahylib.hpp>
#include <client.hpp>
#include <packet.hpp>
#include <functional>

namespace MCPP {

	/**
	 *	Encapsulates information about a packet
	 *	being received from a client.
	 */
	class ReceiveEvent {

		public:

			/**
			 *	The client from which the packet was
			 *	received.
			 */
			SmartPointer<Client> & From;
			/**
			 *	The packet which was received.
			 */
			Packet & Data;

	};

	/**
	 *	Provides the facilities for routing
	 *	incoming packets to handlers.
	 */
	class PacketRouter {

		public:

			/**
			 *	The type of callback which may subscribe
			 *	to receive events.
			 */
			typedef std::function<void (ReceiveEvent)> Type;

		private:

			//	Routes
			Type play_routes [PacketImpl::LargestID+1];
			Type status_routes [PacketImpl::LargestID+1];
			Type login_routes [PacketImpl::LargestID+1];
			Type handshake_routes [PacketImpl::LargestID+1];

			inline void destroy () noexcept;
			inline void init () noexcept;

		public:

			/**
			 *	Creates a new packet router with no
			 *	routes.
			 */
			PacketRouter () noexcept;

			/**
			 *	Cleans up a packet router.
			 */
			~PacketRouter () noexcept;

			/**
			 *	Fetches a packet route.
			 *
			 *	\param [in] id
			 *		The ID of the packet whole route
			 *		shall be retrieved.
			 *	\param [it] state
			 *		The state of the packet whose route
			 *		shall be retreived.
			 *
			 *	\return
			 *		A reference to the requested route.
			 */
			Type & operator () (UInt32 id, ProtocolState state) noexcept;
			/**
			 *	Fetches a packet route.
			 *
			 *	\param [in] id
			 *		The ID of the packet whole route
			 *		shall be retrieved.
			 *	\param [it] state
			 *		The state of the packet whose route
			 *		shall be retreived.
			 *
			 *	\return
			 *		A reference to the requested route.
			 */
			const Type & operator () (UInt32 id, ProtocolState state) const noexcept;

			/**
			 *	Dispatches a packet to the appropriate
			 *	handler.
			 *
			 *	\param [in] event
			 *		The event object which represents
			 *		this receive event.
			 *	\param [in] state
			 *		The state the protocol is in.
			 */
			void operator () (ReceiveEvent event, ProtocolState state) const;

			/**
			 *	Clears all handlers.
			 */
			void Clear () noexcept;

	};

}
<commit_msg>Packet Router Header Fix<commit_after>/**
 *	\file
 */

#pragma once

#include <rleahylib/rleahylib.hpp>
#include <client.hpp>
#include <packet.hpp>
#include <functional>

namespace MCPP {

	/**
	 *	Encapsulates information about a packet
	 *	being received from a client.
	 */
	class ReceiveEvent {

		public:

			/**
			 *	The client from which the packet was
			 *	received.
			 */
			SmartPointer<Client> & From;
			/**
			 *	The packet which was received.
			 */
			Packet & Data;

	};

	/**
	 *	Provides the facilities for routing
	 *	incoming packets to handlers.
	 */
	class PacketRouter {

		public:

			/**
			 *	The type of callback which may subscribe
			 *	to receive events.
			 */
			typedef std::function<void (ReceiveEvent)> Type;

		private:

			//	Routes
			Type play_routes [PacketImpl::LargestID+1];
			Type status_routes [PacketImpl::LargestID+1];
			Type login_routes [PacketImpl::LargestID+1];
			Type handshake_routes [PacketImpl::LargestID+1];

			inline void destroy () noexcept;
			inline void init () noexcept;

		public:

			/**
			 *	Creates a new packet router with no
			 *	routes.
			 */
			PacketRouter () noexcept;

			/**
			 *	Cleans up a packet router.
			 */
			~PacketRouter () noexcept;

			/**
			 *	Fetches a packet route.
			 *
			 *	\param [in] id
			 *		The ID of the packet whole route
			 *		shall be retrieved.
			 *	\param [it] state
			 *		The state of the packet whose route
			 *		shall be retreived.
			 *
			 *	\return
			 *		A reference to the requested route.
			 */
			Type & operator () (UInt32 id, ProtocolState state) noexcept;
			/**
			 *	Fetches a packet route.
			 *
			 *	\param [in] id
			 *		The ID of the packet whole route
			 *		shall be retrieved.
			 *	\param [it] state
			 *		The state of the packet whose route
			 *		shall be retreived.
			 *
			 *	\return
			 *		A reference to the requested route.
			 */
			const Type & operator () (UInt32 id, ProtocolState state) const noexcept;

			/**
			 *	Dispatches a packet to the appropriate
			 *	handler.
			 *
			 *	\param [in] event
			 *		The event object which represents
			 *		this receive event.
			 *	\param [in] state
			 *		The state the protocol is in.
			 */
			void operator () (ReceiveEvent event, ProtocolState state) const;

			/**
			 *	Clears all handlers.
			 */
			void Clear () noexcept;

	};

}
<|endoftext|>


<commit_before>#include "testing/testing.hpp"

#include "routing_common/car_model_coefs.hpp"
#include "routing_common/maxspeed_conversion.hpp"
#include "routing_common/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/feature.hpp"

#include "platform/measurement_utils.hpp"

#include "base/macros.hpp"
#include "base/math.hpp"

#include <cstdint>
#include <vector>

using namespace routing;
using namespace std;

namespace
{
HighwayBasedSpeeds const kDefaultSpeeds = {
    {HighwayType::HighwayTrunk, InOutCitySpeedKMpH(100.0 /* in city */, 150.0 /* out city */)},
    {HighwayType::HighwayPrimary, InOutCitySpeedKMpH(90.0 /* in city */, 120.0 /* out city */)},
    {HighwayType::HighwaySecondary,
     InOutCitySpeedKMpH(SpeedKMpH(80.0 /* weight */, 70.0 /* eta */) /* in and out city*/)},
    {HighwayType::HighwayResidential,
     InOutCitySpeedKMpH(SpeedKMpH(45.0 /* weight */, 55.0 /* eta */) /* in city */,
                        SpeedKMpH(50.0 /* weight */, 60.0 /* eta */) /* out city */)},
    {HighwayType::HighwayService,
     InOutCitySpeedKMpH(SpeedKMpH(47.0 /* weight */, 36.0 /* eta */) /* in city */,
                        SpeedKMpH(50.0 /* weight */, 40.0 /* eta */) /* out city */)}};

HighwayBasedFactors const kDefaultFactors = {
    {HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
    {HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
    {HighwayType::HighwaySecondary, InOutCityFactor(1.0)},
    {HighwayType::HighwayResidential, InOutCityFactor(0.5)}};

VehicleModel::LimitsInitList const kTestLimits = {{{"highway", "trunk"}, true},
                                                   {{"highway", "primary"}, true},
                                                   {{"highway", "secondary"}, true},
                                                   {{"highway", "residential"}, true},
                                                   {{"highway", "service"}, false}};

VehicleModel::SurfaceInitList const kCarSurface = {
    {{"psurface", "paved_good"}, {0.8 /* weightFactor */, 0.9 /* etaFactor */}},
    {{"psurface", "paved_bad"}, {0.4, 0.5}},
    {{"psurface", "unpaved_good"}, {0.6, 0.8}},
    {{"psurface", "unpaved_bad"}, {0.2, 0.2}}};

class VehicleModelTest
{
public:
  VehicleModelTest() { classificator::Load(); }
};

class TestVehicleModel : public VehicleModel
{
  friend void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue);
  friend void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue);
  friend void CheckSpeedWithParams(initializer_list<uint32_t> const & types,
                                   SpeedParams const & params, SpeedKMpH const & expectedSpeed);

public:
  TestVehicleModel()
    : VehicleModel(classif(), kTestLimits, kCarSurface, {kDefaultSpeeds, kDefaultFactors})
  {
  }

  // We are not going to use offroad routing in these tests.
  SpeedKMpH const & GetOffroadSpeed() const override { return kDummy; }

private:
  static SpeedKMpH const kDummy;
};

SpeedKMpH const TestVehicleModel::kDummy = {0.0 /* weight */, 0.0 /* eta */};

uint32_t GetType(char const * s0, char const * s1 = 0, char const * s2 = 0)
{
  char const * const t[] = {s0, s1, s2};
  size_t const size = (s0 != 0) + size_t(s1 != 0) + size_t(s2 != 0);
  return classif().GetTypeByPath(vector<string>(t, t + size));
}

uint32_t GetOnewayType()
{
  return GetType("hwtag", "oneway");
}

void CheckSpeedWithParams(initializer_list<uint32_t> const & types, SpeedParams const & params,
                          SpeedKMpH const & expectedSpeed)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.GetTypeSpeed(h, params), expectedSpeed, ());
}

void CheckSpeed(initializer_list<uint32_t> const & types, InOutCitySpeedKMpH const & expectedSpeed)
{
  SpeedParams const inCity(true /* forward */, true /* in city */, Maxspeed());
  CheckSpeedWithParams(types, inCity, expectedSpeed.m_inCity);
  SpeedParams const outCity(true /* forward */, false /* in city */, Maxspeed());
  CheckSpeedWithParams(types, outCity, expectedSpeed.m_outCity);
}

void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.HasOneWayType(h), expectedValue, ());
}

void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.HasPassThroughType(h), expectedValue, ());
}
}  // namespace

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxSpeed)
{
  TestVehicleModel vehicleModel;
  TEST_EQUAL(vehicleModel.GetMaxWeightSpeed(), 150.0, ());
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed)
{
  {
    CheckSpeed({GetType("highway", "secondary", "bridge")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
    CheckSpeed({GetType("highway", "secondary", "tunnel")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
    CheckSpeed({GetType("highway", "secondary")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  }

  CheckSpeed({GetType("highway", "trunk")},
             {SpeedKMpH(100.0 /* weight */, 100.0 /* eta */) /* in city */,
              SpeedKMpH(150.0 /* weight */, 150.0 /* eta */) /* out of city */});
  CheckSpeed({GetType("highway", "primary")}, {SpeedKMpH(90.0, 90.0), SpeedKMpH(120.0, 120.0)});
  CheckSpeed({GetType("highway", "residential")}, {SpeedKMpH(22.5, 27.5), SpeedKMpH(25.0, 30.0)});
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed_MultiTypes)
{
  uint32_t const typeTunnel = GetType("highway", "secondary", "tunnel");
  uint32_t const typeSecondary = GetType("highway", "secondary");
  uint32_t const typeHighway = GetType("highway");

  CheckSpeed({typeTunnel, typeSecondary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckSpeed({typeTunnel, typeHighway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckSpeed({typeHighway, typeTunnel}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_OneWay)
{
  uint32_t const typeBridge = GetType("highway", "secondary", "bridge");
  uint32_t const typeOneway = GetOnewayType();

  CheckSpeed({typeBridge, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typeBridge, typeOneway}, true);
  CheckSpeed({typeOneway, typeBridge}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typeOneway, typeBridge}, true);

  CheckOneWay({typeOneway}, true);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_DifferentSpeeds)
{
  uint32_t const typeSecondary = GetType("highway", "secondary");
  uint32_t const typePrimary = GetType("highway", "primary");
  uint32_t const typeOneway = GetOnewayType();

  CheckSpeed({typeSecondary, typePrimary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));

  CheckSpeed({typeSecondary, typePrimary, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typePrimary, typeOneway, typeSecondary}, true);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_PassThroughAllowed)
{
  CheckPassThroughAllowed({GetType("highway", "secondary")}, true);
  CheckPassThroughAllowed({GetType("highway", "primary")}, true);
  CheckPassThroughAllowed({GetType("highway", "service")}, false);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_SpeedFactor)
{
  uint32_t const secondary = GetType("highway", "secondary");
  uint32_t const residential = GetType("highway", "residential");
  uint32_t const pavedGood = GetType("psurface", "paved_good");
  uint32_t const pavedBad = GetType("psurface", "paved_bad");
  uint32_t const unpavedGood = GetType("psurface", "unpaved_good");
  uint32_t const unpavedBad = GetType("psurface", "unpaved_bad");

  CheckSpeed({secondary, pavedGood},
             {SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* in city */,
              SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* out of city */});
  CheckSpeed({secondary, pavedBad}, {SpeedKMpH(32.0, 35.0), SpeedKMpH(32.0, 35.0)});
  CheckSpeed({secondary, unpavedGood}, {SpeedKMpH(48.0, 56.0), SpeedKMpH(48.0, 56.0)});
  CheckSpeed({secondary, unpavedBad}, {SpeedKMpH(16.0, 14.0), SpeedKMpH(16.0, 14.0)});

  CheckSpeed({residential, pavedGood}, {SpeedKMpH(18.0, 24.75), SpeedKMpH(20.0, 27.0)});
  CheckSpeed({residential, pavedBad}, {SpeedKMpH(9.0, 13.75), SpeedKMpH(10.0, 15.0)});
  CheckSpeed({residential, unpavedGood}, {SpeedKMpH(13.5, 22.0), SpeedKMpH(15.0, 24.0)});
  CheckSpeed({residential, unpavedBad}, {SpeedKMpH(4.5, 5.5), SpeedKMpH(5.0, 6.0)});
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxspeedFactor)
{
  uint32_t const secondary = GetType("highway", "secondary");
  uint32_t const residential = GetType("highway", "residential");
  uint32_t const primary = GetType("highway", "primary");
  uint32_t const pavedGood = GetType("psurface", "paved_good");
  uint32_t const unpavedBad = GetType("psurface", "unpaved_bad");

  Maxspeed const maxspeed90 =
      Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, kInvalidSpeed);
  CheckSpeedWithParams({secondary, unpavedBad},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed90),
                       SpeedKMpH(18.0));

  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed90),
                       SpeedKMpH(72.0, 81.0));

  Maxspeed const maxspeed9070 =
      Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, 70);
  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed9070),
                       SpeedKMpH(72.0, 81.0));
  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(false /* forward */, false /* in city */, maxspeed9070),
                       SpeedKMpH(56.0, 63.0));

  Maxspeed const maxspeed60 =
      Maxspeed(measurement_utils::Units::Metric, 60 /* forward speed */, kInvalidSpeed);
  CheckSpeedWithParams({residential, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed60),
                       SpeedKMpH(24.0, 27.0));
}

UNIT_TEST(VehicleModel_MultiplicationOperatorTest)
{
  SpeedKMpH const speed(90 /* weight */, 100 /* eta */);
  SpeedFactor const factor(1.0, 1.1);
  SpeedKMpH const lResult = speed * factor;
  SpeedKMpH const rResult = factor * speed;
  TEST_EQUAL(lResult, rResult, ());
  TEST(base::AlmostEqualAbs(lResult.m_weight, 90.0, 1e-7), ());
  TEST(base::AlmostEqualAbs(lResult.m_eta, 110.0, 1e-7), ());
}

UNIT_TEST(VehicleModel_CarModelValidation)
{
  vector<HighwayType> const carRoadTypes = {
      HighwayType::HighwayLivingStreet,  HighwayType::HighwayMotorway,
      HighwayType::HighwayMotorwayLink,  HighwayType::HighwayPrimary,
      HighwayType::HighwayPrimaryLink,   HighwayType::HighwayResidential,
      HighwayType::HighwayRoad,          HighwayType::HighwaySecondary,
      HighwayType::HighwaySecondaryLink, HighwayType::HighwayService,
      HighwayType::HighwayTertiary,      HighwayType::HighwayTertiaryLink,
      HighwayType::HighwayTrack,         HighwayType::HighwayTrunk,
      HighwayType::HighwayTrunkLink,     HighwayType::HighwayUnclassified,
      HighwayType::ManMadePier,          HighwayType::RailwayRailMotorVehicle,
      HighwayType::RouteFerryMotorcar,   HighwayType::RouteFerryMotorVehicle,
      HighwayType::RouteShuttleTrain};

  for (auto const hwType : carRoadTypes)
  {
    auto const factorIt = kHighwayBasedFactors.find(hwType);
    TEST(factorIt != kHighwayBasedFactors.cend(), (hwType));
    TEST(factorIt->second.IsValid(), (hwType, factorIt->second));

    auto const speedIt = kHighwayBasedSpeeds.find(hwType);
    TEST(speedIt != kHighwayBasedSpeeds.cend(), (hwType));
    TEST(speedIt->second.IsValid(), (hwType, speedIt->second));
  }
}
<commit_msg>[routing] Fixing routing common tests after updating car model.<commit_after>#include "testing/testing.hpp"

#include "routing_common/car_model_coefs.hpp"
#include "routing_common/maxspeed_conversion.hpp"
#include "routing_common/vehicle_model.hpp"

#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
#include "indexer/feature.hpp"

#include "platform/measurement_utils.hpp"

#include "base/macros.hpp"
#include "base/math.hpp"

#include <cstdint>
#include <vector>

using namespace routing;
using namespace std;

namespace
{
HighwayBasedSpeeds const kDefaultSpeeds = {
    {HighwayType::HighwayTrunk, InOutCitySpeedKMpH(100.0 /* in city */, 150.0 /* out city */)},
    {HighwayType::HighwayPrimary, InOutCitySpeedKMpH(90.0 /* in city */, 120.0 /* out city */)},
    {HighwayType::HighwaySecondary,
     InOutCitySpeedKMpH(SpeedKMpH(80.0 /* weight */, 70.0 /* eta */) /* in and out city*/)},
    {HighwayType::HighwayResidential,
     InOutCitySpeedKMpH(SpeedKMpH(45.0 /* weight */, 55.0 /* eta */) /* in city */,
                        SpeedKMpH(50.0 /* weight */, 60.0 /* eta */) /* out city */)},
    {HighwayType::HighwayService,
     InOutCitySpeedKMpH(SpeedKMpH(47.0 /* weight */, 36.0 /* eta */) /* in city */,
                        SpeedKMpH(50.0 /* weight */, 40.0 /* eta */) /* out city */)}};

HighwayBasedFactors const kDefaultFactors = {
    {HighwayType::HighwayTrunk, InOutCityFactor(1.0)},
    {HighwayType::HighwayPrimary, InOutCityFactor(1.0)},
    {HighwayType::HighwaySecondary, InOutCityFactor(1.0)},
    {HighwayType::HighwayResidential, InOutCityFactor(0.5)}};

VehicleModel::LimitsInitList const kTestLimits = {{{"highway", "trunk"}, true},
                                                   {{"highway", "primary"}, true},
                                                   {{"highway", "secondary"}, true},
                                                   {{"highway", "residential"}, true},
                                                   {{"highway", "service"}, false}};

VehicleModel::SurfaceInitList const kCarSurface = {
    {{"psurface", "paved_good"}, {0.8 /* weightFactor */, 0.9 /* etaFactor */}},
    {{"psurface", "paved_bad"}, {0.4, 0.5}},
    {{"psurface", "unpaved_good"}, {0.6, 0.8}},
    {{"psurface", "unpaved_bad"}, {0.2, 0.2}}};

class VehicleModelTest
{
public:
  VehicleModelTest() { classificator::Load(); }
};

class TestVehicleModel : public VehicleModel
{
  friend void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue);
  friend void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue);
  friend void CheckSpeedWithParams(initializer_list<uint32_t> const & types,
                                   SpeedParams const & params, SpeedKMpH const & expectedSpeed);

public:
  TestVehicleModel()
    : VehicleModel(classif(), kTestLimits, kCarSurface, {kDefaultSpeeds, kDefaultFactors})
  {
  }

  // We are not going to use offroad routing in these tests.
  SpeedKMpH const & GetOffroadSpeed() const override { return kDummy; }

private:
  static SpeedKMpH const kDummy;
};

SpeedKMpH const TestVehicleModel::kDummy = {0.0 /* weight */, 0.0 /* eta */};

uint32_t GetType(char const * s0, char const * s1 = 0, char const * s2 = 0)
{
  char const * const t[] = {s0, s1, s2};
  size_t const size = (s0 != 0) + size_t(s1 != 0) + size_t(s2 != 0);
  return classif().GetTypeByPath(vector<string>(t, t + size));
}

uint32_t GetOnewayType()
{
  return GetType("hwtag", "oneway");
}

void CheckSpeedWithParams(initializer_list<uint32_t> const & types, SpeedParams const & params,
                          SpeedKMpH const & expectedSpeed)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.GetTypeSpeed(h, params), expectedSpeed, ());
}

void CheckSpeed(initializer_list<uint32_t> const & types, InOutCitySpeedKMpH const & expectedSpeed)
{
  SpeedParams const inCity(true /* forward */, true /* in city */, Maxspeed());
  CheckSpeedWithParams(types, inCity, expectedSpeed.m_inCity);
  SpeedParams const outCity(true /* forward */, false /* in city */, Maxspeed());
  CheckSpeedWithParams(types, outCity, expectedSpeed.m_outCity);
}

void CheckOneWay(initializer_list<uint32_t> const & types, bool expectedValue)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.HasOneWayType(h), expectedValue, ());
}

void CheckPassThroughAllowed(initializer_list<uint32_t> const & types, bool expectedValue)
{
  TestVehicleModel vehicleModel;
  feature::TypesHolder h;
  for (uint32_t t : types)
    h.Add(t);

  TEST_EQUAL(vehicleModel.HasPassThroughType(h), expectedValue, ());
}
}  // namespace

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxSpeed)
{
  TestVehicleModel vehicleModel;
  TEST_EQUAL(vehicleModel.GetMaxWeightSpeed(), 150.0, ());
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed)
{
  {
    CheckSpeed({GetType("highway", "secondary", "bridge")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
    CheckSpeed({GetType("highway", "secondary", "tunnel")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
    CheckSpeed({GetType("highway", "secondary")}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  }

  CheckSpeed({GetType("highway", "trunk")},
             {SpeedKMpH(100.0 /* weight */, 100.0 /* eta */) /* in city */,
              SpeedKMpH(150.0 /* weight */, 150.0 /* eta */) /* out of city */});
  CheckSpeed({GetType("highway", "primary")}, {SpeedKMpH(90.0, 90.0), SpeedKMpH(120.0, 120.0)});
  CheckSpeed({GetType("highway", "residential")}, {SpeedKMpH(45, 27.5), SpeedKMpH(50.0, 30.0)});
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_Speed_MultiTypes)
{
  uint32_t const typeTunnel = GetType("highway", "secondary", "tunnel");
  uint32_t const typeSecondary = GetType("highway", "secondary");
  uint32_t const typeHighway = GetType("highway");

  CheckSpeed({typeTunnel, typeSecondary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckSpeed({typeTunnel, typeHighway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckSpeed({typeHighway, typeTunnel}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_OneWay)
{
  uint32_t const typeBridge = GetType("highway", "secondary", "bridge");
  uint32_t const typeOneway = GetOnewayType();

  CheckSpeed({typeBridge, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typeBridge, typeOneway}, true);
  CheckSpeed({typeOneway, typeBridge}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typeOneway, typeBridge}, true);

  CheckOneWay({typeOneway}, true);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_DifferentSpeeds)
{
  uint32_t const typeSecondary = GetType("highway", "secondary");
  uint32_t const typePrimary = GetType("highway", "primary");
  uint32_t const typeOneway = GetOnewayType();

  CheckSpeed({typeSecondary, typePrimary}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));

  CheckSpeed({typeSecondary, typePrimary, typeOneway}, kDefaultSpeeds.at(HighwayType::HighwaySecondary));
  CheckOneWay({typePrimary, typeOneway, typeSecondary}, true);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_PassThroughAllowed)
{
  CheckPassThroughAllowed({GetType("highway", "secondary")}, true);
  CheckPassThroughAllowed({GetType("highway", "primary")}, true);
  CheckPassThroughAllowed({GetType("highway", "service")}, false);
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_SpeedFactor)
{
  uint32_t const secondary = GetType("highway", "secondary");
  uint32_t const residential = GetType("highway", "residential");
  uint32_t const pavedGood = GetType("psurface", "paved_good");
  uint32_t const pavedBad = GetType("psurface", "paved_bad");
  uint32_t const unpavedGood = GetType("psurface", "unpaved_good");
  uint32_t const unpavedBad = GetType("psurface", "unpaved_bad");

  CheckSpeed({secondary, pavedGood},
             {SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* in city */,
              SpeedKMpH(64.0 /* weight */, 63.0 /* eta */) /* out of city */});
  CheckSpeed({secondary, pavedBad}, {SpeedKMpH(32.0, 35.0), SpeedKMpH(32.0, 35.0)});
  CheckSpeed({secondary, unpavedGood}, {SpeedKMpH(48.0, 56.0), SpeedKMpH(48.0, 56.0)});
  CheckSpeed({secondary, unpavedBad}, {SpeedKMpH(16.0, 14.0), SpeedKMpH(16.0, 14.0)});

  CheckSpeed({residential, pavedGood}, {SpeedKMpH(36.0, 24.75), SpeedKMpH(40.0, 27.0)});
  CheckSpeed({residential, pavedBad}, {SpeedKMpH(18.0, 13.75), SpeedKMpH(20.0, 15.0)});
  CheckSpeed({residential, unpavedGood}, {SpeedKMpH(27, 22.0), SpeedKMpH(30.0, 24.0)});
  CheckSpeed({residential, unpavedBad}, {SpeedKMpH(9, 5.5), SpeedKMpH(10.0, 6.0)});
}

UNIT_CLASS_TEST(VehicleModelTest, VehicleModel_MaxspeedFactor)
{
  uint32_t const secondary = GetType("highway", "secondary");
  uint32_t const residential = GetType("highway", "residential");
  uint32_t const primary = GetType("highway", "primary");
  uint32_t const pavedGood = GetType("psurface", "paved_good");
  uint32_t const unpavedBad = GetType("psurface", "unpaved_bad");

  Maxspeed const maxspeed90 =
      Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, kInvalidSpeed);
  CheckSpeedWithParams({secondary, unpavedBad},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed90),
                       SpeedKMpH(18.0));

  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed90),
                       SpeedKMpH(72.0, 81.0));

  Maxspeed const maxspeed9070 =
      Maxspeed(measurement_utils::Units::Metric, 90 /* forward speed */, 70);
  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed9070),
                       SpeedKMpH(72.0, 81.0));
  CheckSpeedWithParams({primary, pavedGood},
                       SpeedParams(false /* forward */, false /* in city */, maxspeed9070),
                       SpeedKMpH(56.0, 63.0));

  Maxspeed const maxspeed60 =
      Maxspeed(measurement_utils::Units::Metric, 60 /* forward speed */, kInvalidSpeed);
  CheckSpeedWithParams({residential, pavedGood},
                       SpeedParams(true /* forward */, false /* in city */, maxspeed60),
                       SpeedKMpH(24.0, 27.0));
}

UNIT_TEST(VehicleModel_MultiplicationOperatorTest)
{
  SpeedKMpH const speed(90 /* weight */, 100 /* eta */);
  SpeedFactor const factor(1.0, 1.1);
  SpeedKMpH const lResult = speed * factor;
  SpeedKMpH const rResult = factor * speed;
  TEST_EQUAL(lResult, rResult, ());
  TEST(base::AlmostEqualAbs(lResult.m_weight, 90.0, 1e-7), ());
  TEST(base::AlmostEqualAbs(lResult.m_eta, 110.0, 1e-7), ());
}

UNIT_TEST(VehicleModel_CarModelValidation)
{
  vector<HighwayType> const carRoadTypes = {
      HighwayType::HighwayLivingStreet,  HighwayType::HighwayMotorway,
      HighwayType::HighwayMotorwayLink,  HighwayType::HighwayPrimary,
      HighwayType::HighwayPrimaryLink,   HighwayType::HighwayResidential,
      HighwayType::HighwayRoad,          HighwayType::HighwaySecondary,
      HighwayType::HighwaySecondaryLink, HighwayType::HighwayService,
      HighwayType::HighwayTertiary,      HighwayType::HighwayTertiaryLink,
      HighwayType::HighwayTrack,         HighwayType::HighwayTrunk,
      HighwayType::HighwayTrunkLink,     HighwayType::HighwayUnclassified,
      HighwayType::ManMadePier,          HighwayType::RailwayRailMotorVehicle,
      HighwayType::RouteFerryMotorcar,   HighwayType::RouteFerryMotorVehicle,
      HighwayType::RouteShuttleTrain};

  for (auto const hwType : carRoadTypes)
  {
    auto const factorIt = kHighwayBasedFactors.find(hwType);
    TEST(factorIt != kHighwayBasedFactors.cend(), (hwType));
    TEST(factorIt->second.IsValid(), (hwType, factorIt->second));

    auto const speedIt = kHighwayBasedSpeeds.find(hwType);
    TEST(speedIt != kHighwayBasedSpeeds.cend(), (hwType));
    TEST(speedIt->second.IsValid(), (hwType, speedIt->second));
  }
}
<|endoftext|>