<commit_before>// @(#)root/base:$Id$
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TAttFill.h"
#include "TVirtualPad.h"
#include "TStyle.h"
#include "TVirtualX.h"
#include "TVirtualPadEditor.h"
#include "TColor.h"

ClassImp(TAttFill)

//______________________________________________________________________________
/* Begin_Html

Fill Area Attributes class

This class is used (in general by secondary inheritance)
by many other classes (graphics, histograms). It holds all the fill area
attributes.

Fill Area attributes

Fill Area attributes are:

Fill Area color.

Fill Area style.

Fill Area color

The fill area color is a color index (integer) pointing in the ROOT
color table.
The fill area color of any class inheriting from <tt>TAttFill</tt> can
be changed using the method <tt>SetFillColor</tt> and retrieved using the
method <tt>GetFillColor</tt>.
The following table shows the first 50 default colors.
End_Html
Begin_Macro(source)
{
   TCanvas *c = new TCanvas("c","Fill Area colors",0,0,500,200);
   c.DrawColorTable();
   return c;
}
End_Macro

Begin_Html

The ROOT Color Wheel.

The wheel contains the recommended 216 colors to be used in web applications.
The colors in the Color Wheel are created by TColor::CreateColorWheel.

Using this color set for your text, background or graphics will give your
application a consistent appearance across different platforms and browsers.

Colors are grouped by hue, the aspect most important in human perception
Touching color chips have the same hue, but with different brightness and vividness.

Colors of slightly different hues clash. If you intend to display
colors of the same hue together, you should pick them from the same group.

Each color chip is identified by a mnemonic (eg kYellow) and a number.
The keywords, kRed, kBlue, kYellow, kPink, etc are defined in the header file Rtypes.h
that is included in all ROOT other header files. We strongly recommend to use these keywords
in your code instead of hardcoded color numbers, eg:

   myObject.SetFillColor(kRed);
   myObject.SetFillColor(kYellow-10);
   myLine.SetLineColor(kMagenta+2);

End_Html
Begin_Macro(source)
{
   TColorWheel *w = new TColorWheel();
   w->Draw();
   return w->GetCanvas();
}
End_Macro

Begin_Html

Special case forcing black&white output.

If the current style fill area color is set to 0, then ROOT will force
a black&white output for all objects with a fill area defined and independently
of the object fill style.

Fill Area style

The fill area style defines the pattern used to fill a polygon.
The fill area style of any class inheriting from <tt>TAttFill</tt> can
be changed using the method <tt>SetFillStyle</tt> and retrieved using the
method <tt>GetFillStyle</tt>.

Conventions for fill styles:

  0    : hollow

  1001 : Solid

  2001 : hatch style

  3000+pattern_number (see below)

  For TPad only:

  4000 :the window is transparent.

  4000 to 4100 the window is 100% transparent to 100% opaque.

pattern_number can have any value from 1 to 25 (see table), or any
value from 100 to 999. For the latest the numbering convention is the following:

      pattern_number = ijk      (FillStyle = 3ijk)

      i (1-9) : specify the space between each hatch
                1 = 1/2mm  9 = 6mm

      j (0-9) : specify angle between 0 and 90 degrees
                0 = 0
                1 = 10
                2 = 20
                3 = 30
                4 = 45
                5 = Not drawn
                6 = 60
                7 = 70
                8 = 80
                9 = 90

      k (0-9) : specify angle between 90 and 180 degrees
                0 = 180
                1 = 170
                2 = 160
                3 = 150
                4 = 135
                5 = Not drawn
                6 = 120
                7 = 110
                8 = 100
                9 = 90

The following table shows the list of pattern styles.
The first table displays the 25 fixed patterns. They cannot be
customized unlike the hatches displayed in the second table which be
customized using:

 <tt>gStyle->SetHatchesSpacing()</tt> to define the spacing between hatches.

 <tt>gStyle->SetHatchesLineWidth()</tt> to define the hatches line width.

End_Html
Begin_Macro(source)
fillpatterns.C
End_Macro */

//______________________________________________________________________________
TAttFill::TAttFill()
{
   // AttFill default constructor.
   // Default fill attributes are taking from the current style

   if (!gStyle) return;
   fFillColor = gStyle->GetFillColor();
   fFillStyle = gStyle->GetFillStyle();
}

//______________________________________________________________________________
TAttFill::TAttFill(Color_t color, Style_t style)
{
   // AttFill normal constructor.
   // color Fill Color
   // style Fill Style

   fFillColor = color;
   fFillStyle = style;
}

//______________________________________________________________________________
TAttFill::~TAttFill()
{
   // AttFill destructor.
}

//______________________________________________________________________________
void TAttFill::Copy(TAttFill &attfill) const
{
   // Copy this fill attributes to a new TAttFill.

   attfill.fFillColor  = fFillColor;
   attfill.fFillStyle  = fFillStyle;
}

//______________________________________________________________________________
void TAttFill::Modify()
{
   // Change current fill area attributes if necessary.

   if (!gPad) return;
   if (!gPad->IsBatch()) {
      gVirtualX->SetFillColor(fFillColor);
      gVirtualX->SetFillStyle(fFillStyle);
   }

   gPad->SetAttFillPS(fFillColor,fFillStyle);
}

//______________________________________________________________________________
void TAttFill::ResetAttFill(Option_t *)
{
   // Reset this fill attributes to default values.

   fFillColor = 1;
   fFillStyle = 0;
}

