<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

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 FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

/* 2-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x, _ELIM)

/* 3-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS x, _ELIM)

/* -- */

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (11, ( \
    ~cpp_name~,                        /* name */ \
    ~constructor_name~,                /* constructor name */ \
    0,                                 /* constructor arity */ \
    ~full_name~,                       /* full name */ \
    ~methods~,                         /* methods */ \
    0,                                 /* NO methods */ \
    0,                                 /* augment constructor (custom func.)*/ \
    true,                              /* constructible */ \
    false,                             /* custom enumerate */ \
    ::flusspferd::native_object_base,  /* base class */ \
    0                                  /* augment prototype (custom func.) */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__no_methods             5
#define FLUSSPFERD_CD_PARAM__augment_constructor    6
#define FLUSSPFERD_CD_PARAM__constructible          7
#define FLUSSPFERD_CD_PARAM__custom_enumerate       8
#define FLUSSPFERD_CD_PARAM__base                   9
#define FLUSSPFERD_CD_PARAM__augment_prototype     10

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_no_methods, \
  p_augment_constructor, \
  p_constructible, \
  p_custom_enumerate, \
  p_base, \
  p_augment_prototype \
) \
  class p_cpp_name : public p_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      typedef boost::mpl::bool_< (p_constructible) > constructible; \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object( \
            ::flusspferd::prototype< p_base >() \
          ); \
        BOOST_PP_IF( \
          p_no_methods, \
          BOOST_PP_TUPLE_EAT(2), \
          FLUSSPFERD_CD_METHODS \
        ) (p_cpp_name, p_methods) \
        BOOST_PP_EXPR_IF( \
          p_augment_prototype, \
          p_cpp_name :: augment_prototype(proto);) \
        return proto; \
      } \
      static void augment_constructor(::flusspferd::object &o) { \
        (void)o; \
        BOOST_PP_EXPR_IF( \
          p_augment_constructor, \
          p_cpp_name :: augment_constructor(o);) \
      } \
      typedef boost::mpl::bool_< (p_custom_enumerate) > custom_enumerate; \
    }; \
    BOOST_PP_EXPR_IF( \
      p_augment_constructor, \
      static void augment_constructor(::flusspferd::object &o);) \
    BOOST_PP_EXPR_IF( \
      p_augment_prototype, \
      static void augment_prototype(::flusspferd::object &proto);) \
  private: \
  /* */

#define FLUSSPFERD_CD_METHODS(p_cpp_name, p_methods) \
  BOOST_PP_SEQ_FOR_EACH( \
    FLUSSPFERD_CD_METHOD, \
    p_cpp_name, \
    FLUSSPFERD_PP_GEN_TUPLE3SEQ(p_methods)) \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, p_method) \
  BOOST_PP_CAT( \
    FLUSSPFERD_CD_METHOD__, \
    BOOST_PP_TUPLE_ELEM(3, 1, p_method) \
  ) ( \
    p_cpp_name, \
    BOOST_PP_TUPLE_ELEM(3, 0, p_method), \
    BOOST_PP_TUPLE_ELEM(3, 2, p_method) \
  ) \
  /* */

#define FLUSSPFERD_CD_METHOD__bind(p_cpp_name, p_method_name, p_bound) \
  ::flusspferd::create_native_method( \
      proto, \
      (p_method_name), \
      & p_cpp_name :: p_bound); \
  /* */

#define FLUSSPFERD_CD_METHOD__alias(p_cpp_name, p_method_name, p_alias) \
  proto.define_property( \
    (p_method_name), \
    proto.get_property((p_alias)), \
    ::flusspferd::dont_enumerate); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<commit_msg>class_macros: reorder parameters<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

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 FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

/* 2-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x, _ELIM)

/* 3-tuple seq */

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS(x, y, z) \
  ((x, y, z)) \
  FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE3SEQ(x) \
  BOOST_PP_CAT(FLUSSPFERD_PP_GEN_TUPLE3SEQ_PROCESS x, _ELIM)

/* -- */

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (11, ( \
    ~cpp_name~,                        /* name */ \
    ::flusspferd::native_object_base,  /* base class */ \
    ~constructor_name~,                /* constructor name */ \
    0,                                 /* constructor arity */ \
    true,                              /* constructible */ \
    ~full_name~,                       /* full name */ \
    ~methods~,                         /* methods */ \
    0,                                 /* NO methods */ \
    false,                             /* custom enumerate */ \
    0,                                 /* augment constructor (custom func.)*/\
    0                                  /* augment prototype (custom func.) */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__base                   1
#define FLUSSPFERD_CD_PARAM__constructor_name       2
#define FLUSSPFERD_CD_PARAM__constructor_arity      3
#define FLUSSPFERD_CD_PARAM__constructible          4
#define FLUSSPFERD_CD_PARAM__full_name              5
#define FLUSSPFERD_CD_PARAM__methods                6
#define FLUSSPFERD_CD_PARAM__no_methods             7
#define FLUSSPFERD_CD_PARAM__custom_enumerate       8
#define FLUSSPFERD_CD_PARAM__augment_constructor    9
#define FLUSSPFERD_CD_PARAM__augment_prototype     10

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_base, \
  p_constructor_name, \
  p_constructor_arity, \
  p_constructible, \
  p_full_name, \
  p_methods, \
  p_no_methods, \
  p_custom_enumerate, \
  p_augment_constructor, \
  p_augment_prototype \
) \
  class p_cpp_name : public p_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      typedef boost::mpl::bool_< (p_constructible) > constructible; \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object( \
            ::flusspferd::prototype< p_base >() \
          ); \
        BOOST_PP_IF( \
          p_no_methods, \
          BOOST_PP_TUPLE_EAT(2), \
          FLUSSPFERD_CD_METHODS \
        ) (p_cpp_name, p_methods) \
        BOOST_PP_EXPR_IF( \
          p_augment_prototype, \
          p_cpp_name :: augment_prototype(proto);) \
        return proto; \
      } \
      static void augment_constructor(::flusspferd::object &o) { \
        (void)o; \
        BOOST_PP_EXPR_IF( \
          p_augment_constructor, \
          p_cpp_name :: augment_constructor(o);) \
      } \
      typedef boost::mpl::bool_< (p_custom_enumerate) > custom_enumerate; \
    }; \
    BOOST_PP_EXPR_IF( \
      p_augment_constructor, \
      static void augment_constructor(::flusspferd::object &o);) \
    BOOST_PP_EXPR_IF( \
      p_augment_prototype, \
      static void augment_prototype(::flusspferd::object &proto);) \
  private: \
  /* */

#define FLUSSPFERD_CD_METHODS(p_cpp_name, p_methods) \
  BOOST_PP_SEQ_FOR_EACH( \
    FLUSSPFERD_CD_METHOD, \
    p_cpp_name, \
    FLUSSPFERD_PP_GEN_TUPLE3SEQ(p_methods)) \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, p_method) \
  BOOST_PP_CAT( \
    FLUSSPFERD_CD_METHOD__, \
    BOOST_PP_TUPLE_ELEM(3, 1, p_method) \
  ) ( \
    p_cpp_name, \
    BOOST_PP_TUPLE_ELEM(3, 0, p_method), \
    BOOST_PP_TUPLE_ELEM(3, 2, p_method) \
  ) \
  /* */

#define FLUSSPFERD_CD_METHOD__bind(p_cpp_name, p_method_name, p_bound) \
  ::flusspferd::create_native_method( \
      proto, \
      (p_method_name), \
      & p_cpp_name :: p_bound); \
  /* */

#define FLUSSPFERD_CD_METHOD__alias(p_cpp_name, p_method_name, p_alias) \
  proto.define_property( \
    (p_method_name), \
    proto.get_property((p_alias)), \
    ::flusspferd::dont_enumerate); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/
#ifndef MAPNIK_TEXT_LINE_POLICY_HPP
#define MAPNIK_TEXT_LINE_POLICY_HPP

#include <mapnik/vertex_cache.hpp>
#include <mapnik/label_placements/max_line_angle_mover.hpp>

namespace mapnik
{

struct text_line_policy
{
    using params_type = label_placement::placement_params;

    text_line_policy(
        vertex_cache & path,
        text_layout_generator const & lg,
        double layout_width,
        params_type const & params)
        : layout_generator_(lg),
          params_(params),
          layout_width_(layout_width),
          minimum_path_length_(lg.get_text_props().minimum_path_length),
          path_(path)
    {
    }

    bool check_size() const
    {
        return !(
            path_.length() < minimum_path_length_ * params_.scale_factor ||
            path_.length() < layout_width_);
    }

    double get_spacing() const
    {
        return spacing_;
    }

    bool next_subpath()
    {
        if (path_.next_subpath())
        {
            spacing_ = init_spacing();
            position_tolerance_ = init_position_tolerance();
            return true;
        }
        return false;
    }

    bool align()
    {
        auto const & root_layout = layout_generator_.layouts_->root_layout();
        horizontal_alignment_e halign = root_layout.horizontal_alignment();

        // halign == H_LEFT -> don't move
        if (halign == H_MIDDLE ||
            halign == H_AUTO)
        {
            if (!path_.forward(spacing_ / 2.0))
            {
                return false;
            }
        }
        else if (halign == H_RIGHT)
        {
            if (!path_.forward(path_.length()))
            {
                return false;
            }
        }
        else if (halign == H_ADJUST)
        {
            if (!path_.forward(path_.length() / 2.0))
            {
                return false;
            }
        }

        double move_dx = root_layout.displacement().x;
        if (move_dx != 0.0)
        {
            vertex_cache::state state = path_.save_state();
            if (!path_.move(move_dx))
            {
                path_.restore_state(state);
            }
        }
        return true;
    }

    bool move(double distance)
    {
        return path_.move(distance);
    }

    bool forward(bool success)
    {
        return path_.forward(spacing_);
    }

    double position_tolerance() const
    {
        return position_tolerance_;
    }

    text_layout_generator const & layout_generator_;
    params_type const & params_;
    const double layout_width_;
    const double minimum_path_length_;
    vertex_cache & path_;
    double spacing_;
    double position_tolerance_;

private:
    double init_spacing() const
    {
        double spacing = layout_generator_.get_text_props().label_spacing;
        int num_labels = 1;
        if (spacing > 0)
        {
            double count_float = path_.length() / (spacing * params_.scale_factor + layout_width_);
            const double epsilon = std::numeric_limits<double>::epsilon() * count_float;
            bool round = std::abs(count_float - std::round(count_float)) < epsilon;
            num_labels = round ? std::round(count_float) : std::floor(count_float);
        }
        if (num_labels <= 0)
        {
            num_labels = 1;
        }
        return path_.length() / num_labels;
    }

    double init_position_tolerance() const
    {
        double tolerance = layout_generator_.get_text_props().label_position_tolerance * params_.scale_factor;
        if (tolerance > 0)
        {
            return tolerance;
        }

        auto const & root_layout = layout_generator_.layouts_->root_layout();
        horizontal_alignment_e halign = root_layout.horizontal_alignment();
        if (halign == H_ADJUST)
        {
            // Let small tolerance by default.
            return 10.0;
        }

        return spacing_ / 2.0;
    }
};

struct text_max_line_angle_policy : text_line_policy
{
    using params_type = label_placement::placement_params;

    text_max_line_angle_policy(
        vertex_cache & path,
        text_layout_generator const & lg,
        double layout_width,
        params_type const & params,
        double max_angle_diff,
        double max_angle_distance)
        : text_line_policy(path, lg, layout_width, params),
          mover_(path, max_angle_diff, max_angle_distance)
    {
    }

    bool move(double distance)
    {
        if (!text_line_policy::move(distance))
        {
            return false;
        }

        return mover_.move(distance);
    }

    max_line_angle_mover mover_;
};

}//ns mapnik

#endif // MAPNIK_TEXT_LINE_POLICY_HPP
<commit_msg>Scale factor<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/
#ifndef MAPNIK_TEXT_LINE_POLICY_HPP
#define MAPNIK_TEXT_LINE_POLICY_HPP

#include <mapnik/vertex_cache.hpp>
#include <mapnik/label_placements/max_line_angle_mover.hpp>

namespace mapnik
{

struct text_line_policy
{
    using params_type = label_placement::placement_params;

    text_line_policy(
        vertex_cache & path,
        text_layout_generator const & lg,
        double layout_width,
        params_type const & params)
        : layout_generator_(lg),
          params_(params),
          layout_width_(layout_width),
          minimum_path_length_(lg.get_text_props().minimum_path_length),
          path_(path)
    {
    }

    bool check_size() const
    {
        return !(
            path_.length() < minimum_path_length_ * params_.scale_factor ||
            path_.length() < layout_width_);
    }

    double get_spacing() const
    {
        return spacing_;
    }

    bool next_subpath()
    {
        if (path_.next_subpath())
        {
            spacing_ = init_spacing();
            position_tolerance_ = init_position_tolerance();
            return true;
        }
        return false;
    }

    bool align()
    {
        auto const & root_layout = layout_generator_.layouts_->root_layout();
        horizontal_alignment_e halign = root_layout.horizontal_alignment();

        // halign == H_LEFT -> don't move
        if (halign == H_MIDDLE ||
            halign == H_AUTO)
        {
            if (!path_.forward(spacing_ / 2.0))
            {
                return false;
            }
        }
        else if (halign == H_RIGHT)
        {
            if (!path_.forward(path_.length()))
            {
                return false;
            }
        }
        else if (halign == H_ADJUST)
        {
            if (!path_.forward(path_.length() / 2.0))
            {
                return false;
            }
        }

        double move_dx = root_layout.displacement().x;
        if (move_dx != 0.0)
        {
            vertex_cache::state state = path_.save_state();
            if (!path_.move(move_dx))
            {
                path_.restore_state(state);
            }
        }
        return true;
    }

    bool move(double distance)
    {
        return path_.move(distance);
    }

    bool forward(bool success)
    {
        return path_.forward(spacing_);
    }

    double position_tolerance() const
    {
        return position_tolerance_;
    }

    text_layout_generator const & layout_generator_;
    params_type const & params_;
    const double layout_width_;
    const double minimum_path_length_;
    vertex_cache & path_;
    double spacing_;
    double position_tolerance_;

private:
    double init_spacing() const
    {
        double spacing = layout_generator_.get_text_props().label_spacing;
        int num_labels = 1;
        if (spacing > 0)
        {
            double count_float = path_.length() / (spacing * params_.scale_factor + layout_width_);
            const double epsilon = std::numeric_limits<double>::epsilon() * count_float;
            bool round = std::abs(count_float - std::round(count_float)) < epsilon;
            num_labels = round ? std::round(count_float) : std::floor(count_float);
        }
        if (num_labels <= 0)
        {
            num_labels = 1;
        }
        return path_.length() / num_labels;
    }

    double init_position_tolerance() const
    {
        double tolerance = layout_generator_.get_text_props().label_position_tolerance * params_.scale_factor;
        if (tolerance > 0)
        {
            return tolerance;
        }

        auto const & root_layout = layout_generator_.layouts_->root_layout();
        horizontal_alignment_e halign = root_layout.horizontal_alignment();
        if (halign == H_ADJUST)
        {
            // Let small tolerance by default.
            return 10.0 * params_.scale_factor;
        }

        return spacing_ / 2.0;
    }
};

struct text_max_line_angle_policy : text_line_policy
{
    using params_type = label_placement::placement_params;

    text_max_line_angle_policy(
        vertex_cache & path,
        text_layout_generator const & lg,
        double layout_width,
        params_type const & params,
        double max_angle_diff,
        double max_angle_distance)
        : text_line_policy(path, lg, layout_width, params),
          mover_(path, max_angle_diff, max_angle_distance)
    {
    }

    bool move(double distance)
    {
        if (!text_line_policy::move(distance))
        {
            return false;
        }

        return mover_.move(distance);
    }

    max_line_angle_mover mover_;
};

}//ns mapnik

#endif // MAPNIK_TEXT_LINE_POLICY_HPP
<|endoftext|>


<commit_before>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <memory>
#include <iterator>

#include "hadesmem/config.hpp"

namespace hadesmem
{

class Process;

class ProcessEntry;

namespace detail
{

struct ProcessIteratorImpl;

}

// ModuleIterator satisfies the requirements of an input iterator
// (C++ Standard, 24.2.1, Input Iterators [input.iterators]).
class ProcessIterator : public std::iterator<std::input_iterator_tag,
  ProcessEntry>
{
public:
  ProcessIterator() HADESMEM_NOEXCEPT;

  explicit ProcessIterator(int dummy);

  reference operator*() const HADESMEM_NOEXCEPT;

  pointer operator->() const HADESMEM_NOEXCEPT;

  ProcessIterator& operator++();

  ProcessIterator operator++(int);

  bool operator==(ProcessIterator const& other) const HADESMEM_NOEXCEPT;

  bool operator!=(ProcessIterator const& other) const HADESMEM_NOEXCEPT;

private:
  // Using a shared_ptr to provide shallow copy semantics, as
  // required by InputIterator.
  std::shared_ptr<detail::ProcessIteratorImpl> impl_;
};

class ProcessList
{
public:
  typedef ProcessIterator iterator;
  typedef ProcessIterator const_iterator;

  ProcessList() HADESMEM_NOEXCEPT;

  iterator begin();

  const_iterator begin() const;

  iterator end() HADESMEM_NOEXCEPT;

  const_iterator end() const HADESMEM_NOEXCEPT;
};

}
<commit_msg>* Fix comment.<commit_after>// Copyright (C) 2010-2012 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <memory>
#include <iterator>

#include "hadesmem/config.hpp"

namespace hadesmem
{

class Process;

class ProcessEntry;

namespace detail
{

struct ProcessIteratorImpl;

}

// ProcessIterator satisfies the requirements of an input iterator
// (C++ Standard, 24.2.1, Input Iterators [input.iterators]).
class ProcessIterator : public std::iterator<std::input_iterator_tag,
  ProcessEntry>
{
public:
  ProcessIterator() HADESMEM_NOEXCEPT;

  explicit ProcessIterator(int dummy);

  reference operator*() const HADESMEM_NOEXCEPT;

  pointer operator->() const HADESMEM_NOEXCEPT;

  ProcessIterator& operator++();

  ProcessIterator operator++(int);

  bool operator==(ProcessIterator const& other) const HADESMEM_NOEXCEPT;

  bool operator!=(ProcessIterator const& other) const HADESMEM_NOEXCEPT;

private:
  // Using a shared_ptr to provide shallow copy semantics, as
  // required by InputIterator.
  std::shared_ptr<detail::ProcessIteratorImpl> impl_;
};

class ProcessList
{
public:
  typedef ProcessIterator iterator;
  typedef ProcessIterator const_iterator;

  ProcessList() HADESMEM_NOEXCEPT;

  iterator begin();

  const_iterator begin() const;

  iterator end() HADESMEM_NOEXCEPT;

  const_iterator end() const HADESMEM_NOEXCEPT;
};

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlstreamio.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "diagnose.hxx"
#include <stdio.h>
#include <stdarg.h>
#include "rtl/instance.hxx"
#include "rtl/bootstrap.hxx"

namespace xmlsecurity {

struct UseDiagnose : public rtl::StaticWithInit<
    const bool, UseDiagnose>
{
    const bool operator () ()
    {
        ::rtl::OUString value;
        sal_Bool res = rtl::Bootstrap::get(
            ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("XMLSECURITY_TRACE")), value);
        return res == sal_True ? true : false;
    }
};

/* the function will print the string when
   - build with debug
   - the bootstrap variable XMLSECURITY_TRACE is set.
 */
void xmlsec_trace(const char* pszFormat, ...)
{
    bool bDebug = false;

#if OSL_DEBUG_LEVEL > 1
    bDebug = true;
#endif
    if (bDebug || UseDiagnose::get())
    {
        va_list args;
        fprintf(stderr, "[xmlsecurity] ");
        va_start(args, pszFormat);
        vfprintf(stderr, pszFormat, args);
        va_end(args);

        fprintf(stderr,"\n");
        fflush(stderr);
    }
}

}
<commit_msg>cmcfixes73: #i110566# silence gcc warnings<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: xmlstreamio.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "diagnose.hxx"
#include <stdio.h>
#include <stdarg.h>
#include "rtl/instance.hxx"
#include "rtl/bootstrap.hxx"

namespace xmlsecurity {

struct UseDiagnose : public rtl::StaticWithInit<
    const bool, UseDiagnose>
{
    bool operator () () const
    {
        ::rtl::OUString value;
        sal_Bool res = rtl::Bootstrap::get(
            ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("XMLSECURITY_TRACE")), value);
        return res == sal_True ? true : false;
    }
};

/* the function will print the string when
   - build with debug
   - the bootstrap variable XMLSECURITY_TRACE is set.
 */