//______________________________________________________________________________
void TAttFill::SaveFillAttributes(ostream &out, const char *name, Int_t coldef, Int_t stydef)
{
    // Save fill attributes as C++ statement(s) on output stream out

   if (fFillColor != coldef) {
      if (fFillColor > 228) {
         TColor::SaveColor(out, fFillColor);
         out<<"   "<<name<<"->SetFillColor(ci);" << endl;
      } else
         out<<"   "<<name<<"->SetFillColor("<<fFillColor<<");"<<endl;
   }
   if (fFillStyle != stydef) {
      out<<"   "<<name<<"->SetFillStyle("<<fFillStyle<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttFill::SetFillAttributes()
{
   // Invoke the DialogCanvas Fill attributes.

   TVirtualPadEditor::UpdateFillAttributes(fFillColor,fFillStyle);
}
<commit_msg>- Complete help<commit_after>// @(#)root/base:$Id$
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TAttFill.h"
#include "TVirtualPad.h"
#include "TStyle.h"
#include "TVirtualX.h"
#include "TVirtualPadEditor.h"
#include "TColor.h"

ClassImp(TAttFill)

//______________________________________________________________________________
/* Begin_Html

Fill Area Attributes class

This class is used (in general by secondary inheritance)
by many other classes (graphics, histograms). It holds all the fill area
attributes.

Fill Area attributes

Fill Area attributes are:

Fill Area color.

Fill Area style.

Fill Area color

The fill area color is a color index (integer) pointing in the ROOT
color table.
The fill area color of any class inheriting from <tt>TAttFill</tt> can
be changed using the method <tt>SetFillColor</tt> and retrieved using the
method <tt>GetFillColor</tt>.
The following table shows the first 50 default colors.
End_Html
Begin_Macro(source)
{
   TCanvas *c = new TCanvas("c","Fill Area colors",0,0,500,200);
   c.DrawColorTable();
   return c;
}
End_Macro

Begin_Html

The ROOT Color Wheel.

The wheel contains the recommended 216 colors to be used in web applications.
The colors in the Color Wheel are created by TColor::CreateColorWheel.

Using this color set for your text, background or graphics will give your
application a consistent appearance across different platforms and browsers.

Colors are grouped by hue, the aspect most important in human perception
Touching color chips have the same hue, but with different brightness and vividness.

Colors of slightly different hues clash. If you intend to display
colors of the same hue together, you should pick them from the same group.

Each color chip is identified by a mnemonic (eg kYellow) and a number.
The keywords, kRed, kBlue, kYellow, kPink, etc are defined in the header file Rtypes.h
that is included in all ROOT other header files. We strongly recommend to use these keywords
in your code instead of hardcoded color numbers, eg:

   myObject.SetFillColor(kRed);
   myObject.SetFillColor(kYellow-10);
   myLine.SetLineColor(kMagenta+2);

End_Html
Begin_Macro(source)
{
   TColorWheel *w = new TColorWheel();
   w->Draw();
   return w->GetCanvas();
}
End_Macro

Begin_Html

Special case forcing black&white output.

If the current style fill area color is set to 0, then ROOT will force
a black&white output for all objects with a fill area defined and independently
of the object fill style.

Fill Area style

The fill area style defines the pattern used to fill a polygon.
The fill area style of any class inheriting from <tt>TAttFill</tt> can
be changed using the method <tt>SetFillStyle</tt> and retrieved using the
method <tt>GetFillStyle</tt>.

Conventions for fill styles:

  0    : hollow

  1001 : Solid

  2001 : hatch style

  3000+pattern_number (see below)

  For TPad only:

  4000 :the window is transparent.

  4000 to 4100 the window is 100% transparent to 100% opaque.

      The pad transparency is visible in binary outputs files like gif, jpg, png etc ..
      but not in vector graphics output files like PS, PDF and SVG.

pattern_number can have any value from 1 to 25 (see table), or any
value from 100 to 999. For the latest the numbering convention is the following:

      pattern_number = ijk      (FillStyle = 3ijk)

      i (1-9) : specify the space between each hatch
                1 = 1/2mm  9 = 6mm

      j (0-9) : specify angle between 0 and 90 degrees
                0 = 0
                1 = 10
                2 = 20
                3 = 30
                4 = 45
                5 = Not drawn
                6 = 60
                7 = 70
                8 = 80
                9 = 90

      k (0-9) : specify angle between 90 and 180 degrees
                0 = 180
                1 = 170
                2 = 160
                3 = 150
                4 = 135
                5 = Not drawn
                6 = 120
                7 = 110
                8 = 100
                9 = 90

The following table shows the list of pattern styles.
The first table displays the 25 fixed patterns. They cannot be
customized unlike the hatches displayed in the second table which be
customized using:

 <tt>gStyle->SetHatchesSpacing()</tt> to define the spacing between hatches.

 <tt>gStyle->SetHatchesLineWidth()</tt> to define the hatches line width.

End_Html
Begin_Macro(source)
fillpatterns.C
End_Macro */

//______________________________________________________________________________
TAttFill::TAttFill()
{
   // AttFill default constructor.
   // Default fill attributes are taking from the current style

   if (!gStyle) return;
   fFillColor = gStyle->GetFillColor();
   fFillStyle = gStyle->GetFillStyle();
}

//______________________________________________________________________________
TAttFill::TAttFill(Color_t color, Style_t style)
{
   // AttFill normal constructor.
   // color Fill Color
   // style Fill Style

   fFillColor = color;
   fFillStyle = style;
}

//______________________________________________________________________________
TAttFill::~TAttFill()
{
   // AttFill destructor.
}

//______________________________________________________________________________
void TAttFill::Copy(TAttFill &attfill) const
{
   // Copy this fill attributes to a new TAttFill.

   attfill.fFillColor  = fFillColor;
   attfill.fFillStyle  = fFillStyle;
}

//______________________________________________________________________________
void TAttFill::Modify()
{
   // Change current fill area attributes if necessary.

   if (!gPad) return;
   if (!gPad->IsBatch()) {
      gVirtualX->SetFillColor(fFillColor);
      gVirtualX->SetFillStyle(fFillStyle);
   }

   gPad->SetAttFillPS(fFillColor,fFillStyle);
}

//______________________________________________________________________________
void TAttFill::ResetAttFill(Option_t *)
{
   // Reset this fill attributes to default values.

   fFillColor = 1;
   fFillStyle = 0;
}

//______________________________________________________________________________
void TAttFill::SaveFillAttributes(ostream &out, const char *name, Int_t coldef, Int_t stydef)
{
    // Save fill attributes as C++ statement(s) on output stream out

   if (fFillColor != coldef) {
      if (fFillColor > 228) {
         TColor::SaveColor(out, fFillColor);
         out<<"   "<<name<<"->SetFillColor(ci);" << endl;
      } else
         out<<"   "<<name<<"->SetFillColor("<<fFillColor<<");"<<endl;
   }
   if (fFillStyle != stydef) {
      out<<"   "<<name<<"->SetFillStyle("<<fFillStyle<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttFill::SetFillAttributes()
{
   // Invoke the DialogCanvas Fill attributes.

   TVirtualPadEditor::UpdateFillAttributes(fFillColor,fFillStyle);
}
<|endoftext|>


<commit_before>/* Copyright (C) 2016 INRA
 *
 * 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.
 */

#include "../src/utils.hpp"
#include <efyj/efyj.hpp>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x)

namespace py = pybind11;

static void
show_context(const efyj::context& ctx) noexcept
{
    switch (ctx.status) {
    case efyj::status::success:
        break;
    case efyj::status::not_enough_memory:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::numeric_cast_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::internal_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::file_error:
        py::print(
          "File error: ", get_error_message(ctx.status), " at ", ctx.data_1);
        break;
    case efyj::status::solver_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::unconsistent_input_vector:
        break;
    case efyj::status::dexi_parser_scale_definition_error:
    case efyj::status::dexi_parser_scale_not_found:
    case efyj::status::dexi_parser_scale_too_big:
    case efyj::status::dexi_parser_file_format_error:
    case efyj::status::dexi_parser_not_enough_memory:
    case efyj::status::dexi_parser_element_unknown:
    case efyj::status::dexi_parser_option_conversion_error:
    case efyj::status::dexi_writer_error:
        py::print("DEXi error: ",
                  get_error_message(ctx.status),
                  " at line ",
                  ctx.line,
                  " column ",
                  ctx.column,
                  "with value: ",
                  ctx.data_1);
        break;
    case efyj::status::csv_parser_file_error:
    case efyj::status::csv_parser_column_number_incorrect:
    case efyj::status::csv_parser_scale_value_unknown:
    case efyj::status::csv_parser_column_conversion_failure:
    case efyj::status::csv_parser_basic_attribute_unknown:
    case efyj::status::csv_parser_init_dataset_simulation_empty:
    case efyj::status::csv_parser_init_dataset_cast_error:
        py::print("CSV error: ",
                  get_error_message(ctx.status),
                  " at line ",
                  ctx.line,
                  " column ",
                  ctx.column);
        break;
    case efyj::status::extract_option_same_input_files:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::extract_option_fail_open_file:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::merge_option_same_inputoutput:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::merge_option_fail_open_file:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::option_input_inconsistent:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::scale_value_inconsistent:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::option_too_many:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::unknown_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    }
}

static void
check_user_interrupt(void* /*user_data*/)
{
    if (PyErr_CheckSignals() != 0)
        throw py::error_already_set();
}

static bool
update_result(const efyj::result& r, void* user_data)
{
    auto* ret = reinterpret_cast<efyj::result*>(user_data);

    try {
        *ret = r;
        return true;
    } catch (...) {
        return false;
    }
};

PYBIND11_MODULE(pyefyj, m)
{
    m.doc() = R"pbdoc(
        pyefyj binding
        --------------
        .. currentmodule:: pyefyj
        .. autosummary::
           :toctree: _generate
           information
           adjustment
           prediction
    )pbdoc";

    m.attr("__version__") = MACRO_STRINGIFY(VERSION_MAJOR) "." MACRO_STRINGIFY(
      VERSION_MINOR) "." MACRO_STRINGIFY(VERSION_PATCH);

    py::class_<efyj::information_results>(m, "information_results")
      .def(py::init<>())
      .def_readonly("names", &efyj::information_results::basic_attribute_names)
      .def_readonly(
        "values",
        &efyj::information_results::basic_attribute_scale_value_numbers);

    py::class_<efyj::modifier>(m, "modifier")
      .def_readonly("attribute", &efyj::modifier::attribute)
      .def_readonly("line", &efyj::modifier::line)
      .def_readonly("value", &efyj::modifier::value);

    py::class_<efyj::result>(m, "results")
      .def(py::init<>())
      .def_readonly("modifiers", &efyj::result::modifiers)
      .def_readonly("kappa", &efyj::result::kappa)
      .def_readonly("time", &efyj::result::time)
      .def_readonly("kappa_computed", &efyj::result::kappa_computed)
      .def_readonly("function_computed", &efyj::result::function_computed);

    py::class_<efyj::data>(m, "data")
      .def(py::init<>())
      .def_readwrite("simulations", &efyj::data::simulations)
      .def_readwrite("places", &efyj::data::places)
      .def_readwrite("departments", &efyj::data::departments)
      .def_readwrite("years", &efyj::data::years)
      .def_readwrite("observed", &efyj::data::observed)
      .def_readwrite("scale_values", &efyj::data::scale_values);

    efyj::context ctx;
    ctx.out = &std::cout;
    ctx.err = &std::cerr;
    ctx.line = 0;
    ctx.column = 0;
    ctx.size = 0;
    ctx.data_1.reserve(256u);
    ctx.status = efyj::status::success;
    ctx.log_priority = efyj::log_level::info;

    m.def(
      "information",
      [&ctx](const std::string& s) -> efyj::information_results {
          efyj::information_results out;

          if (const auto ret = efyj::information(ctx, s, out); is_bad(ret))
              py::print("information(...) failed");

          return out;
      },
      R"pbdoc(
        Retrieves information from a DEXi file.
        Use this information to build correct scale values vector.
    )pbdoc");

    m.def(
      "evaluate",
      [&ctx](const std::string& s,
             const efyj::data& d) -> efyj::evaluation_results {
          efyj::evaluation_results out;

          if (const auto ret = efyj::evaluate(ctx, s, d, out); is_bad(ret)) {
              py::print("evaluation(...) failed");
          }

          return out;
      },
      R"pbdoc(
        Evaluation of DEXi file with data.
    )pbdoc");

    m.def(
      "adjustment",
      [&ctx](const std::string& model_file_path,
             const efyj::data& d) -> efyj::result {
          efyj::result out;
          const auto ret = efyj::adjustment(ctx,
                                            model_file_path,
                                            d,
                                            update_result,
                                            &out,
                                            check_user_interrupt,
                                            nullptr,
                                            true,
                                            0,
                                            1u);

          if (is_bad(ret))
              py::print("adjustment failed");

          return out;
      },
      R"pbdoc(
        Compute adjustment of a DEXi file.
    )pbdoc");

    m.def(
      "prediction",
      [&ctx](const std::string& model_file_path,
             const efyj::data& d) -> efyj::result {
          efyj::result out;
          const auto ret = efyj::prediction(ctx,
                                            model_file_path,
                                            d,
                                            update_result,
                                            &out,
                                            check_user_interrupt,
                                            nullptr,
                                            true,
                                            0,
                                            1u);

          if (is_bad(ret))
              py::print("adjustment failed");

          return out;
      },
      R"pbdoc(
        Compute prediction of a DEXi file.
    )pbdoc");

    m.def(
      "merge",
      [&ctx](const std::string& model_file_path,
             const std::string& output_file_path,
             const efyj::data& d) -> bool {
          if (const auto ret =
                efyj::merge_options(ctx, model_file_path, output_file_path, d);
              efyj::is_bad(ret)) {
              py::print("merge failed\n");
              return false;
          }

          return true;
      },
      R"pbdoc(
        Merge options data into existing DEXi file.
    )pbdoc");
}
<commit_msg>python: show more information on failure<commit_after>/* Copyright (C) 2016 INRA
 *
 * 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.
 */

#include "../src/utils.hpp"
#include <efyj/efyj.hpp>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x)

namespace py = pybind11;

static void
show_context(const efyj::context& ctx) noexcept
{
    switch (ctx.status) {
    case efyj::status::success:
        break;
    case efyj::status::not_enough_memory:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::numeric_cast_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::internal_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::file_error:
        py::print(
          "File error: ", get_error_message(ctx.status), " at ", ctx.data_1);
        break;
    case efyj::status::solver_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::unconsistent_input_vector:
        break;
    case efyj::status::dexi_parser_scale_definition_error:
    case efyj::status::dexi_parser_scale_not_found:
    case efyj::status::dexi_parser_scale_too_big:
    case efyj::status::dexi_parser_file_format_error:
    case efyj::status::dexi_parser_not_enough_memory:
    case efyj::status::dexi_parser_element_unknown:
    case efyj::status::dexi_parser_option_conversion_error:
    case efyj::status::dexi_writer_error:
        py::print("DEXi error: ",
                  get_error_message(ctx.status),
                  " at line ",
                  ctx.line,
                  " column ",
                  ctx.column,
                  "with value: ",
                  ctx.data_1);
        break;
    case efyj::status::csv_parser_file_error:
    case efyj::status::csv_parser_column_number_incorrect:
    case efyj::status::csv_parser_scale_value_unknown:
    case efyj::status::csv_parser_column_conversion_failure:
    case efyj::status::csv_parser_basic_attribute_unknown:
    case efyj::status::csv_parser_init_dataset_simulation_empty:
    case efyj::status::csv_parser_init_dataset_cast_error:
        py::print("CSV error: ",
                  get_error_message(ctx.status),
                  " at line ",
                  ctx.line,
                  " column ",
                  ctx.column);
        break;
    case efyj::status::extract_option_same_input_files:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::extract_option_fail_open_file:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::merge_option_same_inputoutput:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::merge_option_fail_open_file:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::option_input_inconsistent:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::scale_value_inconsistent:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::option_too_many:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    case efyj::status::unknown_error:
        py::print("Error: ", get_error_message(ctx.status));
        break;
    }
}

static void
check_user_interrupt(void* /*user_data*/)
{
    if (PyErr_CheckSignals() != 0)
        throw py::error_already_set();
}

static bool
update_result(const efyj::result& r, void* user_data)
{
    auto* ret = reinterpret_cast<efyj::result*>(user_data);

    try {
        *ret = r;
        return true;
    } catch (...) {
        return false;
    }
};

PYBIND11_MODULE(pyefyj, m)
{
    m.doc() = R"pbdoc(
        pyefyj binding
        --------------
        .. currentmodule:: pyefyj
        .. autosummary::
           :toctree: _generate
           information
           adjustment
           prediction
    )pbdoc";

    m.attr("__version__") = MACRO_STRINGIFY(VERSION_MAJOR) "." MACRO_STRINGIFY(
      VERSION_MINOR) "." MACRO_STRINGIFY(VERSION_PATCH);

    py::class_<efyj::information_results>(m, "information_results")
      .def(py::init<>())
      .def_readonly("names", &efyj::information_results::basic_attribute_names)
      .def_readonly(
        "values",
        &efyj::information_results::basic_attribute_scale_value_numbers);

    py::class_<efyj::modifier>(m, "modifier")
      .def_readonly("attribute", &efyj::modifier::attribute)
      .def_readonly("line", &efyj::modifier::line)
      .def_readonly("value", &efyj::modifier::value);

    py::class_<efyj::result>(m, "results")
      .def(py::init<>())
      .def_readonly("modifiers", &efyj::result::modifiers)
      .def_readonly("kappa", &efyj::result::kappa)
      .def_readonly("time", &efyj::result::time)
      .def_readonly("kappa_computed", &efyj::result::kappa_computed)
      .def_readonly("function_computed", &efyj::result::function_computed);

    py::class_<efyj::data>(m, "data")
      .def(py::init<>())
      .def_readwrite("simulations", &efyj::data::simulations)
      .def_readwrite("places", &efyj::data::places)
      .def_readwrite("departments", &efyj::data::departments)
      .def_readwrite("years", &efyj::data::years)
      .def_readwrite("observed", &efyj::data::observed)
      .def_readwrite("scale_values", &efyj::data::scale_values);

    efyj::context ctx;
    ctx.out = &std::cout;
    ctx.err = &std::cerr;
    ctx.line = 0;
    ctx.column = 0;
    ctx.size = 0;
    ctx.data_1.reserve(256u);
    ctx.status = efyj::status::success;
    ctx.log_priority = efyj::log_level::info;

    m.def(
      "information",
      [&ctx](const std::string& s) -> efyj::information_results {
          efyj::information_results out;

          if (const auto ret = efyj::information(ctx, s, out); is_bad(ret)) {
              py::print("information(...) failed");
	      show_context(ctx);
	  }

          return out;
      },
      R"pbdoc(
        Retrieves information from a DEXi file.
        Use this information to build correct scale values vector.
    )pbdoc");

    m.def(
      "evaluate",
      [&ctx](const std::string& s,
             const efyj::data& d) -> efyj::evaluation_results {
          efyj::evaluation_results out;

          if (const auto ret = efyj::evaluate(ctx, s, d, out); is_bad(ret)) {
              py::print("evaluation(...) failed");
	      show_context(ctx);
          }

          return out;
      },
      R"pbdoc(
        Evaluation of DEXi file with data.
    )pbdoc");

    m.def(
      "adjustment",
      [&ctx](const std::string& model_file_path,
             const efyj::data& d) -> efyj::result {
          efyj::result out;
          const auto ret = efyj::adjustment(ctx,
                                            model_file_path,
                                            d,
                                            update_result,
                                            &out,
                                            check_user_interrupt,
                                            nullptr,
                                            true,
                                            0,
                                            1u);

          if (is_bad(ret)) {
              py::print("adjustment failed");
	      show_context(ctx);
	  }

          return out;
      },
      R"pbdoc(
        Compute adjustment of a DEXi file.
    )pbdoc");

    m.def(
      "prediction",
      [&ctx](const std::string& model_file_path,
             const efyj::data& d) -> efyj::result {
          efyj::result out;
          const auto ret = efyj::prediction(ctx,
                                            model_file_path,
                                            d,
                                            update_result,
                                            &out,
                                            check_user_interrupt,
                                            nullptr,
                                            true,
                                            0,
                                            1u);

          if (is_bad(ret)) {
              py::print("adjustment failed");
	      show_context(ctx);
	  }

          return out;
      },
      R"pbdoc(
        Compute prediction of a DEXi file.
    )pbdoc");

    m.def(
      "merge",
      [&ctx](const std::string& model_file_path,
             const std::string& output_file_path,
             const efyj::data& d) -> bool {
          if (const auto ret =
                efyj::merge_options(ctx, model_file_path, output_file_path, d);
              efyj::is_bad(ret)) {
              py::print("merge failed\n");
	      show_context(ctx);
              return false;
          }

          return true;
      },
      R"pbdoc(
        Merge options data into existing DEXi file.
    )pbdoc");
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * 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.
 */

/*
 * Description:
 *     checkpoint the replicated app
 *
 * Revision history:
 *     Nov., 2015, @imzhenyu (Zhenyu Guo), first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include "replica.h"
#include "mutation.h"
#include "mutation_log.h"
#include "replica_stub.h"

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ "replica.chkpoint"

namespace dsn {
    namespace replication {

        void replica::on_checkpoint_timer()
        {
            check_hashed_access();
            init_checkpoint();
            garbage_collection();
        }

        // run in replica thread
        void replica::garbage_collection()
        {
            if (_private_log)
            {
                _private_log->garbage_collection(
                    get_gpid(),
                    _app->last_durable_decree(),
                    _app->init_info().init_offset_in_private_log
                    );
                if(PS_PRIMARY == status())
                {
                    _counter_private_log_size.set(_private_log->size() / 1000000);
                }
            }
        }

        // run in replica thread
        void replica::init_checkpoint()
        {
            // only applicable to primary and secondary replicas
            if (status() != PS_PRIMARY && status() != PS_SECONDARY)
                return;

            // no need to checkpoint
            if (_app->is_delta_state_learning_supported())
                return;

            auto err = _app->checkpoint_async();
            if (err != ERR_NOT_IMPLEMENTED)
            {
                if (err == ERR_OK)
                {
                    ddebug("%s: checkpoint_async succeed, app_last_committed_decree=%" PRId64 ", app_last_durable_decree=%" PRId64,
                           name(), _app->last_committed_decree(), _app->last_durable_decree());
                }
                if (err != ERR_OK && err != ERR_WRONG_TIMING && err != ERR_NO_NEED_OPERATE && err != ERR_TRY_AGAIN)
                {
                    derror("%s: checkpoint_async failed, err = %s", name(), err.to_string());
                }
                return;
            }

            // private log must be enabled to make sure commits
            // are not lost during checkpinting
            dassert(nullptr != _private_log, "log_enable_private_prepare must be true for checkpointing");

            if (last_committed_decree() - last_durable_decree() < _options->checkpoint_min_decree_gap)
                return;

            // primary cannot checkpoint (TODO: test if async checkpoint is supported)
            // therefore we have to copy checkpoints from secondaries
            if (PS_PRIMARY == status())
            {
                // only one running instance
                if (nullptr == _primary_states.checkpoint_task)
                {
                    if (_primary_states.membership.secondaries.size() == 0)
                        return;

                    std::shared_ptr<replica_configuration> rc(new replica_configuration);
                    _primary_states.get_replica_config(PS_SECONDARY, *rc);

                    rpc_address sd = _primary_states.membership.secondaries
                        [dsn_random32(0, (int)_primary_states.membership.secondaries.size() - 1)];

                    _primary_states.checkpoint_task = rpc::call(
                        sd,
                        RPC_REPLICA_COPY_LAST_CHECKPOINT,
                        *rc,
                        this,
                        [=](error_code err_local, learn_response&& response)
                        {
                            auto response_alloc = std::make_shared<learn_response>(std::move(response));
                            on_copy_checkpoint_ack(err_local, rc, response_alloc);
                        },
                        gpid_to_hash(get_gpid())
                        );
                }
            }

            // secondary can start checkpint in the long running thread pool
            else
            {
                dassert(PS_SECONDARY == status(), "");

                // only one running instance
                if (!_secondary_states.checkpoint_is_running)
                {
                    _secondary_states.checkpoint_is_running = true;
                    _secondary_states.checkpoint_task = tasking::create_task(
                        LPC_CHECKPOINT_REPLICA,
                        this,
                        [this] {background_checkpoint();},
                        gpid_to_hash(get_gpid()));
                    _secondary_states.checkpoint_task->enqueue();
                }
            }
        }

        // @ secondary
        void replica::on_copy_checkpoint(const replica_configuration& request, /*out*/ learn_response& response)
        {
            check_hashed_access();

            if (request.ballot > get_ballot())
            {
                if (!update_local_configuration(request))
                {
                    response.err = ERR_INVALID_STATE;
                    return;
                }
            }

            if (status() != PS_SECONDARY)
            {
                response.err = ERR_INVALID_STATE;
                return;
            }

            if (_app->last_durable_decree() == 0)
            {
                response.err = ERR_OBJECT_NOT_FOUND;
                return;
            }

            blob placeholder;
            int err = _app->get_checkpoint(0, placeholder, response.state);
            if (err != 0)
            {
                response.err = ERR_LEARN_FILE_FAILED;
            }
            else
            {
                response.err = ERR_OK;
                response.last_committed_decree = last_committed_decree();
                response.base_local_dir = _app->data_dir();

                // the state.files is returned whether with full_path or only-filename depends
                // on the app impl, we'd better handle with it
                for (std::string& file_name: response.state.files)
                {
                    std::size_t last_splitter = file_name.find_last_of("/\\");
                    if (last_splitter != std::string::npos)
                        file_name = file_name.substr(last_splitter+1);
                }
                response.address = _stub->_primary_address;
            }
        }

        void replica::on_copy_checkpoint_ack(error_code err, const std::shared_ptr<replica_configuration>& req, const std::shared_ptr<learn_response>& resp)
        {
            check_hashed_access();

            if (PS_PRIMARY != status())
            {
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (err != ERR_OK || resp == nullptr)
            {
                dwarn("%s: copy checkpoint from secondary failed, err = %s", name(), err.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (resp->err != ERR_OK)
            {
                dinfo("%s: copy checkpoint from secondary failed, err = %s", name(), resp->err.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (resp->state.to_decree_included <= _app->last_durable_decree())
            {
                dinfo("%s: copy checkpoint from secondary skipped, as its decree is not bigger than current durable_decree: %" PRIu64 " vs %" PRIu64 "",
                    name(), resp->state.to_decree_included, _app->last_durable_decree()
                    );
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            std::string ldir = utils::filesystem::path_combine(
                _app->learn_dir(),
                "checkpoint.copy"
                );

            if (utils::filesystem::path_exists(ldir))
                utils::filesystem::remove_path(ldir);

            _primary_states.checkpoint_task = file::copy_remote_files(
                resp->address,
                resp->base_local_dir,
                resp->state.files,
                ldir,
                false,
                LPC_REPLICA_COPY_LAST_CHECKPOINT_DONE,
                this,
                [this, resp, ldir](error_code err, size_t sz)
                {
                    this->on_copy_checkpoint_file_completed(err, sz, resp, ldir);
                },
                gpid_to_hash(get_gpid())
                );
        }

        void replica::on_copy_checkpoint_file_completed(error_code err, size_t sz, std::shared_ptr<learn_response> resp, const std::string& chk_dir)
        {
            check_hashed_access();

            if (ERR_OK != err)
            {
                if (ERR_TIMEOUT == err)
                    dwarn("copy checkpoint failed, err(%s), remote_addr(%s)", err.to_string(), resp->address.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }
            if (PS_PRIMARY == status() && resp->state.to_decree_included > _app->last_durable_decree())
            {
                // we must give the app the full path of the check point
                for (std::string& filename: resp->state.files)
                {
                    dassert(filename.find_last_of("/\\")==std::string::npos, "invalid file name");
                    filename = utils::filesystem::path_combine(chk_dir, filename);
                }
                _app->apply_checkpoint(resp->state, CHKPT_COPY);
            }

            _primary_states.checkpoint_task = nullptr;
        }

        // run in background thread
        void replica::background_checkpoint()
        {
            auto err = _app->checkpoint();
            _secondary_states.checkpoint_completed_task = tasking::enqueue(
                LPC_CHECKPOINT_REPLICA_COMPLETED,
                this,
                [this, err]() { this->on_checkpoint_completed(err); },
                gpid_to_hash(get_gpid())
                );
        }

        void replica::catch_up_with_private_logs(partition_status s)
        {
            learn_state state;
            _private_log->get_learn_state(
                get_gpid(),
                _app->last_committed_decree() + 1,
                state
                );

            auto err = apply_learned_state_from_private_log(state);

            if (s == PS_POTENTIAL_SECONDARY)
            {
                _potential_secondary_states.learn_remote_files_completed_task = tasking::create_task(
                    LPC_CHECKPOINT_REPLICA_COMPLETED,
                    this,
                    [this, err]()
                    {
                        this->on_learn_remote_state_completed(err);
                    },
                    gpid_to_hash(get_gpid())
                    );
                _potential_secondary_states.learn_remote_files_completed_task->enqueue();
            }
            else
            {
                _secondary_states.checkpoint_completed_task = tasking::create_task(
                    LPC_CHECKPOINT_REPLICA_COMPLETED,
                    this,
                    [this, err]()
                    {
                        this->on_checkpoint_completed(err);
                    },
                    gpid_to_hash(get_gpid())
                    );
                _secondary_states.checkpoint_completed_task->enqueue();
            }
        }

        void replica::on_checkpoint_completed(error_code err)
        {
            check_hashed_access();

            // closing or wrong timing or no need operate
            if (PS_SECONDARY != status() || err == ERR_WRONG_TIMING || err == ERR_NO_NEED_OPERATE)
            {
                _secondary_states.checkpoint_is_running = false;
                return;
            }

            // handle failure
            if (err != ERR_OK)
            {
                // done checkpointing
                _secondary_states.checkpoint_is_running = false;
                handle_local_failure(err);
                return;
            }

            auto c = _prepare_list->last_committed_decree();

            // missing commits
            if (c > _app->last_committed_decree())
            {
                // missed ones are covered by prepare list
                if (_app->last_committed_decree() > _prepare_list->min_decree())
                {
                    for (auto d = _app->last_committed_decree() + 1; d <= c; d++)
                    {
                        auto mu = _prepare_list->get_mutation_by_decree(d);
                        dassert(nullptr != mu, "");
                        err = _app->write_internal(mu);
                        if (ERR_OK != err)
                        {
                            _secondary_states.checkpoint_is_running = false;
                            handle_local_failure(err);
                            return;
                        }
                    }

                    // everything is ok now, done checkpointing
                    _secondary_states.checkpoint_is_running = false;
                }

                // missed ones need to be loaded via private logs
                else
                {
                    _secondary_states.catchup_with_private_log_task = tasking::create_task(
                        LPC_CATCHUP_WITH_PRIVATE_LOGS,
                        this,
                        [this]() { this->catch_up_with_private_logs(PS_SECONDARY); },
                        gpid_to_hash(get_gpid())
                        );
                    _secondary_states.catchup_with_private_log_task->enqueue();
                }
            }

            // no missing commits
            else
            {
                // everything is ok now, done checkpointing
                _secondary_states.checkpoint_is_running = false;
            }
        }
    }
} // namespace
<commit_msg>smallfix<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * 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.
 */

/*
 * Description:
 *     checkpoint the replicated app
 *
 * Revision history:
 *     Nov., 2015, @imzhenyu (Zhenyu Guo), first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include "replica.h"
#include "mutation.h"
#include "mutation_log.h"
#include "replica_stub.h"

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ "replica.chkpoint"

namespace dsn {
    namespace replication {

        void replica::on_checkpoint_timer()
        {
            check_hashed_access();
            init_checkpoint();
            garbage_collection();
        }

        // run in replica thread
        void replica::garbage_collection()
        {
            if (_private_log)
            {
                _private_log->garbage_collection(
                    get_gpid(),
                    _app->last_durable_decree(),
                    _app->init_info().init_offset_in_private_log
                    );
                if(PS_PRIMARY == status())
                {
                    _counter_private_log_size.set(_private_log->size() / 1000000);
                }
            }
        }

        // run in replica thread
        void replica::init_checkpoint()
        {
            // only applicable to primary and secondary replicas
            if (status() != PS_PRIMARY && status() != PS_SECONDARY)
                return;

            // no need to checkpoint
            if (_app->is_delta_state_learning_supported())
                return;

            auto err = _app->checkpoint_async();
            if (err != ERR_NOT_IMPLEMENTED)
            {
                if (err == ERR_OK)
                {
                    ddebug("%s: checkpoint_async succeed, app_last_committed_decree=%" PRId64 ", app_last_durable_decree=%" PRId64,
                           name(), _app->last_committed_decree(), _app->last_durable_decree());
                }
                if (err != ERR_OK && err != ERR_WRONG_TIMING && err != ERR_NO_NEED_OPERATE && err != ERR_TRY_AGAIN)
                {
                    derror("%s: checkpoint_async failed, err = %s", name(), err.to_string());
                }
                return;
            }

            // private log must be enabled to make sure commits
            // are not lost during checkpinting
            dassert(nullptr != _private_log, "log_enable_private_prepare must be true for checkpointing");

            if (last_committed_decree() - last_durable_decree() < _options->checkpoint_min_decree_gap)
                return;

            // primary cannot checkpoint (TODO: test if async checkpoint is supported)
            // therefore we have to copy checkpoints from secondaries
            if (PS_PRIMARY == status())
            {
                // only one running instance
                if (nullptr == _primary_states.checkpoint_task)
                {
                    if (_primary_states.membership.secondaries.size() == 0)
                        return;

                    std::shared_ptr<replica_configuration> rc(new replica_configuration);
                    _primary_states.get_replica_config(PS_SECONDARY, *rc);

                    rpc_address sd = _primary_states.membership.secondaries
                        [dsn_random32(0, (int)_primary_states.membership.secondaries.size() - 1)];

                    _primary_states.checkpoint_task = rpc::call(
                        sd,
                        RPC_REPLICA_COPY_LAST_CHECKPOINT,
                        *rc,
                        this,
                        [=](error_code err_local, learn_response&& response)
                        {
                            auto response_alloc = std::make_shared<learn_response>(std::move(response));
                            on_copy_checkpoint_ack(err_local, rc, response_alloc);
                        },
                        gpid_to_hash(get_gpid())
                        );
                }
            }

            // secondary can start checkpint in the long running thread pool
            else
            {
                dassert(PS_SECONDARY == status(), "");

                // only one running instance
                if (!_secondary_states.checkpoint_is_running)
                {
                    _secondary_states.checkpoint_is_running = true;
                    _secondary_states.checkpoint_task = tasking::create_task(
                        LPC_CHECKPOINT_REPLICA,
                        this,
                        [this] {background_checkpoint();},
                        gpid_to_hash(get_gpid()));
                    _secondary_states.checkpoint_task->enqueue();
                }
            }
        }

        // @ secondary
        void replica::on_copy_checkpoint(const replica_configuration& request, /*out*/ learn_response& response)
        {
            check_hashed_access();

            if (request.ballot > get_ballot())
            {
                if (!update_local_configuration(request))
                {
                    response.err = ERR_INVALID_STATE;
                    return;
                }
            }

            if (status() != PS_SECONDARY)
            {
                response.err = ERR_INVALID_STATE;
                return;
            }

            if (_app->last_durable_decree() == 0)
            {
                response.err = ERR_OBJECT_NOT_FOUND;
                return;
            }

            blob placeholder;
            int err = _app->get_checkpoint(0, placeholder, response.state);
            if (err != 0)
            {
                response.err = ERR_LEARN_FILE_FAILED;
            }
            else
            {
                response.err = ERR_OK;
                response.last_committed_decree = last_committed_decree();
                response.base_local_dir = _app->data_dir();

                // the state.files is returned whether with full_path or only-filename depends
                // on the app impl, we'd better handle with it
                for (std::string& file_name: response.state.files)
                {
                    std::size_t last_splitter = file_name.find_last_of("/\\");
                    if (last_splitter != std::string::npos)
                        file_name = file_name.substr(last_splitter+1);
                }
                response.address = _stub->_primary_address;
            }
        }

        void replica::on_copy_checkpoint_ack(error_code err, const std::shared_ptr<replica_configuration>& req, const std::shared_ptr<learn_response>& resp)
        {
            check_hashed_access();

            if (PS_PRIMARY != status())
            {
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (err != ERR_OK || resp == nullptr)
            {
                dwarn("%s: copy checkpoint from secondary failed, err = %s", name(), err.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (resp->err != ERR_OK)
            {
                dinfo("%s: copy checkpoint from secondary failed, err = %s", name(), resp->err.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            if (resp->state.to_decree_included <= _app->last_durable_decree())
            {
                dinfo("%s: copy checkpoint from secondary skipped, as its decree is not bigger than current durable_decree: %" PRIu64 " vs %" PRIu64 "",
                    name(), resp->state.to_decree_included, _app->last_durable_decree()
                    );
                _primary_states.checkpoint_task = nullptr;
                return;
            }

            std::string ldir = utils::filesystem::path_combine(
                _app->learn_dir(),
                "checkpoint.copy"
                );

            if (utils::filesystem::path_exists(ldir))
                utils::filesystem::remove_path(ldir);

            _primary_states.checkpoint_task = file::copy_remote_files(
                resp->address,
                resp->base_local_dir,
                resp->state.files,
                ldir,
                false,
                LPC_REPLICA_COPY_LAST_CHECKPOINT_DONE,
                this,
                [this, resp, ldir](error_code err, size_t sz)
                {
                    this->on_copy_checkpoint_file_completed(err, sz, resp, ldir);
                },
                gpid_to_hash(get_gpid())
                );
        }

        void replica::on_copy_checkpoint_file_completed(error_code err, size_t sz, std::shared_ptr<learn_response> resp, const std::string& chk_dir)
        {
            check_hashed_access();

            if (ERR_OK != err)
            {
                dwarn("copy checkpoint failed, err(%s), remote_addr(%s)", err.to_string(), resp->address.to_string());
                _primary_states.checkpoint_task = nullptr;
                return;
            }
            if (PS_PRIMARY == status() && resp->state.to_decree_included > _app->last_durable_decree())
            {
                // we must give the app the full path of the check point
                for (std::string& filename: resp->state.files)
                {
                    dassert(filename.find_last_of("/\\")==std::string::npos, "invalid file name");
                    filename = utils::filesystem::path_combine(chk_dir, filename);
                }
                _app->apply_checkpoint(resp->state, CHKPT_COPY);
            }

            _primary_states.checkpoint_task = nullptr;
        }

        // run in background thread
        void replica::background_checkpoint()
        {
            auto err = _app->checkpoint();
            _secondary_states.checkpoint_completed_task = tasking::enqueue(
                LPC_CHECKPOINT_REPLICA_COMPLETED,
                this,
                [this, err]() { this->on_checkpoint_completed(err); },
                gpid_to_hash(get_gpid())
                );
        }

        void replica::catch_up_with_private_logs(partition_status s)
        {
            learn_state state;
            _private_log->get_learn_state(
                get_gpid(),
                _app->last_committed_decree() + 1,
                state
                );

            auto err = apply_learned_state_from_private_log(state);

            if (s == PS_POTENTIAL_SECONDARY)
            {
                _potential_secondary_states.learn_remote_files_completed_task = tasking::create_task(
                    LPC_CHECKPOINT_REPLICA_COMPLETED,
                    this,
                    [this, err]()
                    {
                        this->on_learn_remote_state_completed(err);
                    },
                    gpid_to_hash(get_gpid())
                    );
                _potential_secondary_states.learn_remote_files_completed_task->enqueue();
            }
            else
            {
                _secondary_states.checkpoint_completed_task = tasking::create_task(
                    LPC_CHECKPOINT_REPLICA_COMPLETED,
                    this,
                    [this, err]()
                    {
                        this->on_checkpoint_completed(err);
                    },
                    gpid_to_hash(get_gpid())
                    );
                _secondary_states.checkpoint_completed_task->enqueue();
            }
        }

        void replica::on_checkpoint_completed(error_code err)
        {
            check_hashed_access();

            // closing or wrong timing or no need operate
            if (PS_SECONDARY != status() || err == ERR_WRONG_TIMING || err == ERR_NO_NEED_OPERATE)
            {
                _secondary_states.checkpoint_is_running = false;
                return;
            }

            // handle failure
            if (err != ERR_OK)
            {
                // done checkpointing
                _secondary_states.checkpoint_is_running = false;
                handle_local_failure(err);
                return;
            }

            auto c = _prepare_list->last_committed_decree();

            // missing commits
            if (c > _app->last_committed_decree())
            {
                // missed ones are covered by prepare list
                if (_app->last_committed_decree() > _prepare_list->min_decree())
                {
                    for (auto d = _app->last_committed_decree() + 1; d <= c; d++)
                    {
                        auto mu = _prepare_list->get_mutation_by_decree(d);
                        dassert(nullptr != mu, "");
                        err = _app->write_internal(mu);
                        if (ERR_OK != err)
                        {
                            _secondary_states.checkpoint_is_running = false;
                            handle_local_failure(err);
                            return;
                        }
                    }

                    // everything is ok now, done checkpointing
                    _secondary_states.checkpoint_is_running = false;
                }

                // missed ones need to be loaded via private logs
                else
                {
                    _secondary_states.catchup_with_private_log_task = tasking::create_task(
                        LPC_CATCHUP_WITH_PRIVATE_LOGS,
                        this,
                        [this]() { this->catch_up_with_private_logs(PS_SECONDARY); },
                        gpid_to_hash(get_gpid())
                        );
                    _secondary_states.catchup_with_private_log_task->enqueue();
                }
            }

            // no missing commits
            else
            {
                // everything is ok now, done checkpointing
                _secondary_states.checkpoint_is_running = false;
            }
        }
    }
} // namespace
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BST_MENUS_H__
#define __BST_MENUS_H__

#include        "bstutils.hh"

/* --- BstChoice --- */
/* BstChoice are simple inlined popup menus for modal selections.
 */
struct BstChoice;

GtkWidget* bst_choice_menu_createv        (const gchar		  *menu_path,
					   BstChoice              *first_choice,
					   ...);
void bst_choice_menu_add_choice_and_free  (GtkWidget		  *menu,
					   BstChoice		  *choice);
void bst_choice_menu_set_item_sensitive	  (GtkWidget		  *menu,
					   gulong		   id,
					   gboolean		   sensitive);
GtkWidget* bst_choice_dialog_createv      (BstChoice              *first_choice,
					   ...) G_GNUC_NULL_TERMINATED;
gboolean   bst_choice_selectable          (GtkWidget              *widget);
guint      bst_choice_modal               (GtkWidget              *widget,
					   guint                   mouse_button,
					   guint32                 time);
guint      bst_choice_get_last            (GtkWidget              *widget);
void	   bst_choice_destroy		  (GtkWidget		  *choice);

/* --- BstChoice shortcuts --- */
#define BST_CHOICE_TITLE(name)           (bst_choice_alloc (BST_CHOICE_TYPE_TITLE, \
							    (name), NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE(id, name, bst_icon)   (bst_choice_alloc (BST_CHOICE_TYPE_ITEM, \
							    (name), (void*) (size_t) (id), \
                                                            BST_STOCK_ ## bst_icon, Bse::Icon()))
#define BST_CHOICE_D(id, name, bst_icon) (bst_choice_alloc (BST_CHOICE_TYPE_ITEM | \
							    BST_CHOICE_FLAG_DEFAULT, \
                                                            (name), (void*) (size_t) (id), \
							    BST_STOCK_ ## bst_icon, Bse::Icon()))
#define BST_CHOICE_S(id, name, icon, s)  (bst_choice_alloc (BST_CHOICE_TYPE_ITEM | \
							    ((s) ? (BstChoiceFlags) 0 : BST_CHOICE_FLAG_INSENSITIVE), \
                                                            (name), (void*) (size_t) (id), \
							    BST_STOCK_ ## icon, Bse::Icon()))
#define BST_CHOICE_SUBMENU(nam,menu,icn) (bst_choice_alloc (BST_CHOICE_TYPE_SUBMENU, \
							    (nam), (menu), BST_STOCK_ ## icn, Bse::Icon()))
#define BST_CHOICE_TEXT(name)            (bst_choice_alloc (BST_CHOICE_TYPE_TEXT, \
							    (name), NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE_SEPERATOR             (bst_choice_alloc (BST_CHOICE_TYPE_SEPARATOR, \
							    "", NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE_END                   (NULL)

/* --- private implementation stubs --- */
typedef enum
{
  BST_CHOICE_TYPE_SEPARATOR	= 0,
  BST_CHOICE_TYPE_TITLE		= 1,
  BST_CHOICE_TYPE_TEXT		= 2,
  BST_CHOICE_TYPE_ITEM		= 3,
  BST_CHOICE_TYPE_SUBMENU	= 4,
  BST_CHOICE_TYPE_MASK		= 0xff,
  BST_CHOICE_FLAG_INSENSITIVE	= (1 << 8),
  BST_CHOICE_FLAG_DEFAULT	= (1 << 9),
  BST_CHOICE_FLAG_MASK		= (~BST_CHOICE_TYPE_MASK)
} BstChoiceFlags;
BstChoice* bst_choice_alloc               (BstChoiceFlags          type,
					   const String           &choice_name,
					   void                   *choice_id,
					   const String 	  &icon_stock_id,
					   const Bse::Icon	  &bseicon);

// == Flags Enumeration Operators in C++ ==
#ifdef __cplusplus
constexpr BstChoiceFlags  operator&  (BstChoiceFlags  s1, BstChoiceFlags s2) { return BstChoiceFlags (s1 & (long long unsigned) s2); }
inline    BstChoiceFlags& operator&= (BstChoiceFlags &s1, BstChoiceFlags s2) { s1 = s1 & s2; return s1; }
constexpr BstChoiceFlags  operator|  (BstChoiceFlags  s1, BstChoiceFlags s2) { return BstChoiceFlags (s1 | (long long unsigned) s2); }
inline    BstChoiceFlags& operator|= (BstChoiceFlags &s1, BstChoiceFlags s2) { s1 = s1 | s2; return s1; }
constexpr BstChoiceFlags  operator~  (BstChoiceFlags  s1)                    { return BstChoiceFlags (~(long long unsigned) s1); }
#endif // __cplusplus

#endif  /* __BST_MENUS_H__ */
<commit_msg>BEAST-GTK: bstmenus: fix nullptr sentinel<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BST_MENUS_H__
#define __BST_MENUS_H__

#include        "bstutils.hh"

/* --- BstChoice --- */
/* BstChoice are simple inlined popup menus for modal selections.
 */
struct BstChoice;

GtkWidget* bst_choice_menu_createv        (const gchar		  *menu_path,
					   BstChoice              *first_choice,
					   ...);
void bst_choice_menu_add_choice_and_free  (GtkWidget		  *menu,
					   BstChoice		  *choice);
void bst_choice_menu_set_item_sensitive	  (GtkWidget		  *menu,
					   gulong		   id,
					   gboolean		   sensitive);
GtkWidget* bst_choice_dialog_createv      (BstChoice              *first_choice,
					   ...) G_GNUC_NULL_TERMINATED;
gboolean   bst_choice_selectable          (GtkWidget              *widget);
guint      bst_choice_modal               (GtkWidget              *widget,
					   guint                   mouse_button,
					   guint32                 time);
guint      bst_choice_get_last            (GtkWidget              *widget);
void	   bst_choice_destroy		  (GtkWidget		  *choice);

/* --- BstChoice shortcuts --- */
#define BST_CHOICE_TITLE(name)           (bst_choice_alloc (BST_CHOICE_TYPE_TITLE, \
							    (name), NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE(id, name, bst_icon)   (bst_choice_alloc (BST_CHOICE_TYPE_ITEM, \
							    (name), (void*) (size_t) (id), \
                                                            BST_STOCK_ ## bst_icon, Bse::Icon()))
#define BST_CHOICE_D(id, name, bst_icon) (bst_choice_alloc (BST_CHOICE_TYPE_ITEM | \
							    BST_CHOICE_FLAG_DEFAULT, \
                                                            (name), (void*) (size_t) (id), \
							    BST_STOCK_ ## bst_icon, Bse::Icon()))
#define BST_CHOICE_S(id, name, icon, s)  (bst_choice_alloc (BST_CHOICE_TYPE_ITEM | \
							    ((s) ? (BstChoiceFlags) 0 : BST_CHOICE_FLAG_INSENSITIVE), \
                                                            (name), (void*) (size_t) (id), \
							    BST_STOCK_ ## icon, Bse::Icon()))
#define BST_CHOICE_SUBMENU(nam,menu,icn) (bst_choice_alloc (BST_CHOICE_TYPE_SUBMENU, \
							    (nam), (menu), BST_STOCK_ ## icn, Bse::Icon()))
#define BST_CHOICE_TEXT(name)            (bst_choice_alloc (BST_CHOICE_TYPE_TEXT, \
							    (name), NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE_SEPERATOR             (bst_choice_alloc (BST_CHOICE_TYPE_SEPARATOR, \
							    "", NULL, BST_STOCK_NONE, Bse::Icon()))
#define BST_CHOICE_END                   (nullptr)

/* --- private implementation stubs --- */
typedef enum
{
  BST_CHOICE_TYPE_SEPARATOR	= 0,
  BST_CHOICE_TYPE_TITLE		= 1,
  BST_CHOICE_TYPE_TEXT		= 2,
  BST_CHOICE_TYPE_ITEM		= 3,
  BST_CHOICE_TYPE_SUBMENU	= 4,
  BST_CHOICE_TYPE_MASK		= 0xff,
  BST_CHOICE_FLAG_INSENSITIVE	= (1 << 8),
  BST_CHOICE_FLAG_DEFAULT	= (1 << 9),
  BST_CHOICE_FLAG_MASK		= (~BST_CHOICE_TYPE_MASK)
} BstChoiceFlags;
BstChoice* bst_choice_alloc               (BstChoiceFlags          type,
					   const String           &choice_name,
					   void                   *choice_id,
					   const String 	  &icon_stock_id,
					   const Bse::Icon	  &bseicon);

// == Flags Enumeration Operators in C++ ==
#ifdef __cplusplus
constexpr BstChoiceFlags  operator&  (BstChoiceFlags  s1, BstChoiceFlags s2) { return BstChoiceFlags (s1 & (long long unsigned) s2); }
inline    BstChoiceFlags& operator&= (BstChoiceFlags &s1, BstChoiceFlags s2) { s1 = s1 & s2; return s1; }
constexpr BstChoiceFlags  operator|  (BstChoiceFlags  s1, BstChoiceFlags s2) { return BstChoiceFlags (s1 | (long long unsigned) s2); }
inline    BstChoiceFlags& operator|= (BstChoiceFlags &s1, BstChoiceFlags s2) { s1 = s1 | s2; return s1; }
constexpr BstChoiceFlags  operator~  (BstChoiceFlags  s1)                    { return BstChoiceFlags (~(long long unsigned) s1); }
#endif // __cplusplus

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


<commit_before>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"

#include "entityx/System.h"
#include "Transform.h"
#include "cinder/Perlin.h"
#include "cinder/Rand.h"

#include "Components.h"
#include "Systems.h"
#include "Expires.h"
#include "ExpiresSystem.h"
#include "Behavior.h"
#include "BehaviorSystem.h"
#include "Behaviors.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace soso;

// Wraps positions to stay within a rectangle.
const auto borderWrap = createWrapFunction(Rectf(0, 0, 640, 480));

///
/// EntityCreationApp demonstrates creation of entities and some of the uses of components and systems.
///
class EntityCreationApp : public App {
public:
	EntityCreationApp();

	void setup() override;
	void mouseDown(MouseEvent event) override;
	void mouseDrag(MouseEvent event) override;
	void mouseUp(MouseEvent event) override;
	void keyDown(KeyEvent event) override;
	void update() override;
	void draw() override;

	entityx::Entity createDot(const ci::vec2 &position, const ci::vec2 &direction, float diameter);

private:
	entityx::EventManager	 events;
	entityx::EntityManager entities;
	entityx::SystemManager systems;
	uint32_t							 num_dots = 0;
	static const uint32_t	 max_dots = 1024;

	ci::vec2							 mouse, mouse_prev;
	bool									 do_clear = true;
};

// Initialize our EntityManager and SystemManager to know about events and each other.

EntityCreationApp::EntityCreationApp()
: entities(events),
	systems(entities, events)
{}

void EntityCreationApp::setup()
{
	// Create our systems for controlling entity behavior.
	// We also use free functions for entity behavior, which don't need to be instantiated.
	systems.add<ExpiresSystem>();
	systems.add<BehaviorSystem>(entities);
	systems.configure();

	// Create an initial dot on screen
	createDot(getWindowCenter(), vec2(1, 0), 36.0f);
}

entityx::Entity EntityCreationApp::createDot(const ci::vec2 &position, const ci::vec2 &direction, float diameter)
{
	// Keep track of the number of dots created so we don't have way too many.
	if (num_dots > max_dots) {
		return entityx::Entity(); // return an invalid entity
	}
	num_dots += 1;

	// Create an entity, managed by `entities`.
	auto dot = entities.create();
	// Assign the components we care about
	dot.assign<Position>(position);
	dot.assign<Circle>(diameter);
	dot.assign<Motion>(direction, 250.0f);
	// Assign an Expires component and store a handle to it in `exp`
	auto exp = dot.assign<Expires>(randFloat(4.0f, 6.0f));

	// Set a function to call when the Expires component runs out of time//
	// Called last_wish, since it happens just before the entity is destroyed.
	exp->last_wish = [this, diameter, direction] (entityx::Entity e) {
		num_dots -= 1;

		if (diameter > 8.0f) {
			// If we weren't too small, create some smaller dots where we were destroyed.
			auto pos = e.component<Position>()->position;
			auto dir = glm::rotate<float>(direction, M_PI / 2);

			createDot(pos, dir, diameter * 0.66f);
			createDot(pos, - dir, diameter * 0.66f);
		}
	};

	return dot;
}

void EntityCreationApp::mouseDown(MouseEvent event)
{
	// Create an entity that tracks the mouse.
	auto mouse_entity = entities.create();
	mouse_entity.assign<Position>(event.getPos());
	mouse_entity.assign<Circle>(49.0f, Color::gray(0.5f));
	// The DragTracker behavior will destroy its entity when the drag ends.
	assignBehavior<DragTracker>(mouse_entity);
}

void EntityCreationApp::mouseDrag( MouseEvent event )
{
	// Keep track of the mouse position.
	// This could be better done in a behavior or component (say, when DragTracker is destroyed)
	// Dear reader: try modifying the DragTracker behavior so it calls a function on destruction.
	// Use that function to create a dot where the tracker was last seen.
	mouse_prev = mouse;
	mouse = event.getPos();
}

void EntityCreationApp::mouseUp(MouseEvent event)
{
	mouse = event.getPos();
	auto delta = mouse - mouse_prev;
	auto len = length(delta);
	if (length(delta) > std::numeric_limits<float>::epsilon()) {
		delta /= len;
	}
	else {
		delta = vec2(1, 0);
	}
	createDot(mouse, delta, 49.0f);
}

void EntityCreationApp::keyDown(KeyEvent event)
{
	if (event.getCode() == KeyEvent::KEY_c) {
    do_clear = ! do_clear;
	}
}

void EntityCreationApp::update()
{
	auto dt = 1.0 / 60.0;

	// Update all of our systems.
	systems.update<ExpiresSystem>(dt);
	systems.update<BehaviorSystem>(dt);

	// Apply functions to the entities. See Systems.h for these function definitions.
	slowDownWithAge(entities);
	applyMotion(entities, dt);
	borderWrap(entities);

	if (! do_clear) {
    fadeWithAge(entities);
	}
}

void EntityCreationApp::draw()
{
	if (do_clear) {
		gl::clear( Color( 0, 0, 0 ) );
	}
	gl::disableDepthRead();
	gl::setMatricesWindowPersp(getWindowSize());

	// Why is this cooler than just calling draw on each item?
	// We could do smart things based on what we know about our world and have a clear function call order.

	entityx::ComponentHandle<Circle>		ch;
	entityx::ComponentHandle<Position>	ph;

	gl::ScopedColor color(Color::white());
	for (auto __unused e : entities.entities_with_components(ch, ph)) {
		gl::color(ch->color);
		gl::drawSolidCircle(ph->position, ch->radius());
	}
}

CINDER_APP( EntityCreationApp, RendererGl(RendererGl::Options().msaa(4)) )
<commit_msg>Reorganize comment about drawing.<commit_after>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"

#include "entityx/System.h"
#include "Transform.h"
#include "cinder/Perlin.h"
#include "cinder/Rand.h"

#include "Components.h"
#include "Systems.h"
#include "Expires.h"
#include "ExpiresSystem.h"
#include "Behavior.h"
#include "BehaviorSystem.h"
#include "Behaviors.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace soso;

// Wraps positions to stay within a rectangle.
const auto borderWrap = createWrapFunction(Rectf(0, 0, 640, 480));

///
/// EntityCreationApp demonstrates creation of entities and some of the uses of components and systems.
///
class EntityCreationApp : public App {
public:
	EntityCreationApp();

	void setup() override;
	void mouseDown(MouseEvent event) override;
	void mouseDrag(MouseEvent event) override;
	void mouseUp(MouseEvent event) override;
	void keyDown(KeyEvent event) override;
	void update() override;
	void draw() override;

	entityx::Entity createDot(const ci::vec2 &position, const ci::vec2 &direction, float diameter);

private:
	entityx::EventManager	 events;
	entityx::EntityManager entities;
	entityx::SystemManager systems;
	uint32_t							 num_dots = 0;
	static const uint32_t	 max_dots = 1024;

	ci::vec2							 mouse, mouse_prev;
	bool									 do_clear = true;
};

// Initialize our EntityManager and SystemManager to know about events and each other.

EntityCreationApp::EntityCreationApp()
: entities(events),
	systems(entities, events)
{}

void EntityCreationApp::setup()
{
	// Create our systems for controlling entity behavior.
	// We also use free functions for entity behavior, which don't need to be instantiated.
	systems.add<ExpiresSystem>();
	systems.add<BehaviorSystem>(entities);
	systems.configure();

	// Create an initial dot on screen
	createDot(getWindowCenter(), vec2(1, 0), 36.0f);
}

entityx::Entity EntityCreationApp::createDot(const ci::vec2 &position, const ci::vec2 &direction, float diameter)
{
	// Keep track of the number of dots created so we don't have way too many.
	if (num_dots > max_dots) {
		return entityx::Entity(); // return an invalid entity
	}
	num_dots += 1;

	// Create an entity, managed by `entities`.
	auto dot = entities.create();
	// Assign the components we care about
	dot.assign<Position>(position);
	dot.assign<Circle>(diameter);
	dot.assign<Motion>(direction, 250.0f);
	// Assign an Expires component and store a handle to it in `exp`
	auto exp = dot.assign<Expires>(randFloat(4.0f, 6.0f));

	// Set a function to call when the Expires component runs out of time//
	// Called last_wish, since it happens just before the entity is destroyed.
	exp->last_wish = [this, diameter, direction] (entityx::Entity e) {
		num_dots -= 1;

		if (diameter > 8.0f) {
			// If we weren't too small, create some smaller dots where we were destroyed.
			auto pos = e.component<Position>()->position;
			auto dir = glm::rotate<float>(direction, M_PI / 2);

			createDot(pos, dir, diameter * 0.66f);
			createDot(pos, - dir, diameter * 0.66f);
		}
	};

	return dot;
}

void EntityCreationApp::mouseDown(MouseEvent event)
{
	// Create an entity that tracks the mouse.
	auto mouse_entity = entities.create();
	mouse_entity.assign<Position>(event.getPos());
	mouse_entity.assign<Circle>(49.0f, Color::gray(0.5f));
	// The DragTracker behavior will destroy its entity when the drag ends.
	assignBehavior<DragTracker>(mouse_entity);
}

void EntityCreationApp::mouseDrag( MouseEvent event )
{
	// Keep track of the mouse position.
	// This could be better done in a behavior or component (say, when DragTracker is destroyed)
	// Dear reader: try modifying the DragTracker behavior so it calls a function on destruction.
	// Use that function to create a dot where the tracker was last seen.
	mouse_prev = mouse;
	mouse = event.getPos();
}

void EntityCreationApp::mouseUp(MouseEvent event)
{
	mouse = event.getPos();
	auto delta = mouse - mouse_prev;
	auto len = length(delta);
	if (length(delta) > std::numeric_limits<float>::epsilon()) {
		delta /= len;
	}
	else {
		delta = vec2(1, 0);
	}
	createDot(mouse, delta, 49.0f);
}

void EntityCreationApp::keyDown(KeyEvent event)
{
	if (event.getCode() == KeyEvent::KEY_c) {
    do_clear = ! do_clear;
	}
}

void EntityCreationApp::update()
{
	auto dt = 1.0 / 60.0;

	// Update all of our systems.
	systems.update<ExpiresSystem>(dt);
	systems.update<BehaviorSystem>(dt);

	// Apply functions to the entities. See Systems.h for these function definitions.
	slowDownWithAge(entities);
	applyMotion(entities, dt);
	borderWrap(entities);

	if (! do_clear) {
    fadeWithAge(entities);
	}
}

void EntityCreationApp::draw()
{
	if (do_clear) {
		gl::clear( Color( 0, 0, 0 ) );
	}
	gl::disableDepthRead();
	gl::setMatricesWindowPersp(getWindowSize());

	// Below, we loop through and draw every entity that has both a position and a circle component.
	// This is a bit more interesting than having a custom draw function for every entity,
	// because it allows us to do smart things based on what we know about our world.
	entityx::ComponentHandle<Circle>		ch;
	entityx::ComponentHandle<Position>	ph;

	gl::ScopedColor color(Color::white());
	for (auto __unused e : entities.entities_with_components(ch, ph)) {
		gl::color(ch->color);
		gl::drawSolidCircle(ph->position, ch->radius());
	}
}

CINDER_APP( EntityCreationApp, RendererGl(RendererGl::Options().msaa(4)) )
<|endoftext|>


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

#include "scanner/evaluators/tracker/tracker_evaluator.h"
#include "scanner/evaluators/serialize.h"

#include "scanner/util/common.h"
#include "scanner/util/util.h"

#include "struck/Tracker.h"
#include "struck/Config.h"

#ifdef HAVE_CUDA
#include "scanner/util/cuda.h"
#endif

#include <cmath>

namespace scanner {

TrackerEvaluator::TrackerEvaluator(const EvaluatorConfig& config,
                                   DeviceType device_type,
                                   i32 device_id,
                                   i32 warmup_count)
    : config_(config),
      device_type_(device_type),
      device_id_(device_id),
      warmup_count_(warmup_count)
{
  if (device_type_ == DeviceType::GPU) {
    LOG(FATAL) << "GPU tracker support not implemented yet";
  }
}

void TrackerEvaluator::configure(const VideoMetadata& metadata) {
  LOG(INFO) << "Tracker configure";
  metadata_ = metadata;
}

void TrackerEvaluator::reset() {
  LOG(INFO) << "Tracker reset";
  tracks_.clear();
}

void TrackerEvaluator::evaluate(
    const std::vector<std::vector<u8 *>> &input_buffers,
    const std::vector<std::vector<size_t>> &input_sizes,
    std::vector<std::vector<u8 *>> &output_buffers,
    std::vector<std::vector<size_t>> &output_sizes) {
  assert(input_buffers.size() >= 2);

  i32 input_count = input_buffers[0].size();
  LOG(INFO) << "Tracker evaluate on " << input_count << " inputs";

  for (i32 b = 0; b < input_count; ++b) {
    u8 *bbox_buffer = input_buffers[1][b];
    size_t num_bboxes = *((size_t *)bbox_buffer);
    bbox_buffer += sizeof(size_t);
    i32 bbox_size = *((i32 *)bbox_buffer);
    bbox_buffer += sizeof(i32);

    // Find all the boxes which overlap the existing tracked boxes and update
    // the tracked boxes confidence values to those as well as the time since
    // last being seen

    // For boxes which don't overlap existing ones, create a new track for them
    std::vector<BoundingBox> detected_bboxes;
    std::vector<BoundingBox> new_detected_bboxes;
    for (size_t i = 0; i < num_bboxes; ++i) {
      BoundingBox box;
      box.ParseFromArray(bbox_buffer, bbox_size);
      bbox_buffer += bbox_size;

      i32 overlap_idx = -1;
      for (size_t j = 0; j < tracks_.size(); ++j) {
        auto& tracked_bbox = tracks_[j].box;
        if (iou(box, tracked_bbox) > IOU_THRESHOLD) {
          overlap_idx = j;
          break;
        }
      }
      if (overlap_idx != -1) {
        // Overlap with existing box
        tracks_[overlap_idx].box = box;
        tracks_[overlap_idx].frames_since_last_detection = 0;
      } else {
        // New box
        new_detected_bboxes.push_back(box);
      }
      detected_bboxes.push_back(box);
    }

    // Check if any tracks have been many frames without being redetected and
    // remove them
    for (i32 i = 0; i < (i32)tracks_.size(); ++i) {
      if (frames_since_last_detection_[i] > UNDETECTED_WINDOW) {
        tracked_bboxes_.erase(tracked_bboxes_.begin() + i);
        frames_since_last_detection_.erase(
            frames_since_last_detection_.begin() + i);
        trackers_.erase(trackers_.begin() + i);
        tracker_configs_.erase(tracker_configs_.begin() + i);
        tracker_ids_.erase(tracker_ids_.begin() + i);
        i--;
      }
    }

    // Perform tracking for all existing tracks that we have
    std::vector<BoundingBox> generated_bboxes;
    {
      u8 *buffer = input_buffers[0][b];
      cv::Mat frame(metadata_.height(), metadata_.width(), CV_8UC3, buffer);
      for (i32 i = 0; i < (i32)tracks_.size(); ++i) {
        auto& track = tracks_[i];
        auto& tracker = track.tracker;
        tracker->Track(frame);
        const struck::FloatRect &tracked_bbox = tracker->GetBB();
        f64 score = tracker->GetScore();

        if (score < TRACK_SCORE_THRESHOLD) {
          tracks_.erase(tracks_.begin() + i);
          i--;
        } else {
          BoundingBox box;
          box.set_x1(tracked_bbox.XMin());
          box.set_y1(tracked_bbox.YMin());
          box.set_x2(tracked_bbox.XMax());
          box.set_y2(tracked_bbox.YMax());
          box.set_score(tracked_bboxes_[i].score());
          box.set_track_id(tracker_ids_[i]);
          box.set_track_score(score);
          generated_bboxes.push_back(box);

          track.frames_since_last_detection_++;
        }
      }
    }

    // Add new detected bounding boxes to the fold
    for (BoundingBox& box : new_detected_bboxes) {
      tracks_.resize(tracks_.size() + 1);
      Track& track = tracks_.back();
      //i32 tracker_id = next_tracker_id_++;
      i32 tracker_id = unif(gen);
      track.id = tracker_id;
      track.config.reset(new struck::Config{});
      struck::Config &config = *track.config.get();;
      config.frameWidth = metadata_.width();
      config.frameHeight = metadata_.height();
      struck::Config::FeatureKernelPair fkp;
      fkp.feature = struck::Config::kFeatureTypeHaar;
      fkp.kernel = struck::Config::kKernelTypeLinear;
      config.features.push_back(fkp);
      track.tracker = new struck::Tracker(config);

      u8 *buffer = input_buffers[0][b];
      cv::Mat frame(metadata_.height(), metadata_.width(), CV_8UC3, buffer);
      struck::FloatRect r(box.x1(), box.y1(), box.x2() - box.x1(),
                          box.y2() - box.y1());
      track.tracker->Initialise(frame, r);

      box.set_track_id(track.id);
      track.frames_since_last_detection = 0;

      generated_bboxes.push_back(box);
    }

    {
      size_t size;
      u8 *buffer;

      serialize_bbox_vector(detected_bboxes, buffer, size);
      output_buffers[1].push_back(buffer);
      output_sizes[1].push_back(size);

      serialize_bbox_vector(generated_bboxes, buffer, size);
      output_buffers[2].push_back(buffer);
      output_sizes[2].push_back(size);
    }
  }

  u8 *buffer = nullptr;
  for (i32 b = 0; b < input_count; ++b) {
    size_t size = input_sizes[0][b];
    if (device_type_ == DeviceType::GPU) {
#ifdef HAVE_CUDA
      cudaMalloc((void **)&buffer, size);
      cudaMemcpy(buffer, input_buffers[0][b], size, cudaMemcpyDefault);
#else
      LOG(FATAL) << "Not built with CUDA support.";
#endif
    } else {
      buffer = new u8[size];
      memcpy(buffer, input_buffers[0][b], size);
    }
    output_buffers[0].push_back(buffer);
    output_sizes[0].push_back(size);
  }
}

float TrackerEvaluator::iou(const BoundingBox& bl, const BoundingBox& br) {
  float x1 = std::max(bl.x1(), br.x1());
  float y1 = std::max(bl.y1(), br.y1());
  float x2 = std::min(bl.x2(), br.x2());
  float y2 = std::min(bl.y2(), br.y2());

  float bl_width = bl.x2() - bl.x1();
  float bl_height = bl.y2() - bl.y1();
  float br_width = br.x2() - br.x1();
  float br_height= br.y2() - br.y1();
  if (x1 >= x2 || y1 >= y2) { return 0.0; }
  float intersection = (y2 - y1) * (x2 - x1);
  float _union = (bl_width * bl_height) + (br_width * br_height) - intersection;
  float iou = intersection / _union;
  return std::isnan(iou) ? 0.0 : iou;
}

TrackerEvaluatorFactory::TrackerEvaluatorFactory(DeviceType device_type,
                                                 i32 warmup_count)
    : device_type_(device_type), warmup_count_(warmup_count) {
  if (device_type_ == DeviceType::GPU) {
    LOG(FATAL) << "GPU tracker support not implemented yet";
  }
}

EvaluatorCapabilities TrackerEvaluatorFactory::get_capabilities() {
  EvaluatorCapabilities caps;
  caps.device_type = device_type_;
  caps.max_devices = 1;
  caps.warmup_size = warmup_count_;
  return caps;
}

std::vector<std::string> TrackerEvaluatorFactory::get_output_names() {
  return {"image", "before_bboxes", "after_bboxes"};
}

Evaluator *
TrackerEvaluatorFactory::new_evaluator(const EvaluatorConfig &config) {
  return new TrackerEvaluator(config, device_type_, 0, warmup_count_);
}
}
<commit_msg>Fix tracker compile errors<commit_after>/* Copyright 2016 Carnegie Mellon University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "scanner/evaluators/tracker/tracker_evaluator.h"
#include "scanner/evaluators/serialize.h"

#include "scanner/util/common.h"
#include "scanner/util/util.h"

#include "struck/Tracker.h"
#include "struck/Config.h"

#ifdef HAVE_CUDA
#include "scanner/util/cuda.h"
#endif

#include <cmath>

namespace scanner {

TrackerEvaluator::TrackerEvaluator(const EvaluatorConfig& config,
                                   DeviceType device_type,
                                   i32 device_id,
                                   i32 warmup_count)
    : config_(config),
      device_type_(device_type),
      device_id_(device_id),
      warmup_count_(warmup_count)
{
  if (device_type_ == DeviceType::GPU) {
    LOG(FATAL) << "GPU tracker support not implemented yet";
  }
}

void TrackerEvaluator::configure(const VideoMetadata& metadata) {
  LOG(INFO) << "Tracker configure";
  metadata_ = metadata;
}

void TrackerEvaluator::reset() {
  LOG(INFO) << "Tracker reset";
  tracks_.clear();
}

void TrackerEvaluator::evaluate(
    const std::vector<std::vector<u8 *>> &input_buffers,
    const std::vector<std::vector<size_t>> &input_sizes,
    std::vector<std::vector<u8 *>> &output_buffers,
    std::vector<std::vector<size_t>> &output_sizes) {
  assert(input_buffers.size() >= 2);

  i32 input_count = input_buffers[0].size();
  LOG(INFO) << "Tracker evaluate on " << input_count << " inputs";

  for (i32 b = 0; b < input_count; ++b) {
    u8 *bbox_buffer = input_buffers[1][b];
    size_t num_bboxes = *((size_t *)bbox_buffer);
    bbox_buffer += sizeof(size_t);
    i32 bbox_size = *((i32 *)bbox_buffer);
    bbox_buffer += sizeof(i32);

    // Find all the boxes which overlap the existing tracked boxes and update
    // the tracked boxes confidence values to those as well as the time since
    // last being seen

    // For boxes which don't overlap existing ones, create a new track for them
    std::vector<BoundingBox> detected_bboxes;
    std::vector<BoundingBox> new_detected_bboxes;
    for (size_t i = 0; i < num_bboxes; ++i) {
      BoundingBox box;
      box.ParseFromArray(bbox_buffer, bbox_size);
      bbox_buffer += bbox_size;

      i32 overlap_idx = -1;
      for (size_t j = 0; j < tracks_.size(); ++j) {
        auto& tracked_bbox = tracks_[j].box;
        if (iou(box, tracked_bbox) > IOU_THRESHOLD) {
          overlap_idx = j;
          break;
        }
      }
      if (overlap_idx != -1) {
        // Overlap with existing box
        tracks_[overlap_idx].box = box;
        tracks_[overlap_idx].frames_since_last_detection = 0;
      } else {
        // New box
        new_detected_bboxes.push_back(box);
      }
      detected_bboxes.push_back(box);
    }

    // Perform tracking for all existing tracks that we have
    std::vector<BoundingBox> generated_bboxes;
    {
      u8 *buffer = input_buffers[0][b];
      cv::Mat frame(metadata_.height(), metadata_.width(), CV_8UC3, buffer);
      for (i32 i = 0; i < (i32)tracks_.size(); ++i) {
        auto& track = tracks_[i];
        auto& tracker = track.tracker;
        tracker->Track(frame);
        const struck::FloatRect &tracked_bbox = tracker->GetBB();
        f64 score = tracker->GetScore();

        if (score < TRACK_SCORE_THRESHOLD) {
          tracks_.erase(tracks_.begin() + i);
          i--;
        } else {
          BoundingBox box;
          box.set_x1(tracked_bbox.XMin());
          box.set_y1(tracked_bbox.YMin());
          box.set_x2(tracked_bbox.XMax());
          box.set_y2(tracked_bbox.YMax());
          box.set_score(track.box.score());
          box.set_track_id(track.id);
          box.set_track_score(score);
          generated_bboxes.push_back(box);

          track.frames_since_last_detection++;
        }
      }
    }

    // Add new detected bounding boxes to the fold
    for (BoundingBox& box : new_detected_bboxes) {
      tracks_.resize(tracks_.size() + 1);
      Track& track = tracks_.back();
      //i32 tracker_id = next_tracker_id_++;
      i32 tracker_id = unif(gen);
      track.id = tracker_id;
      track.config.reset(new struck::Config{});
      struck::Config &config = *track.config.get();;
      config.frameWidth = metadata_.width();
      config.frameHeight = metadata_.height();
      struck::Config::FeatureKernelPair fkp;
      fkp.feature = struck::Config::kFeatureTypeHaar;
      fkp.kernel = struck::Config::kKernelTypeLinear;
      config.features.push_back(fkp);
      track.tracker.reset(new struck::Tracker(config));

      u8 *buffer = input_buffers[0][b];
      cv::Mat frame(metadata_.height(), metadata_.width(), CV_8UC3, buffer);
      struck::FloatRect r(box.x1(), box.y1(), box.x2() - box.x1(),
                          box.y2() - box.y1());
      track.tracker->Initialise(frame, r);

      box.set_track_id(track.id);
      track.frames_since_last_detection = 0;

      generated_bboxes.push_back(box);
    }

    {
      size_t size;
      u8 *buffer;

      serialize_bbox_vector(detected_bboxes, buffer, size);
      output_buffers[1].push_back(buffer);
      output_sizes[1].push_back(size);

      serialize_bbox_vector(generated_bboxes, buffer, size);
      output_buffers[2].push_back(buffer);
      output_sizes[2].push_back(size);
    }
  }

  u8 *buffer = nullptr;
  for (i32 b = 0; b < input_count; ++b) {
    size_t size = input_sizes[0][b];
    if (device_type_ == DeviceType::GPU) {
#ifdef HAVE_CUDA
      cudaMalloc((void **)&buffer, size);
      cudaMemcpy(buffer, input_buffers[0][b], size, cudaMemcpyDefault);
#else
      LOG(FATAL) << "Not built with CUDA support.";
#endif
    } else {
      buffer = new u8[size];
      memcpy(buffer, input_buffers[0][b], size);
    }
    output_buffers[0].push_back(buffer);
    output_sizes[0].push_back(size);
  }
}

float TrackerEvaluator::iou(const BoundingBox& bl, const BoundingBox& br) {
  float x1 = std::max(bl.x1(), br.x1());
  float y1 = std::max(bl.y1(), br.y1());
  float x2 = std::min(bl.x2(), br.x2());
  float y2 = std::min(bl.y2(), br.y2());

  float bl_width = bl.x2() - bl.x1();
  float bl_height = bl.y2() - bl.y1();
  float br_width = br.x2() - br.x1();
  float br_height= br.y2() - br.y1();
  if (x1 >= x2 || y1 >= y2) { return 0.0; }
  float intersection = (y2 - y1) * (x2 - x1);
  float _union = (bl_width * bl_height) + (br_width * br_height) - intersection;
  float iou = intersection / _union;
  return std::isnan(iou) ? 0.0 : iou;
}

TrackerEvaluatorFactory::TrackerEvaluatorFactory(DeviceType device_type,
                                                 i32 warmup_count)
    : device_type_(device_type), warmup_count_(warmup_count) {
  if (device_type_ == DeviceType::GPU) {
    LOG(FATAL) << "GPU tracker support not implemented yet";
  }
}

EvaluatorCapabilities TrackerEvaluatorFactory::get_capabilities() {
  EvaluatorCapabilities caps;
  caps.device_type = device_type_;
  caps.max_devices = 1;
  caps.warmup_size = warmup_count_;
  return caps;
}

std::vector<std::string> TrackerEvaluatorFactory::get_output_names() {
  return {"image", "before_bboxes", "after_bboxes"};
}

Evaluator *
TrackerEvaluatorFactory::new_evaluator(const EvaluatorConfig &config) {
  return new TrackerEvaluator(config, device_type_, 0, warmup_count_);
}
}
<|endoftext|>