void xmlsec_trace(const char* pszFormat, ...)
{
    bool bDebug = false;

#if OSL_DEBUG_LEVEL > 1
    bDebug = true;
#endif
    if (bDebug || UseDiagnose::get())
    {
        va_list args;
        fprintf(stderr, "[xmlsecurity] ");
        va_start(args, pszFormat);
        vfprintf(stderr, pszFormat, args);
        va_end(args);

        fprintf(stderr,"\n");
        fflush(stderr);
    }
}

}
<|endoftext|>


<commit_before>/*
 * boost_date_time.hpp
 *
 *  Created on: Sep 2, 2015
 *      Author: zmij
 */

#ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BOOST_DATE_TIME_HPP_
#define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BOOST_DATE_TIME_HPP_

#include <tip/db/pg/protocol_io_traits.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/date_time.hpp>

namespace tip {
namespace db {
namespace pg {
namespace io {

namespace grammar {
namespace parse {

template < typename InputIterator >
struct time_grammar :
		boost::spirit::qi::grammar< InputIterator, boost::posix_time::time_duration()> {
	typedef boost::posix_time::time_duration value_type;
	time_grammar() : time_grammar::base_type(time)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_pass;
		using qi::_val;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		using qi::_4;
		_2digits = qi::uint_parser< std::uint32_t, 10, 2, 2 >();
		fractional_part = -('.' >> qi::long_);

		time = (_2digits >> ':' >> _2digits >> ':' >> _2digits >> fractional_part )
			[ _pass = (_1 < 24) && (_2 < 60) && (_3 < 60),
			  _val = phx::construct< value_type >(_1, _2, _3, _4)];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> time;
	boost::spirit::qi::rule< InputIterator, std::uint32_t() > _2digits;
	boost::spirit::qi::rule< InputIterator, std::uint64_t() > fractional_part;
};

template < typename InputIterator >
struct date_grammar :
		boost::spirit::qi::grammar< InputIterator, boost::gregorian::date()> {
	typedef boost::gregorian::date value_type;
	date_grammar() : date_grammar::base_type(date)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_pass;
		using qi::_val;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		_2digits = qi::uint_parser< std::uint32_t, 10, 2, 2 >();
		_4digits = qi::uint_parser< std::uint32_t, 10, 4, 4 >();
		date = (_4digits >> "-" >> _2digits >> "-" >> _2digits)
			[
			 	 _pass = _3 < 32,
				 phx::try_[
					_val = phx::construct< value_type > (_1, _2, _3)
				].catch_all[
					_pass = false
				]
			];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> date;
	boost::spirit::qi::rule< InputIterator, std::int32_t() > _2digits;
	boost::spirit::qi::rule< InputIterator, std::int32_t() > _4digits;
};

template < typename InputIterator, typename DateTime >
struct datetime_grammar;

template < typename InputIterator >
struct datetime_grammar< InputIterator, boost::posix_time::ptime > :
		boost::spirit::qi::grammar< InputIterator, boost::posix_time::ptime()> {
	typedef boost::posix_time::ptime value_type;
	datetime_grammar() : datetime_grammar::base_type(datetime)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_val;
		using qi::_1;
		using qi::_2;

		datetime = (date >> ' ' >> time)
			[ _val = phx::construct< value_type >( _1, _2) ];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> datetime;
	date_grammar< InputIterator > date;
	time_grammar< InputIterator > time;
};

}  // namespace parse
}  // namespace grammar

template < >
struct protocol_parser< boost::posix_time::ptime, TEXT_DATA_FORMAT > :
		detail::parser_base< boost::posix_time::ptime > {
	typedef detail::parser_base< boost::posix_time::ptime > base_type;
	typedef typename base_type::value_type value_type;
	protocol_parser(value_type& v) : base_type(v) {}

	size_t
	size() const;

	template < typename InputIterator >
    InputIterator
    operator()(InputIterator begin, InputIterator end)
	{
		typedef std::iterator_traits< InputIterator > iter_traits;
		typedef typename iter_traits::value_type iter_value_type;
		static_assert(std::is_same< iter_value_type, byte >::type::value,
				"Input iterator must be over a char container");
		namespace qi = boost::spirit::qi;
		namespace parse = grammar::parse;

		parse::datetime_grammar< InputIterator, value_type > grammar;
		value_type tmp;
		if (qi::parse(begin, end, grammar, tmp)) {
			std::swap(tmp, base_type::value);
		}
		return begin;
	}
};

namespace traits {

//@{
template < >
struct pgcpp_data_mapping< oids::type::timestamp > :
		detail::data_mapping_base< oids::type::timestamp, boost::posix_time::ptime > {};
template < >
struct cpppg_data_mapping< boost::posix_time::ptime > :
		detail::data_mapping_base< oids::type::timestamp, boost::posix_time::ptime > {};

template <>
struct is_nullable< boost::posix_time::ptime > : ::std::true_type {};

template <>
struct nullable_traits< boost::posix_time::ptime > {
	inline static bool
	is_null(boost::posix_time::ptime const& val)
	{
		return val.is_not_a_date_time();
	}
	inline static void
	set_null(boost::posix_time::ptime& val)
	{
		val = boost::posix_time::ptime{};
	}
};

template <>
struct needs_quotes< boost::posix_time::ptime > : ::std::true_type {};
//@}

}  // namespace traits

}  // namespace io
}  // namespace pg
}  // namespace db
}  // namespace tip

#endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BOOST_DATE_TIME_HPP_ */
<commit_msg>Check year's range<commit_after>/*
 * boost_date_time.hpp
 *
 *  Created on: Sep 2, 2015
 *      Author: zmij
 */

#ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BOOST_DATE_TIME_HPP_
#define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_IO_BOOST_DATE_TIME_HPP_

#include <tip/db/pg/protocol_io_traits.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/date_time.hpp>

namespace tip {
namespace db {
namespace pg {
namespace io {

namespace grammar {
namespace parse {

template < typename InputIterator >
struct time_grammar :
		boost::spirit::qi::grammar< InputIterator, boost::posix_time::time_duration()> {
	typedef boost::posix_time::time_duration value_type;
	time_grammar() : time_grammar::base_type(time)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_pass;
		using qi::_val;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		using qi::_4;
		_2digits = qi::uint_parser< std::uint32_t, 10, 2, 2 >();
		fractional_part = -('.' >> qi::long_);

		time = (_2digits >> ':' >> _2digits >> ':' >> _2digits >> fractional_part )
			[ _pass = (_1 < 24) && (_2 < 60) && (_3 < 60),
			  _val = phx::construct< value_type >(_1, _2, _3, _4)];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> time;
	boost::spirit::qi::rule< InputIterator, std::uint32_t() > _2digits;
	boost::spirit::qi::rule< InputIterator, std::uint64_t() > fractional_part;
};

template < typename InputIterator >
struct date_grammar :
		boost::spirit::qi::grammar< InputIterator, boost::gregorian::date()> {
	typedef boost::gregorian::date value_type;
	date_grammar() : date_grammar::base_type(date)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_pass;
		using qi::_val;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		_2digits = qi::uint_parser< std::uint32_t, 10, 2, 2 >();
		_4digits = qi::uint_parser< std::uint32_t, 10, 4, 4 >();
		date = (_4digits >> "-" >> _2digits >> "-" >> _2digits)
			[
			 	 _pass = (1400 <= _1) && (_1 <= 10000) && (_3 < 32),
				 phx::try_[
					_val = phx::construct< value_type > (_1, _2, _3)
				].catch_all[
					_pass = false
				]
			];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> date;
	boost::spirit::qi::rule< InputIterator, std::int32_t() > _2digits;
	boost::spirit::qi::rule< InputIterator, std::int32_t() > _4digits;
};

template < typename InputIterator, typename DateTime >
struct datetime_grammar;

template < typename InputIterator >
struct datetime_grammar< InputIterator, boost::posix_time::ptime > :
		boost::spirit::qi::grammar< InputIterator, boost::posix_time::ptime()> {
	typedef boost::posix_time::ptime value_type;
	datetime_grammar() : datetime_grammar::base_type(datetime)
	{
		namespace qi = boost::spirit::qi;
		namespace phx = boost::phoenix;
		using qi::_val;
		using qi::_1;
		using qi::_2;

		datetime = (date >> ' ' >> time)
			[ _val = phx::construct< value_type >( _1, _2) ];
	}
	boost::spirit::qi::rule< InputIterator, value_type()> datetime;
	date_grammar< InputIterator > date;
	time_grammar< InputIterator > time;
};

}  // namespace parse
}  // namespace grammar

template < >
struct protocol_parser< boost::posix_time::ptime, TEXT_DATA_FORMAT > :
		detail::parser_base< boost::posix_time::ptime > {
	typedef detail::parser_base< boost::posix_time::ptime > base_type;
	typedef typename base_type::value_type value_type;
	protocol_parser(value_type& v) : base_type(v) {}

	size_t
	size() const;

	template < typename InputIterator >
    InputIterator
    operator()(InputIterator begin, InputIterator end)
	{
		typedef std::iterator_traits< InputIterator > iter_traits;
		typedef typename iter_traits::value_type iter_value_type;
		static_assert(std::is_same< iter_value_type, byte >::type::value,
				"Input iterator must be over a char container");
		namespace qi = boost::spirit::qi;
		namespace parse = grammar::parse;

		parse::datetime_grammar< InputIterator, value_type > grammar;
		value_type tmp;
		if (qi::parse(begin, end, grammar, tmp)) {
			std::swap(tmp, base_type::value);
		}
		return begin;
	}
};

namespace traits {

//@{
template < >
struct pgcpp_data_mapping< oids::type::timestamp > :
		detail::data_mapping_base< oids::type::timestamp, boost::posix_time::ptime > {};
template < >
struct cpppg_data_mapping< boost::posix_time::ptime > :
		detail::data_mapping_base< oids::type::timestamp, boost::posix_time::ptime > {};

template <>
struct is_nullable< boost::posix_time::ptime > : ::std::true_type {};

template <>
struct nullable_traits< boost::posix_time::ptime > {
	inline static bool
	is_null(boost::posix_time::ptime const& val)
	{
		return val.is_not_a_date_time();
	}
	inline static void
	set_null(boost::posix_time::ptime& val)
	{
		val = boost::posix_time::ptime{};
	}
};

template <>
struct needs_quotes< boost::posix_time::ptime > : ::std::true_type {};
//@}

}  // namespace traits

}  // namespace io
}  // namespace pg
}  // namespace db
}  // namespace tip

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


<commit_before>
#include <zmq.h>

#include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <czmq.h>
#include <string>
#include <cstdio>
#include <thread>
#include <iostream>
#include <vector>
#include <sys/stat.h>
#include <mutex>
#include "TableOpenHelper.hpp"
#include "protocol.hpp"

//Feature toggle
#define BATCH_UPDATES
#define DEBUG_UPDATES
#define DEBUG_READ

const char* updateWorkerThreadAddr = "inproc://updateWorkerThread";

using namespace std;

/**
 * Encapsulates multiple key-value tables in one interface.
 * The tables are addressed by number and
 */
class KeyValueMultiTable {
public:
    typedef uint32_t IndexType;

    KeyValueMultiTable(IndexType defaultTablespaceSize = 16) : databases(32) {
        //Initialize the table array with 16 tables.
        //This avoids early re-allocation
        databasesSize = 16;
        //Use malloc here to allow usage of realloc
        //Initialize all pointers to zero
        for (int i = 0; i < databases.size(); i++) {
            databases[i] = NULL;
        }
    }

    /**
     * Close all tables and stop the table open server.
     *
     * This can't be done in the destructor because it needs to be done before
     * the context is deallocated
     */
    void cleanup() {
        fprintf(stderr, "Flushing and closing tables...\n");
        //Flush & delete all databases
        for (int i = 0; i < databasesSize; i++) {
            if (databases[i] != NULL) {
                delete databases[i];
            }
        }
    }

    leveldb::DB* getTable(IndexType index, TableOpenHelper& openHelper) {
        //Check if the database has already been opened
        if (databases[index] == NULL || index >= databases.size()) {
            openHelper.openTable(index);
        }
        return databases[index];
    }

    void closeTable(IndexType index) {
        if (databases[index] != NULL) {
            delete databases[index];
            databases[index] = NULL;
        }
    }

    leveldb::DB* getExistingTable(IndexType index) {
        return databases[index];
    }

    vector<leveldb::DB*>& getDatabases() {
        return databases;
    }
private:
    /**
     * The databases vector.
     * Any method in this class has read-only access (tables may be closed by this class however)
     *
     * Write acess is serialized using the TableOpenHelper class.
     *
     * Therefore locks and double initialization are avoided.
     */
    std::vector<leveldb::DB*> databases; //Indexed by table num
    uint32_t databasesSize;
};

/**
 * This struct is used to shared common variables across a server thread
 */
struct KVServer {

    KVServer(zctx_t* ctx) : ctx(ctx), tables(), numUpdateThreads(0) {

    }

    void initializeTableOpenHelper() {
        tableOpenHelper = new TableOpenHelper(ctx);
    }

    /**
     * Cleanup. This must be called before the ZMQ context is destroyed
     */
    void cleanup() {
        delete tableOpenHelper;
        tables.cleanup();
    }

    ~KVServer() {
        if (numUpdateThreads > 0) {
            delete[] updateWorkerThreads;
        }
        printf("Gracefully closed tables, exiting...\n");
    }
    KeyValueMultiTable tables;
    //External sockets
    void* reqRepSocket; //ROUTER socket that receives remote req/rep. READ requests can only use this socket
    void* subSocket; //SUB socket that subscribes to UPDATE requests (For mirroring etc)
    void* pullSocket; //PULL socket for UPDATE load balancinge
    void* responseProxySocket; //Worker threads connect to this PULL socket -- messages need to contain envelopes and area automatically proxied to the main router socket
    //Internal sockets
    void* updateWorkerThreadSocket; //PUSH socket that distributes update requests among worker threads
    TableOpenHelper* tableOpenHelper; //Only for use in the main thread
    //Thread info
    uint16_t numUpdateThreads;
    std::thread** updateWorkerThreads;
    //Other stuff
    zctx_t* ctx;
};

void handleReadRequest(KeyValueMultiTable& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle read request of size %d\n", (uint32_t) zmsg_size(msg) - 1);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    cout << "RM Resized to size " << zmsg_size(msg) << endl;
    //The response has doesn't have the table frame, so
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    string value; //Where the value will be placed
    leveldb::Status status;
    //Read each read request
    zframe_t* keyFrame = NULL;
    while ((keyFrame = zmsg_next(msg)) != NULL) {
        //Build a slice of the key (zero-copy)
        string keystr((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice key((char*) zframe_data(keyFrame), zframe_size(keyFrame));
#ifdef DEBUG_READ
        printf("Reading key %s from table %d\n", key.ToString().c_str(), tableId);
#endif
        status = db->Get(readOptions, key, &value);
        if (status.IsNotFound()) {
#ifdef DEBUG_READ
            cout << "Could not find value for key " << key.ToString() << "in table " << tableId << endl;
#endif
            //Empty value
            zframe_reset(keyFrame, "", 0);
        } else {
#ifdef DEBUG_READ
            cout << "Read " << value << " (key = " << key.ToString() << ") --> " << value << endl;
#endif
            zframe_reset(keyFrame, value.c_str(), value.length());
        }
    }
    //Now we can remove the table ID frame from the message (doing so before would confuse zmsg_next())
    zmsg_remove(msg, tableIdFrame);
    zframe_destroy(&tableIdFrame);
#ifdef DEBUG_READ
    cout << "Final reply msg size: " << zmsg_size(msg) << endl;
#endif
}

void handleUpdateRequest(KeyValueMultiTable& tables, zmsg_t* msg, TableOpenHelper& helper) {
    leveldb::Status status;
    leveldb::WriteOptions writeOptions;
    //Parse the table id
    //This function requires that the given message has the table id in its first frame
    zframe_t* tableIdFrame = zmsg_first(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    zmsg_remove(msg, tableIdFrame);
    //Get the table
    leveldb::DB* db = tables.getTable(tableId, helper);
    //The entire update is processed in one batch
#ifdef BATCH_UPDATES
    leveldb::WriteBatch batch;
    while (true) {
        //The next two frames contain
        zframe_t* keyFrame = zmsg_next(msg);
        if (!keyFrame) {
            break;
        }
        zframe_t* valueFrame = zmsg_next(msg);
        assert(valueFrame); //if this fails there is an odd number of data frames --> illegal (see protocol spec)

        leveldb::Slice keySlice((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice valueSlice((char*) zframe_data(valueFrame), zframe_size(valueFrame));

#ifdef DEBUG_UPDATES
        printf("Insert '%s' = '%s'\n", keySlice.ToString().c_str(), valueSlice.ToString().c_str());
        fflush(stdout);
#endif

        batch.Put(keySlice, valueSlice);
    }
    //Commit the batch
#ifdef DEBUG_UPDATES
    printf("Commit update batch\n");
#endif
    db->Write(writeOptions, &batch);
#else //No batch updates
    for (int i = 0; i < request.write_requests_size(); i++) {
        const KeyValue& kv = request.write_requests(i);
        status = db->Put(writeOptions, kv.key(), kv.value());
    }
    for (int i = 0; i < request.delete_requests_size(); i++) {
        status = db->Delete(writeOptions, request.delete_requests(i));
    }
#endif
    //The memory occupied by the message is free'd in the thread loop
}

/*
 * Request/response codes are determined by the first byte
 * Request codes (from client):
 *      1<Read request>: Read. Response: Serialized ReadResponse
 *      2<Update request>: Update. Response: 0 --> Acknowledge
 * Response codes (to client):
 *      0: Acknowledge
 */
int handleRequestResponse(zloop_t *loop, zmq_pollitem_t *poller, void *arg) {
    KVServer* server = (KVServer*) arg;
    //Initialize a scoped lock
    zmsg_t *msg = zmsg_recv(server->reqRepSocket);
    if (msg) {
        //The message consists of four frames: Client addr, empty delimiter, msg type (1 byte) and data
        assert(zmsg_size(msg) >= 3); //return addr + empty delimiter + protocol header [+ data frames]
        //Extract the frames
        zframe_t* addrFrame = zmsg_first(msg);
        zframe_t* delimiterFrame = zmsg_next(msg);
        zframe_t* headerFrame = zmsg_next(msg);
        //Check the header -- send error message if invalid
        string errorString;
        char* headerData = (char*) zframe_data(headerFrame);
        if (!checkProtocolVersion(headerData, zframe_size(headerFrame), errorString)) {
            fprintf(stderr, "Got illegal message from client\n");
            return 1;
        }
        RequestType requestType = (RequestType) (uint8_t) headerData[2];
        //        fprintf(stderr, "Got message of type %d from client\n", (int) msgType);
        if (requestType == RequestType::ReadRequest) {
            handleReadRequest(server->tables, msg, *(server->tableOpenHelper));
            zmsg_send(&msg, server->reqRepSocket);
        } else if (requestType == RequestType::PutRequest) {
            //We reuse the header frame and the routing information to send the acknowledge message
            //The rest of the msg (the table id + data) is directly forwarded to one of the handler threads
            //Remove the routing information
            zframe_t* routingFrame = zmsg_unwrap(msg);
            //Remove the header frame
            headerFrame = zmsg_pop(msg);
            zframe_destroy(&headerFrame);
            //Send the message to the update worker (--> processed async)
            zmsg_send(&msg, server->updateWorkerThreadSocket);
            //Send acknowledge message
            msg = zmsg_new();
            zmsg_wrap(msg, routingFrame);
            zmsg_addmem(msg, "\x31\x01\x20\x00", 4); //Send response code 0x00 (ack)
            zmsg_send(&msg, server->reqRepSocket);
        } else {
            fprintf(stderr, "Unknown message type %d from client\n", (int) requestType);
        }
        cout << "Sending reply to" << (requestType == RequestType::PutRequest ? " put request " : " read request ") << endl;
    }
    return 0;
}

void initializeDirectoryStructure() {
    mkdir("tables", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP);
}

/**
 * This data structure is used in the update worker thread to share info with
 * the update poll handler
 */
struct UpdateWorkerInfo {
    KVServer* server;
    void* pullSocket;
};

/**
 * The main function for the update worker thread
 */
void updateWorkerThreadFunction(zctx_t* ctx, KVServer* serverInfo) {
    void* workPullSocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_connect(workPullSocket, updateWorkerThreadAddr);
    //Create the table open helper (creates a socket that sends table open requests)
    TableOpenHelper tableOpenHelper(ctx);
    //Create the data structure with all info for the poll handler
    while (true) {
        zmsg_t* msg = zmsg_recv(workPullSocket);
        assert(zmsg_size(msg) >= 1);
        //Process the frame
        handleUpdateRequest(serverInfo->tables, msg, tableOpenHelper);
        //Cleanup
        zmsg_destroy(&msg);
    }
    printf("Stopping update processor\n");
    zsocket_destroy(ctx, workPullSocket);
}

void initializeUpdateWorkers(zctx_t* ctx, KVServer* serverInfo) {
    //Initialize the push socket
    serverInfo->updateWorkerThreadSocket = zsocket_new(ctx, ZMQ_PUSH);
    zsocket_bind(serverInfo->updateWorkerThreadSocket, updateWorkerThreadAddr);
    //Start the threads
    const int numThreads = 3;
    serverInfo->numUpdateThreads = numThreads;
    serverInfo->updateWorkerThreads = new std::thread*[numThreads];
    for (int i = 0; i < numThreads; i++) {
        serverInfo->updateWorkerThreads[i] = new std::thread(updateWorkerThreadFunction, ctx, serverInfo);
    }
}

/**
 * ZDB KeyValueServer
 * Port
 */
int main() {
    const char* reqRepUrl = "tcp://*:7100";
    const char* writeSubscriptionUrl = "tcp://*:7101";
    const char* errorPubUrl = "tcp://*:7102";
    //Ensure the tables directory exists
    initializeDirectoryStructure();
    //Create the ZMQ context
    zctx_t* ctx = zctx_new();
    //Create the object that will be shared between the threadsloop
    KVServer server(ctx);
    //Start the table opener thread (constructor returns after thread has been started. Cleanup on scope exit.)
    bool dbCompressionEnabled = true;
    TableOpenServer tableOpenServer(ctx, server.tables.getDatabases(), dbCompressionEnabled);
    server.initializeTableOpenHelper();
    //Initialize all worker threads
    initializeUpdateWorkers(ctx, &server);
    //Initialize the sockets that run on the main thread
    server.reqRepSocket = zsocket_new(ctx, ZMQ_ROUTER);
    server.responseProxySocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_bind(server.responseProxySocket, "inproc://mainRequestProxy");
    zsocket_bind(server.reqRepSocket, reqRepUrl);
    //Start the loop
    printf("Starting server...\n");
    zloop_t *reactor = zloop_new();
    zmq_pollitem_t poller = {server.reqRepSocket, 0, ZMQ_POLLIN};
    zmq_pollitem_t poller = {server.repP, 0, ZMQ_POLLIN};
    zloop_poller(reactor, &poller, handleRequestResponse, &server);
    zloop_start(reactor);
    //Cleanup (called when finished)
    zloop_destroy(&reactor);
    server.cleanup(); //Before the context is destroyed
    zctx_destroy(&ctx);
    //All tables are closed at scope exit.
}<commit_msg>Start to add server info support<commit_after>
#include <zmq.h>

#include <leveldb/db.h>
#include <leveldb/write_batch.h>
#include <czmq.h>
#include <string>
#include <cstdio>
#include <thread>
#include <iostream>
#include <vector>
#include <sys/stat.h>
#include <mutex>
#include "TableOpenHelper.hpp"
#include "protocol.hpp"

//Feature toggle
#define BATCH_UPDATES
#define DEBUG_UPDATES
#define DEBUG_READ

const char* updateWorkerThreadAddr = "inproc://updateWorkerThread";

using namespace std;

/**
 * Encapsulates multiple key-value tables in one interface.
 * The tables are addressed by number and
 */
class KeyValueMultiTable {
public:
    typedef uint32_t IndexType;

    KeyValueMultiTable(IndexType defaultTablespaceSize = 16) : databases(32) {
        //Initialize the table array with 16 tables.
        //This avoids early re-allocation
        databasesSize = 16;
        //Use malloc here to allow usage of realloc
        //Initialize all pointers to zero
        for (int i = 0; i < databases.size(); i++) {
            databases[i] = NULL;
        }
    }

    /**
     * Close all tables and stop the table open server.
     *
     * This can't be done in the destructor because it needs to be done before
     * the context is deallocated
     */
    void cleanup() {
        fprintf(stderr, "Flushing and closing tables...\n");
        //Flush & delete all databases
        for (int i = 0; i < databasesSize; i++) {
            if (databases[i] != NULL) {
                delete databases[i];
            }
        }
    }

    leveldb::DB* getTable(IndexType index, TableOpenHelper& openHelper) {
        //Check if the database has already been opened
        if (databases[index] == NULL || index >= databases.size()) {
            openHelper.openTable(index);
        }
        return databases[index];
    }

    void closeTable(IndexType index) {
        if (databases[index] != NULL) {
            delete databases[index];
            databases[index] = NULL;
        }
    }

    leveldb::DB* getExistingTable(IndexType index) {
        return databases[index];
    }

    vector<leveldb::DB*>& getDatabases() {
        return databases;
    }
private:
    /**
     * The databases vector.
     * Any method in this class has read-only access (tables may be closed by this class however)
     *
     * Write acess is serialized using the TableOpenHelper class.
     *
     * Therefore locks and double initialization are avoided.
     */
    std::vector<leveldb::DB*> databases; //Indexed by table num
    uint32_t databasesSize;
};

/**
 * This struct is used to shared common variables across a server thread
 */
struct KVServer {

    KVServer(zctx_t* ctx) : ctx(ctx), tables(), numUpdateThreads(0) {

    }

    void initializeTableOpenHelper() {
        tableOpenHelper = new TableOpenHelper(ctx);
    }

    /**
     * Cleanup. This must be called before the ZMQ context is destroyed
     */
    void cleanup() {
        delete tableOpenHelper;
        tables.cleanup();
    }

    ~KVServer() {
        if (numUpdateThreads > 0) {
            delete[] updateWorkerThreads;
        }
        printf("Gracefully closed tables, exiting...\n");
    }
    KeyValueMultiTable tables;
    //External sockets
    void* reqRepSocket; //ROUTER socket that receives remote req/rep. READ requests can only use this socket
    void* subSocket; //SUB socket that subscribes to UPDATE requests (For mirroring etc)
    void* pullSocket; //PULL socket for UPDATE load balancinge
    void* responseProxySocket; //Worker threads connect to this PULL socket -- messages need to contain envelopes and area automatically proxied to the main router socket
    //Internal sockets
    void* updateWorkerThreadSocket; //PUSH socket that distributes update requests among worker threads
    TableOpenHelper* tableOpenHelper; //Only for use in the main thread
    //Thread info
    uint16_t numUpdateThreads;
    std::thread** updateWorkerThreads;
    //Other stuff
    zctx_t* ctx;
};

void handleReadRequest(KeyValueMultiTable& tables, zmsg_t* msg, TableOpenHelper& openHelper) {
#ifdef DEBUG_READ
    printf("Starting to handle read request of size %d\n", (uint32_t) zmsg_size(msg) - 1);
    fflush(stdout);
#endif
    //Parse the table id
    zframe_t* tableIdFrame = zmsg_next(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    cout << "RM Resized to size " << zmsg_size(msg) << endl;
    //The response has doesn't have the table frame, so
    //Get the table to read from
    leveldb::DB* db = tables.getTable(tableId, openHelper);
    //Create the response object
    leveldb::ReadOptions readOptions;
    string value; //Where the value will be placed
    leveldb::Status status;
    //Read each read request
    zframe_t* keyFrame = NULL;
    while ((keyFrame = zmsg_next(msg)) != NULL) {
        //Build a slice of the key (zero-copy)
        string keystr((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice key((char*) zframe_data(keyFrame), zframe_size(keyFrame));
#ifdef DEBUG_READ
        printf("Reading key %s from table %d\n", key.ToString().c_str(), tableId);
#endif
        status = db->Get(readOptions, key, &value);
        if (status.IsNotFound()) {
#ifdef DEBUG_READ
            cout << "Could not find value for key " << key.ToString() << "in table " << tableId << endl;
#endif
            //Empty value
            zframe_reset(keyFrame, "", 0);
        } else {
#ifdef DEBUG_READ
            cout << "Read " << value << " (key = " << key.ToString() << ") --> " << value << endl;
#endif
            zframe_reset(keyFrame, value.c_str(), value.length());
        }
    }
    //Now we can remove the table ID frame from the message (doing so before would confuse zmsg_next())
    zmsg_remove(msg, tableIdFrame);
    zframe_destroy(&tableIdFrame);
#ifdef DEBUG_READ
    cout << "Final reply msg size: " << zmsg_size(msg) << endl;
#endif
}

void handleUpdateRequest(KeyValueMultiTable& tables, zmsg_t* msg, TableOpenHelper& helper) {
    leveldb::Status status;
    leveldb::WriteOptions writeOptions;
    //Parse the table id
    //This function requires that the given message has the table id in its first frame
    zframe_t* tableIdFrame = zmsg_first(msg);
    assert(zframe_size(tableIdFrame) == sizeof (uint32_t));
    uint32_t tableId = *((uint32_t*) zframe_data(tableIdFrame));
    zmsg_remove(msg, tableIdFrame);
    //Get the table
    leveldb::DB* db = tables.getTable(tableId, helper);
    //The entire update is processed in one batch
#ifdef BATCH_UPDATES
    leveldb::WriteBatch batch;
    while (true) {
        //The next two frames contain
        zframe_t* keyFrame = zmsg_next(msg);
        if (!keyFrame) {
            break;
        }
        zframe_t* valueFrame = zmsg_next(msg);
        assert(valueFrame); //if this fails there is an odd number of data frames --> illegal (see protocol spec)

        leveldb::Slice keySlice((char*) zframe_data(keyFrame), zframe_size(keyFrame));
        leveldb::Slice valueSlice((char*) zframe_data(valueFrame), zframe_size(valueFrame));

#ifdef DEBUG_UPDATES
        printf("Insert '%s' = '%s'\n", keySlice.ToString().c_str(), valueSlice.ToString().c_str());
        fflush(stdout);
#endif

        batch.Put(keySlice, valueSlice);
    }
    //Commit the batch
#ifdef DEBUG_UPDATES
    printf("Commit update batch\n");
#endif
    db->Write(writeOptions, &batch);
#else //No batch updates
    for (int i = 0; i < request.write_requests_size(); i++) {
        const KeyValue& kv = request.write_requests(i);
        status = db->Put(writeOptions, kv.key(), kv.value());
    }
    for (int i = 0; i < request.delete_requests_size(); i++) {
        status = db->Delete(writeOptions, request.delete_requests(i));
    }
#endif
    //The memory occupied by the message is free'd in the thread loop
}

/*
 * Request/response codes are determined by the first byte
 * Request codes (from client):
 *      1<Read request>: Read. Response: Serialized ReadResponse
 *      2<Update request>: Update. Response: 0 --> Acknowledge
 * Response codes (to client):
 *      0: Acknowledge
 */
int handleRequestResponse(zloop_t *loop, zmq_pollitem_t *poller, void *arg) {
    KVServer* server = (KVServer*) arg;
    //Initialize a scoped lock
    zmsg_t *msg = zmsg_recv(server->reqRepSocket);
    if (msg) {
        //The message consists of four frames: Client addr, empty delimiter, msg type (1 byte) and data
        assert(zmsg_size(msg) >= 3); //return addr + empty delimiter + protocol header [+ data frames]
        //Extract the frames
        zframe_t* addrFrame = zmsg_first(msg);
        zframe_t* delimiterFrame = zmsg_next(msg);
        zframe_t* headerFrame = zmsg_next(msg);
        //Check the header -- send error message if invalid
        string errorString;
        char* headerData = (char*) zframe_data(headerFrame);
        if (!checkProtocolVersion(headerData, zframe_size(headerFrame), errorString)) {
            fprintf(stderr, "Got illegal message from client\n");
            return 1;
        }
        RequestType requestType = (RequestType) (uint8_t) headerData[2];
        //        fprintf(stderr, "Got message of type %d from client\n", (int) msgType);
        if (requestType == RequestType::ReadRequest) {
            handleReadRequest(server->tables, msg, *(server->tableOpenHelper));
            zmsg_send(&msg, server->reqRepSocket);
        } else if (requestType == RequestType::PutRequest) {
            //We reuse the header frame and the routing information to send the acknowledge message
            //The rest of the msg (the table id + data) is directly forwarded to one of the handler threads
            //Remove the routing information
            zframe_t* routingFrame = zmsg_unwrap(msg);
            //Remove the header frame
            headerFrame = zmsg_pop(msg);
            zframe_destroy(&headerFrame);
            //Send the message to the update worker (--> processed async)
            zmsg_send(&msg, server->updateWorkerThreadSocket);
            //Send acknowledge message
            msg = zmsg_new();
            zmsg_wrap(msg, routingFrame);
            zmsg_addmem(msg, "\x31\x01\x20\x00", 4); //Send response code 0x00 (ack)
            zmsg_send(&msg, server->reqRepSocket);
        } else if(requestType == RequestType::ServerInfoRequest) {
            const uint64_t serverFlags = SupportOnTheFlyTableOpen | SupportPARTSYNC | SupportFULLSYNC;
            zframe_t* frame = zframe_new(3/*Metadata*/+8/*Flags*/);
        } else {
            fprintf(stderr, "Unknown message type %d from client\n", (int) requestType);
        }
        cout << "Sending reply to" << (requestType == RequestType::PutRequest ? " put request " : " read request ") << endl;
    }
    return 0;
}

void initializeDirectoryStructure() {
    mkdir("tables", S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP);
}

/**
 * This data structure is used in the update worker thread to share info with
 * the update poll handler
 */
struct UpdateWorkerInfo {
    KVServer* server;
    void* pullSocket;
};

/**
 * The main function for the update worker thread
 */
void updateWorkerThreadFunction(zctx_t* ctx, KVServer* serverInfo) {
    void* workPullSocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_connect(workPullSocket, updateWorkerThreadAddr);
    //Create the table open helper (creates a socket that sends table open requests)
    TableOpenHelper tableOpenHelper(ctx);
    //Create the data structure with all info for the poll handler
    while (true) {
        zmsg_t* msg = zmsg_recv(workPullSocket);
        assert(zmsg_size(msg) >= 1);
        //Process the frame
        handleUpdateRequest(serverInfo->tables, msg, tableOpenHelper);
        //Cleanup
        zmsg_destroy(&msg);
    }
    printf("Stopping update processor\n");
    zsocket_destroy(ctx, workPullSocket);
}

void initializeUpdateWorkers(zctx_t* ctx, KVServer* serverInfo) {
    //Initialize the push socket
    serverInfo->updateWorkerThreadSocket = zsocket_new(ctx, ZMQ_PUSH);
    zsocket_bind(serverInfo->updateWorkerThreadSocket, updateWorkerThreadAddr);
    //Start the threads
    const int numThreads = 3;
    serverInfo->numUpdateThreads = numThreads;
    serverInfo->updateWorkerThreads = new std::thread*[numThreads];
    for (int i = 0; i < numThreads; i++) {
        serverInfo->updateWorkerThreads[i] = new std::thread(updateWorkerThreadFunction, ctx, serverInfo);
    }
}

/**
 * ZDB KeyValueServer
 * Port
 */
int main() {
    const char* reqRepUrl = "tcp://*:7100";
    const char* writeSubscriptionUrl = "tcp://*:7101";
    const char* errorPubUrl = "tcp://*:7102";
    //Ensure the tables directory exists
    initializeDirectoryStructure();
    //Create the ZMQ context
    zctx_t* ctx = zctx_new();
    //Create the object that will be shared between the threadsloop
    KVServer server(ctx);
    //Start the table opener thread (constructor returns after thread has been started. Cleanup on scope exit.)
    bool dbCompressionEnabled = true;
    TableOpenServer tableOpenServer(ctx, server.tables.getDatabases(), dbCompressionEnabled);
    server.initializeTableOpenHelper();
    //Initialize all worker threads
    initializeUpdateWorkers(ctx, &server);
    //Initialize the sockets that run on the main thread
    server.reqRepSocket = zsocket_new(ctx, ZMQ_ROUTER);
    server.responseProxySocket = zsocket_new(ctx, ZMQ_PULL);
    zsocket_bind(server.responseProxySocket, "inproc://mainRequestProxy");
    zsocket_bind(server.reqRepSocket, reqRepUrl);
    //Start the loop
    printf("Starting server...\n");
    zloop_t *reactor = zloop_new();
    zmq_pollitem_t poller = {server.reqRepSocket, 0, ZMQ_POLLIN};
    zmq_pollitem_t poller = {server.repP, 0, ZMQ_POLLIN};
    zloop_poller(reactor, &poller, handleRequestResponse, &server);
    zloop_start(reactor);
    //Cleanup (called when finished)
    zloop_destroy(&reactor);
    server.cleanup(); //Before the context is destroyed
    zctx_destroy(&ctx);
    //All tables are closed at scope exit.
}<|endoftext|>


<commit_before>
#include "befakprint.h"

#include <stdio.h>

// baseclass with stuff, inherit to print/export/whatever

beFakPrint::beFakPrint(int id, sqlite *db) {

	if (id<1) {
		printf("illegal id!\n");
		return;
	}

	dbData = db;
	fakturaid = id;
	typ = 0;		// XXX parametr!

	switch (typ) {
		case 2:
			typfaktury = "Duplikat";
			break;
		case 1:
			typfaktury = "Kopia";
			break;
		case 0:
		default:
			typfaktury = "Oryginał";
			break;
	}

	// readout stuff
//printf("reading stuff for id=%i\n",fakturaid);
	fdata = new fakturadat(db);
	flist = new pozfaklist(db);

	fdata->id = fakturaid;
	fdata->fetch();
	flist->fetch(fdata->id);

	// XXX duplicated in dialfirma constructor!!! separate!!!
	int i, j;
	int nRows, nCols;
	char **result;
	BString sql;
	sql = "SELECT ";
	sql += "nazwa, adres, kod, miejscowosc, telefon, email";
	sql += ", nip, regon, bank, konto";
	sql += " FROM konfiguracja WHERE zrobiona = 1";
//printf("sql:%s\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i\n", nRows, nCols);
	if (nRows < 1) {
		// XXX brak informacji o własnej firmie, co robić?
	} else {
//		printf("not initial\n");
		// readout data
		i = nCols;
		own[0] = result[i++];
		for (j=2;j<=10;j++) {
			own[j] = result[i++];
		}
	}
	// tabela pomocnicza do podsumowania
	flist->execSQL("CREATE TEMPORARY TABLE sumawydruk ( wnetto DECIMAL(12,2), vatid INTEGER, wvat DECIMAL(12,2), wbrutto DECIMAL(12,2) )");

//	printf("stuff in memory, do sth with it\n");
}

void beFakPrint::updateSummary(const BString wnetto, const int vatid, const BString wvat, const BString wbrutto) {
	int ret;

	ret = sqlite_exec_printf(dbData, "INSERT INTO sumawydruk (wnetto,vatid,wvat,wbrutto) VALUES ( %Q, %i, %Q, %Q )", 0, 0, &dbErrMsg,
		wnetto.String(), vatid, wvat.String(), wbrutto.String() );
//		printf("result: %i, %s\n", ret, dbErrMsg);

}

void beFakPrint::makeSummary(void) {
	int i, j;
	int nRows, nCols;
	char **result;
	BString sql;

	// suma z rozbiciem na stawki
	sql = "SELECT SUM(s.wnetto), v.nazwa, SUM(s.wvat), SUM(s.wbrutto) FROM sumawydruk AS s, stawka_vat AS v WHERE v.id = s.vatid GROUP BY s.vatid ORDER BY v.nazwa";
//printf("sql:[%s]\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i, %s\n", nRows, nCols, dbErrMsg);
	if (nRows < 1) {
		// nothin'?
	} else {
		i = nCols;
		j = 1;
		fsummarows = nRows;
		fsumma = new summary[nRows];
		while (j <= nRows) {
			fsumma[j-1].summa[0] = decround(result[i++]);
			fsumma[j-1].summa[1] = result[i++];
			fsumma[j-1].summa[2] = decround(result[i++]);
			fsumma[j-1].summa[3] = decround(result[i++]);
			j++;
		}
	}
	sqlite_free_table(result);
	// obliczyc RAZEM
	sql = "SELECT SUM(s.wnetto), v.nazwa, SUM(s.wvat), SUM(s.wbrutto) FROM sumawydruk AS s, stawka_vat AS v WHERE v.id = s.vatid";
//printf("sql:[%s]\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i, %s\n", nRows, nCols, dbErrMsg);
	if (nRows < 1) {
		// nothin'?
	} else {
		i = nCols;
		razem.summa[0] = decround(result[i++]);
		razem.summa[1] = result[i++];
		razem.summa[2] = decround(result[i++]);
		razem.summa[3] = decround(result[i++]);
	}
	sqlite_free_table(result);
}

beFakPrint::~beFakPrint() {
//printf("at the end call destructor from baseclass\n");
	flist->execSQL("DROP TABLE sumawydruk");
	delete [] fsumma;

	delete flist;
	delete fdata;
}

const char *setki[] = { "", "sto ", "dwieście ", "trzysta ", "czterysta ", "pięćset ", "sześćset ", "siedemset ", "osiemset ", "dziewięćset " };
const char *dziesiatki[] = { "", "", "dwadzieścia ", "trzydzieści ", "czterdzieści ", "pięćdziesiąt ", "sześćdziesiąt", "siedemdziesiąt ", "osiemdziesiąt ", "dziewięćdziesiąt " };
const char *nascie[] = { "dziesięć ", "jedenaście ", "dwanaście ", "trzynaście ", "czternaście ", "piętnaście ", "szesnaście ", "siedemnaście ", "osiemnaście ", "dziewiętnaście " };
const char *jednosci[] = { "", "jeden ", "dwa ", "trzy ", "cztery ", "pięć ", "sześć ", "siedem ", "osiem ", "dziewięć " };

const char *beFakPrint::rozbij_tysiac(int val) {
	static BString tmp;
	int i;
	int t = val;

	tmp = "";
	i = t / 100;
	tmp += setki[i];
	t = t % 100;
	i = t / 10;
	t = t % 10;
	if (i!=1) {
		tmp += dziesiatki[i];
		tmp += jednosci[t];
	} else {
		tmp += nascie[t];
	}
	return tmp.String();
}

const char *beFakPrint::slownie(const char *input) {
	static BString tmp;

	int i = 0;
	int l = strlen(input);
	char c;

	int z = 0;		// zlote
	int g = 0;		// grosze
	int w = 0;		// wykladnik
	bool grosze = false;
	tmp = "";

	while (i<l) {
		c = input[i++];
		if (c == '.')
			grosze = true;
		else
		if (!grosze)
			z = z*10+c-'0';
		else {
			w++;
			if (w<3)
				g=g*10+c-'0';
		}
	}
	if (w==1) g*=10;

	i = z / 1000000;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "mln. ";
	}
	z = z % 1000000;

	i = z / 1000;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "tys. ";
	}
	z = z % 1000;

	i = z;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
	}
	if ((tmp.Length()==0) && (g==0))
		tmp = "zero ";
	if (tmp.Length()!=0)
		tmp += "zł ";

	i = g;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "gr";
	}

	return tmp.String();
}

void beFakPrint::Go(void) {
	printf("override and do sth meaningful with data\n");
}
<commit_msg>- initialized fsumma so it may be empty upon destroy<commit_after>
#include "befakprint.h"

#include <stdio.h>

// baseclass with stuff, inherit to print/export/whatever

beFakPrint::beFakPrint(int id, sqlite *db) {

	if (id<1) {
		printf("illegal id!\n");
		return;
	}

	dbData = db;
	fakturaid = id;
	typ = 0;		// XXX parametr!

	switch (typ) {
		case 2:
			typfaktury = "Duplikat";
			break;
		case 1:
			typfaktury = "Kopia";
			break;
		case 0:
		default:
			typfaktury = "Oryginał";
			break;
	}

	// readout stuff
//printf("reading stuff for id=%i\n",fakturaid);
	fdata = new fakturadat(db);
	flist = new pozfaklist(db);

	fdata->id = fakturaid;
	fdata->fetch();
	flist->fetch(fdata->id);
	fsumma = NULL;

	// XXX duplicated in dialfirma constructor!!! separate!!!
	int i, j;
	int nRows, nCols;
	char **result;
	BString sql;
	sql = "SELECT ";
	sql += "nazwa, adres, kod, miejscowosc, telefon, email";
	sql += ", nip, regon, bank, konto";
	sql += " FROM konfiguracja WHERE zrobiona = 1";
//printf("sql:%s\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i\n", nRows, nCols);
	if (nRows < 1) {
		// XXX brak informacji o własnej firmie, co robić?
	} else {
//		printf("not initial\n");
		// readout data
		i = nCols;
		own[0] = result[i++];
		for (j=2;j<=10;j++) {
			own[j] = result[i++];
		}
	}
	// tabela pomocnicza do podsumowania
	flist->execSQL("CREATE TEMPORARY TABLE sumawydruk ( wnetto DECIMAL(12,2), vatid INTEGER, wvat DECIMAL(12,2), wbrutto DECIMAL(12,2) )");

//	printf("stuff in memory, do sth with it\n");
}

void beFakPrint::updateSummary(const BString wnetto, const int vatid, const BString wvat, const BString wbrutto) {
	int ret;

	ret = sqlite_exec_printf(dbData, "INSERT INTO sumawydruk (wnetto,vatid,wvat,wbrutto) VALUES ( %Q, %i, %Q, %Q )", 0, 0, &dbErrMsg,
		wnetto.String(), vatid, wvat.String(), wbrutto.String() );
//		printf("result: %i, %s\n", ret, dbErrMsg);

}

void beFakPrint::makeSummary(void) {
	int i, j;
	int nRows, nCols;
	char **result;
	BString sql;

	// suma z rozbiciem na stawki
	sql = "SELECT SUM(s.wnetto), v.nazwa, SUM(s.wvat), SUM(s.wbrutto) FROM sumawydruk AS s, stawka_vat AS v WHERE v.id = s.vatid GROUP BY s.vatid ORDER BY v.nazwa";
//printf("sql:[%s]\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i, %s\n", nRows, nCols, dbErrMsg);
	if (nRows < 1) {
		// nothin'?
	} else {
		i = nCols;
		j = 1;
		fsummarows = nRows;
		fsumma = new summary[nRows];
		while (j <= nRows) {
			fsumma[j-1].summa[0] = decround(result[i++]);
			fsumma[j-1].summa[1] = result[i++];
			fsumma[j-1].summa[2] = decround(result[i++]);
			fsumma[j-1].summa[3] = decround(result[i++]);
			j++;
		}
	}
	sqlite_free_table(result);
	// obliczyc RAZEM
	sql = "SELECT SUM(s.wnetto), v.nazwa, SUM(s.wvat), SUM(s.wbrutto) FROM sumawydruk AS s, stawka_vat AS v WHERE v.id = s.vatid";
//printf("sql:[%s]\n",sql.String());
	sqlite_get_table(dbData, sql.String(), &result, &nRows, &nCols, &dbErrMsg);
//printf ("got:%ix%i, %s\n", nRows, nCols, dbErrMsg);
	if (nRows < 1) {
		// nothin'?
	} else {
		i = nCols;
		razem.summa[0] = decround(result[i++]);
		razem.summa[1] = result[i++];
		razem.summa[2] = decround(result[i++]);
		razem.summa[3] = decround(result[i++]);
	}
	sqlite_free_table(result);
}

beFakPrint::~beFakPrint() {
//printf("at the end call destructor from baseclass\n");
	flist->execSQL("DROP TABLE sumawydruk");
	delete [] fsumma;

	delete flist;
	delete fdata;
}

const char *setki[] = { "", "sto ", "dwieście ", "trzysta ", "czterysta ", "pięćset ", "sześćset ", "siedemset ", "osiemset ", "dziewięćset " };
const char *dziesiatki[] = { "", "", "dwadzieścia ", "trzydzieści ", "czterdzieści ", "pięćdziesiąt ", "sześćdziesiąt", "siedemdziesiąt ", "osiemdziesiąt ", "dziewięćdziesiąt " };
const char *nascie[] = { "dziesięć ", "jedenaście ", "dwanaście ", "trzynaście ", "czternaście ", "piętnaście ", "szesnaście ", "siedemnaście ", "osiemnaście ", "dziewiętnaście " };
const char *jednosci[] = { "", "jeden ", "dwa ", "trzy ", "cztery ", "pięć ", "sześć ", "siedem ", "osiem ", "dziewięć " };

const char *beFakPrint::rozbij_tysiac(int val) {
	static BString tmp;
	int i;
	int t = val;

	tmp = "";
	i = t / 100;
	tmp += setki[i];
	t = t % 100;
	i = t / 10;
	t = t % 10;
	if (i!=1) {
		tmp += dziesiatki[i];
		tmp += jednosci[t];
	} else {
		tmp += nascie[t];
	}
	return tmp.String();
}

const char *beFakPrint::slownie(const char *input) {
	static BString tmp;

	int i = 0;
	int l = strlen(input);
	char c;

	int z = 0;		// zlote
	int g = 0;		// grosze
	int w = 0;		// wykladnik
	bool grosze = false;
	tmp = "";

	while (i<l) {
		c = input[i++];
		if (c == '.')
			grosze = true;
		else
		if (!grosze)
			z = z*10+c-'0';
		else {
			w++;
			if (w<3)
				g=g*10+c-'0';
		}
	}
	if (w==1) g*=10;

	i = z / 1000000;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "mln. ";
	}
	z = z % 1000000;

	i = z / 1000;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "tys. ";
	}
	z = z % 1000;

	i = z;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
	}
	if ((tmp.Length()==0) && (g==0))
		tmp = "zero ";
	if (tmp.Length()!=0)
		tmp += "zł ";

	i = g;
	if (i!=0) {
		tmp += rozbij_tysiac(i);
		tmp += "gr";
	}

	return tmp.String();
}

void beFakPrint::Go(void) {
	printf("override and do sth meaningful with data\n");
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> 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 EARLIER MENTIONED AUTHORS ``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 <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "CppUTest/TestHarness.h"
#include "CppUTest/FailableMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"

// Allocator must be global. Otherwise, it does not exist when memory leak detector
// reports memory leaks.
static FailableMemoryAllocator failableMallocAllocator("Failable Malloc Allocator", "malloc", "free");
static FailableMemoryAllocator failableNewAllocator("Failable New Allocator", "new", "delete");
static FailableMemoryAllocator failableNewArrayAllocator("Failable New [] Allocator", "new []", "delete []");

#if CPPUTEST_USE_MEM_LEAK_DETECTION

TEST_GROUP(FailableMemoryAllocator)
{
    void setup()
    {
        failableMallocAllocator.clearFailedAllocations();
        failableNewAllocator.clearFailedAllocations();
        failableNewArrayAllocator.clearFailedAllocations();

        setCurrentMallocAllocator(&failableMallocAllocator);
        setCurrentNewAllocator(&failableNewAllocator);
        setCurrentNewArrayAllocator(&failableNewArrayAllocator);
    }
    void teardown()
    {
        setCurrentMallocAllocatorToDefault();
        setCurrentNewAllocatorToDefault();
        setCurrentNewArrayAllocatorToDefault();
    }
};

#if CPPUTEST_USE_MALLOC_MACROS
TEST(FailableMemoryAllocator, MallocWorksNormallyIfNotAskedToFail)
{
    int *memory = (int*)malloc(sizeof(int));
    *memory = 1;
    CHECK(memory != NULL);
    free(memory);
}

TEST(FailableMemoryAllocator, FailFirstMalloc)
{
    failableMallocAllocator.failAllocNumber(1);
    POINTERS_EQUAL(NULL, (int*)malloc(sizeof(int)));
}

TEST(FailableMemoryAllocator, FailSecondAndFourthMalloc)
{
    failableMallocAllocator.failAllocNumber(2);
    failableMallocAllocator.failAllocNumber(4);
    int *memory1 = (int*)malloc(sizeof(int));
    int *memory2 = (int*)malloc(sizeof(int));
    int *memory3 = (int*)malloc(sizeof(int));
    int *memory4 = (int*)malloc(sizeof(int));

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    free(memory1);
    free(memory3);
}

static void _setUpTooManyFailedMallocs()
{
    FailableMemoryAllocator allocator;
    for (int i = 0; i <= allocator.MAX_NUMBER_OF_FAILED_ALLOCS; i++)
        allocator.failAllocNumber(i + 1);
}

TEST(FailableMemoryAllocator, SettingUpTooManyFailedAllocsWillFail)
{
    TestTestingFixture *fixture = new TestTestingFixture;
    fixture->setTestFunction(_setUpTooManyFailedMallocs);

    fixture->runAllTests();

    LONGS_EQUAL(1, fixture->getFailureCount());
    fixture->assertPrintContains("Maximum number of failed memory allocations exceeded");
    delete fixture;
}
#endif

TEST(FailableMemoryAllocator, NewWorksNormallyIfNotAskedToFail)
{
    int *memory = new int;
    *memory = 1;
    CHECK(memory != NULL);
    delete memory;
}

TEST(FailableMemoryAllocator, NewArrayWorksNormallyIfNotAskedToFail)
{
    int *memory = new int[10];
    memory[0] = 1;
    CHECK(memory != NULL);
    delete [] memory;
}

#if CPPUTEST_USE_STD_CPP_LIB

TEST(FailableMemoryAllocator, FailSecondNewRaisesException)
{
    failableNewAllocator.failAllocNumber(2);
    int *memory1 = new int;

    CHECK_THROWS(std::bad_alloc, new int);

    delete memory1;
}

TEST(FailableMemoryAllocator, FailSecondNewArrayRaisesException)
{
    failableNewArrayAllocator.failAllocNumber(2);
    int *memory1 = new int[10];

    CHECK_THROWS(std::bad_alloc, new int[10]);

    delete [] memory1;
}

#endif

#ifdef __clang__
IGNORE_TEST(FailableMemoryAllocator, FailSecondAndFourthNewNoThrow)
{
    /*  Clang misbehaves with -O2 - it will not overload operator new or
     *  operator new[] no matter what. Therefore, this test is must be ignored.
     */
}
#else

#if CPPUTEST_USE_STD_CPP_LIB
#define STD_NOTHROW (std::nothrow)
#else
#define STD_NOTHROW
#endif

TEST(FailableMemoryAllocator, FailSecondAndFourthNewNoThrow)
{
#undef new
    failableNewAllocator.failAllocNumber(2);
    failableNewAllocator.failAllocNumber(4);
    int *memory1 = new STD_NOTHROW int;
    int *memory2 = new STD_NOTHROW int;
    int *memory3 = new STD_NOTHROW int;
    int *memory4 = new STD_NOTHROW int;

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    delete memory1;
    delete memory3;
}
#endif

#ifdef __clang__
IGNORE_TEST(FailableMemoryAllocator, FailSecondAndFourthNewArrayNoThrow)
{
    /*  Clang misbehaves with -O2 - it will not overload operator new or
     *  operator new[] no matter what. Therefore, this test is must be ignored.
     */
}
#else

TEST(FailableMemoryAllocator, FailSecondAndFourthNewArrayNoThrow)
{
    failableNewArrayAllocator.failAllocNumber(2);
    failableNewArrayAllocator.failAllocNumber(4);
    int *memory1 = new STD_NOTHROW int[10];
    int *memory2 = new STD_NOTHROW int[10];
    int *memory3 = new STD_NOTHROW int[10];
    int *memory4 = new STD_NOTHROW int[10];

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    delete [] memory1;
    delete [] memory3;
}
#endif

#endif
<commit_msg>Create TestTestingFixture in stack instead of new-delete<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> 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 EARLIER MENTIONED AUTHORS ``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 <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "CppUTest/TestHarness.h"
#include "CppUTest/FailableMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"

// Allocator must be global. Otherwise, it does not exist when memory leak detector
// reports memory leaks.
static FailableMemoryAllocator failableMallocAllocator("Failable Malloc Allocator", "malloc", "free");
static FailableMemoryAllocator failableNewAllocator("Failable New Allocator", "new", "delete");
static FailableMemoryAllocator failableNewArrayAllocator("Failable New [] Allocator", "new []", "delete []");

#if CPPUTEST_USE_MEM_LEAK_DETECTION

TEST_GROUP(FailableMemoryAllocator)
{
    void setup()
    {
        failableMallocAllocator.clearFailedAllocations();
        failableNewAllocator.clearFailedAllocations();
        failableNewArrayAllocator.clearFailedAllocations();

        setCurrentMallocAllocator(&failableMallocAllocator);
        setCurrentNewAllocator(&failableNewAllocator);
        setCurrentNewArrayAllocator(&failableNewArrayAllocator);
    }
    void teardown()
    {
        setCurrentMallocAllocatorToDefault();
        setCurrentNewAllocatorToDefault();
        setCurrentNewArrayAllocatorToDefault();
    }
};

#if CPPUTEST_USE_MALLOC_MACROS
TEST(FailableMemoryAllocator, MallocWorksNormallyIfNotAskedToFail)
{
    int *memory = (int*)malloc(sizeof(int));
    *memory = 1;
    CHECK(memory != NULL);
    free(memory);
}

TEST(FailableMemoryAllocator, FailFirstMalloc)
{
    failableMallocAllocator.failAllocNumber(1);
    POINTERS_EQUAL(NULL, (int*)malloc(sizeof(int)));
}

TEST(FailableMemoryAllocator, FailSecondAndFourthMalloc)
{
    failableMallocAllocator.failAllocNumber(2);
    failableMallocAllocator.failAllocNumber(4);
    int *memory1 = (int*)malloc(sizeof(int));
    int *memory2 = (int*)malloc(sizeof(int));
    int *memory3 = (int*)malloc(sizeof(int));
    int *memory4 = (int*)malloc(sizeof(int));

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    free(memory1);
    free(memory3);
}

static void _setUpTooManyFailedMallocs()
{
    FailableMemoryAllocator allocator;
    for (int i = 0; i <= allocator.MAX_NUMBER_OF_FAILED_ALLOCS; i++)
        allocator.failAllocNumber(i + 1);
}

TEST(FailableMemoryAllocator, SettingUpTooManyFailedAllocsWillFail)
{
    TestTestingFixture fixture;
    fixture.setTestFunction(_setUpTooManyFailedMallocs);

    fixture.runAllTests();

    LONGS_EQUAL(1, fixture.getFailureCount());
    fixture.assertPrintContains("Maximum number of failed memory allocations exceeded");
}
#endif

TEST(FailableMemoryAllocator, NewWorksNormallyIfNotAskedToFail)
{
    int *memory = new int;
    *memory = 1;
    CHECK(memory != NULL);
    delete memory;
}

TEST(FailableMemoryAllocator, NewArrayWorksNormallyIfNotAskedToFail)
{
    int *memory = new int[10];
    memory[0] = 1;
    CHECK(memory != NULL);
    delete [] memory;
}

#if CPPUTEST_USE_STD_CPP_LIB

TEST(FailableMemoryAllocator, FailSecondNewRaisesException)
{
    failableNewAllocator.failAllocNumber(2);
    int *memory1 = new int;

    CHECK_THROWS(std::bad_alloc, new int);

    delete memory1;
}

TEST(FailableMemoryAllocator, FailSecondNewArrayRaisesException)
{
    failableNewArrayAllocator.failAllocNumber(2);
    int *memory1 = new int[10];

    CHECK_THROWS(std::bad_alloc, new int[10]);

    delete [] memory1;
}

#endif

#ifdef __clang__
IGNORE_TEST(FailableMemoryAllocator, FailSecondAndFourthNewNoThrow)
{
    /*  Clang misbehaves with -O2 - it will not overload operator new or
     *  operator new[] no matter what. Therefore, this test is must be ignored.
     */
}
#else

#if CPPUTEST_USE_STD_CPP_LIB
#define STD_NOTHROW (std::nothrow)
#else
#define STD_NOTHROW
#endif

TEST(FailableMemoryAllocator, FailSecondAndFourthNewNoThrow)
{
#undef new
    failableNewAllocator.failAllocNumber(2);
    failableNewAllocator.failAllocNumber(4);
    int *memory1 = new STD_NOTHROW int;
    int *memory2 = new STD_NOTHROW int;
    int *memory3 = new STD_NOTHROW int;
    int *memory4 = new STD_NOTHROW int;

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    delete memory1;
    delete memory3;
}
#endif

#ifdef __clang__
IGNORE_TEST(FailableMemoryAllocator, FailSecondAndFourthNewArrayNoThrow)
{
    /*  Clang misbehaves with -O2 - it will not overload operator new or
     *  operator new[] no matter what. Therefore, this test is must be ignored.
     */
}
#else

TEST(FailableMemoryAllocator, FailSecondAndFourthNewArrayNoThrow)
{
    failableNewArrayAllocator.failAllocNumber(2);
    failableNewArrayAllocator.failAllocNumber(4);
    int *memory1 = new STD_NOTHROW int[10];
    int *memory2 = new STD_NOTHROW int[10];
    int *memory3 = new STD_NOTHROW int[10];
    int *memory4 = new STD_NOTHROW int[10];

    CHECK(NULL != memory1);
    POINTERS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    POINTERS_EQUAL(NULL, memory4);

    delete [] memory1;
    delete [] memory3;
}
#endif

#endif
<|endoftext|>