<commit_before>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// 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 <algorithm>
#include <fstream>
#include <iostream>
#include <string>

#include "paddle/fluid/framework/op_info.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/variable.h"
#include "paddle/fluid/pybind/pybind.h"
#include "paddle/fluid/string/string_helper.h"

std::map<std::string, std::set<std::string>> op_ins_map = {
    {"layer_norm", {"X", "Scale", "Bias"}},
    {"gru_unit", {"Input", "HiddenPrev", "Weight", "Bias"}},
    {"label_smooth", {"X", "PriorDist"}},
    {"assign", {"X"}},
};
std::map<std::string, std::set<std::string>> op_passing_out_map = {
    {"sgd", {"ParamOut"}},
    {"adam",
     {"ParamOut", "Moment1Out", "Moment2Out", "Beta1PowOut", "Beta2PowOut"}},
    {"momentum", {"ParamOut", "VelocityOut"}},
    {"batch_norm", {"MeanOut", "VarianceOut"}},
    {"accuracy", {"Correct", "Total"}},
    {"fill_constant", {"Out"}},
    {"matmul", {"Out"}}};

// clang-format off
const char* OUT_INITIALIZER_TEMPLATE =
    R"({"%s", {std::shared_ptr<imperative::VarBase>(new imperative::VarBase(tracer->GenerateUniqueName()))}})";
const char* OUT_DUPLICABLE_INITIALIZER_TEMPLATE = R"({"%s", ConstructDuplicableOutput(%s)})";

const char* INPUT_INITIALIZER_TEMPLATE = R"({"%s", {%s}})";
const char* INPUT_LIST_INITIALIZER_TEMPLATE = R"({"%s", %s})";
const char* INPUT_INITIALIZER_TEMPLATE_WITH_NULL = R"(
    if (%s != nullptr) {
      ins["%s"] = {%s};
    }
)";
const char* INPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST = R"(
    if (%s != nullptr) {
      ins["%s"] = %s;
    }
)";

// if inputs is list, no need {}
const char* ARG_OUT_NUM = R"(%sNum)";
const char* ARG_OUT_NUM_TYPE = R"(size_t )";

const char* VAR_TYPE = R"(std::shared_ptr<imperative::VarBase>)";
const char* VAR_LIST_TYPE = R"(std::vector<std::shared_ptr<imperative::VarBase>>)";
const char* ARG_TEMPLATE = R"(const %s& %s)";

const char* RETURN_TUPLE_TYPE = R"(std::tuple<%s>)";
const char* RETURN_TYPE = R"(%s)";
const char* RETURN_TUPLE_TEMPLATE = R"(std::make_tuple(%s))";
const char* RETURN_LIST_TEMPLATE = R"(outs["%s"])";
const char* RETURN_TEMPLATE = R"(outs["%s"][0])";

const char* FUNCTION_ARGS = R"(%s, const py::args& args)";
const char* FUNCTION_ARGS_NO_INPUT = R"(const py::args& args)";

const char* OP_FUNCTION_TEMPLATE =
R"(
%s %s(%s)
{
  framework::AttributeMap attrs;
  ConstructAttrMapFromPyArgs(&attrs, args);
  {
    py::gil_scoped_release release;
    auto tracer = imperative::GetCurrentTracer();
    imperative::NameVarBaseMap outs = %s;
    imperative::NameVarBaseMap ins = %s;
    %s
    tracer->TraceOp("%s", ins, outs, attrs);
    return %s;
  }
})";

const char* PYBIND_ITEM_TEMPLATE = R"(  %s.def("%s", &%s);)";

// clang-format on
static inline bool FindInputInSpecialization(const std::string& op_type,
                                             const std::string& in_name) {
  return op_ins_map[op_type].count(in_name);
}

static inline bool FindOutoutInSpecialization(const std::string& op_type,
                                              const std::string& out_name) {
  return op_passing_out_map[op_type].count(out_name);
}

static std::tuple<std::vector<std::string>, std::vector<std::string>>
GenerateOpFunctions(const std::string& module_name) {
  auto& op_info_map = paddle::framework::OpInfoMap::Instance().map();

  std::vector<std::string> op_function_list, bind_function_list;
  auto& all_kernels = paddle::framework::OperatorWithKernel::AllOpKernels();

  for (auto& pair : op_info_map) {
    auto& op_info = pair.second;
    auto op_proto = op_info.proto_;
    if (op_proto == nullptr) {
      continue;
    }
    auto& op_type = op_proto->type();
    // Skip ooerator which is not inherit form OperatorWithKernel, like while,
    // since only OperatorWithKernel can run in dygraph mode.
    if (!all_kernels.count(op_type)) {
      continue;
    }
    std::string input_args = "";
    std::string ins_initializer = "{";
    std::string ins_initializer_with_null = "";
    std::string py_arg = "";
    for (auto& input : op_proto->inputs()) {
      auto& in_name = input.name();
      // skip those dispensable inputs, like ResidualData in conv2d
      if (input.dispensable() && !FindInputInSpecialization(op_type, in_name)) {
        continue;
      }
      const auto in_type = input.duplicable() ? VAR_LIST_TYPE : VAR_TYPE;
      auto input_arg = paddle::string::Sprintf(ARG_TEMPLATE, in_type, in_name);
      input_args += input_arg;
      input_args += ",";

      if (input.dispensable()) {
        const auto in_template = input.duplicable()
                                     ? INPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST
                                     : INPUT_INITIALIZER_TEMPLATE_WITH_NULL;
        ins_initializer_with_null +=
            paddle::string::Sprintf(in_template, in_name, in_name, in_name);
      } else {
        const auto in_template = input.duplicable()
                                     ? INPUT_LIST_INITIALIZER_TEMPLATE
                                     : INPUT_INITIALIZER_TEMPLATE;
        ins_initializer +=
            paddle::string::Sprintf(in_template, in_name, in_name);
        ins_initializer += ",";
      }
    }
    if (ins_initializer.back() == ',') {
      ins_initializer.pop_back();
    }
    ins_initializer += "}";

    if (input_args.back() == ',') {
      input_args.pop_back();
    }

    // Generate outs initializer
    std::string outs_initializer = "{";
    std::string return_type = "";
    std::string return_str = "";

    int outs_num = 0;
    for (auto& output : op_proto->outputs()) {
      if (output.dispensable()) {
        continue;
      }
      const auto out_type = output.duplicable() ? VAR_LIST_TYPE : VAR_TYPE;
      const auto return_template =
          output.duplicable() ? RETURN_LIST_TEMPLATE : RETURN_TEMPLATE;
      auto& out_name = output.name();
      std::string out_initializer_str;
      if (FindOutoutInSpecialization(op_type, out_name)) {
        if (input_args != "") {
          input_args += ",";
        }
        input_args += out_type;
        input_args += out_name;
        const auto out_template = output.duplicable()
                                      ? INPUT_LIST_INITIALIZER_TEMPLATE
                                      : INPUT_INITIALIZER_TEMPLATE;
        out_initializer_str +=
            paddle::string::Sprintf(out_template, out_name, out_name);
      } else {
        // There are few Operators that have duplicable output, like `Out` in
        // split op. We need to specify the number of variables for the
        // duplicable output, as the argument OutNum;
        if (output.duplicable()) {
          if (input_args != "") {
            input_args += ",";
          }
          auto out_num_str = paddle::string::Sprintf(ARG_OUT_NUM, out_name);
          input_args += ARG_OUT_NUM_TYPE;
          input_args += out_num_str;
          out_initializer_str = paddle::string::Sprintf(
              OUT_DUPLICABLE_INITIALIZER_TEMPLATE, out_name, out_num_str);
        } else {
          out_initializer_str =
              paddle::string::Sprintf(OUT_INITIALIZER_TEMPLATE, out_name);
        }
      }

      return_type += out_type;
      return_type += ",";
      return_str += paddle::string::Sprintf(return_template, out_name);
      return_str += ",";
      outs_num += 1;

      outs_initializer += out_initializer_str;
      outs_initializer += ",";
    }
    if (outs_initializer.back() == ',') {
      outs_initializer.pop_back();
      return_type.pop_back();
      return_str.pop_back();
    }
    outs_initializer += "}";
    if (outs_num == 0) {
      return_type = "void";
    }
    if (outs_num > 1) {
      return_str = paddle::string::Sprintf(RETURN_TUPLE_TEMPLATE, return_str);
      return_type = paddle::string::Sprintf(RETURN_TUPLE_TYPE, return_type);
    }
    std::string function_args = "";
    if (input_args == "") {
      function_args = FUNCTION_ARGS_NO_INPUT;
    } else {
      function_args = paddle::string::Sprintf(FUNCTION_ARGS, input_args);
    }

    std::string func_name = "imperative_" + op_type;
    // generate op funtcion body
    auto op_function_str = paddle::string::Sprintf(
        OP_FUNCTION_TEMPLATE, return_type, func_name, function_args,
        outs_initializer, ins_initializer, ins_initializer_with_null, op_type,
        return_str);

    // generate pybind item
    auto bind_function_str = paddle::string::Sprintf(
        PYBIND_ITEM_TEMPLATE, module_name, op_type, func_name);

    op_function_list.emplace_back(std::move(op_function_str));
    bind_function_list.emplace_back(std::move(bind_function_str));
  }
  return std::make_tuple(op_function_list, bind_function_list);
}

int main(int argc, char* argv[]) {
  if (argc != 2) {
    std::cerr << "argc must be 2" << std::endl;
    return -1;
  }

  std::vector<std::string> headers{"\"paddle/fluid/imperative/tracer.h\""};

  std::ofstream out(argv[1], std::ios::out);

  out << "#pragma once\n\n";

  for (auto& header : headers) {
    out << "#include  " + header + "\n";
  }

  auto op_funcs = GenerateOpFunctions("m");

  out << "namespace py = pybind11;"
      << "\n";
  out << "namespace paddle {\n"
      << "namespace pybind {\n";
  out << paddle::string::join_strings(std::get<0>(op_funcs), '\n');
  out << "\n\n";

  out << "inline void BindOpFunctions(pybind11::module *module) {\n"
      << "  auto m = module->def_submodule(\"ops\");\n\n";

  out << paddle::string::join_strings(std::get<1>(op_funcs), '\n');
  out << "\n";
  out << "}\n\n"
      << "} // namespace pybind\n"
      << "} // namespace paddle\n";

  out.close();
  return 0;
}
<commit_msg>specify outs, test=develop (#24537)<commit_after>// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// 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 <algorithm>
#include <fstream>
#include <iostream>
#include <string>

#include "paddle/fluid/framework/op_info.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/variable.h"
#include "paddle/fluid/pybind/pybind.h"
#include "paddle/fluid/string/string_helper.h"

// NOTE(zhiqiu): Commonly, the inputs in auto-generated OP function are
// determined by the OP`s proto automatically, i.e., all the inputs registered
// in OpMaker.
// However, some OPs have dispensable inputs, which means the input can
// be none for some conditions. It is discovered that most dispensable inputs
// is not used in imperative mode, so we drop those inputs when generating OP
// functions. While, for very few OPs, the dispensable inputs are used, we
// need to manually specify them in this map.
std::map<std::string, std::set<std::string>> op_ins_map = {
    {"layer_norm", {"X", "Scale", "Bias"}},
    {"gru_unit", {"Input", "HiddenPrev", "Weight", "Bias"}},
    {"label_smooth", {"X", "PriorDist"}},
    {"assign", {"X"}},
    {"fake_quantize_dequantize_moving_average_abs_max",
     {"X", "InScale", "InAccum", "InState"}},
};

// NOTE(zhiqiu): Like op_ins_map.
// Commonly, the outputs in auto-generated OP function are determined by the
// OP`s proto automatically, i.e., all the outputs registered in OpMaker.
// However, some OPs have dispensable outputs, which means the output can
// be none for some conditions. It is discovered that most dispensable outputs
// is not used in imperative mode, so we drop those outputs when generating OP
// functions. While, for very few OPs, the dispensable outputs are used, we
// need to manually specify them in this map.
std::map<std::string, std::set<std::string>> op_outs_map = {
    {"fake_quantize_dequantize_moving_average_abs_max",
     {"Out", "OutScale", "OutAccum", "OutState"}},
};

// NOTE(zhiqiu): Commonly, the outputs in auto-generated OP function are
// generated in C++ automatically.
// However, some OPs need to pass the outputs from Python instead of generating
// them in C++. There are mainly 2 reasons for that,
// (1) Optimizer OPs need to update the input param in-place, like sgd.
//     So they need to pass the output which is same as input param.
// (2) Very few python APIs has out in their arguments, like fill_constant.
//     So they need to pass the python output to C++.
//     Actually, this is not a good design, since it may break the SSA graph,
//     especially in declarative mode.
// For those OPs, we need to manually specify the outs need to pass in this map.
std::map<std::string, std::set<std::string>> op_passing_outs_map = {
    {"sgd", {"ParamOut"}},
    {"adam",
     {"ParamOut", "Moment1Out", "Moment2Out", "Beta1PowOut", "Beta2PowOut"}},
    {"momentum", {"ParamOut", "VelocityOut"}},
    {"batch_norm", {"MeanOut", "VarianceOut"}},
    {"accuracy", {"Correct", "Total"}},
    {"fill_constant", {"Out"}},
    {"matmul", {"Out"}},
    {"fake_quantize_dequantize_moving_average_abs_max",
     {"OutScale", "OutAccum", "OutState"}},
};

// clang-format off
const char* OUT_INITIALIZER_TEMPLATE =
    R"({"%s", {std::shared_ptr<imperative::VarBase>(new imperative::VarBase(tracer->GenerateUniqueName()))}})";
const char* OUT_DUPLICABLE_INITIALIZER_TEMPLATE = R"({"%s", ConstructDuplicableOutput(%s)})";

const char* INPUT_INITIALIZER_TEMPLATE = R"({"%s", {%s}})";
const char* INPUT_LIST_INITIALIZER_TEMPLATE = R"({"%s", %s})";

const char* INPUT_INITIALIZER_TEMPLATE_WITH_NULL = R"(
    if (%s != nullptr) {
      ins["%s"] = {%s};
    }
)";

const char* INPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST = R"(
    if (%s.size() != 0) {
      ins["%s"] = %s;
    }
)";

const char* OUTPUT_INITIALIZER_TEMPLATE_WITH_NULL = R"(
    if (%s != nullptr) {
      outs["%s"] = {%s};
    }
)";

const char* OUTPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST = R"(
    if (%s.size() != 0) {
      outs["%s"] = %s;
    }
)";
// if inputs is list, no need {}
const char* ARG_OUT_NUM = R"(%sNum)";
const char* ARG_OUT_NUM_TYPE = R"(size_t )";

const char* VAR_TYPE = R"(std::shared_ptr<imperative::VarBase>)";
const char* VAR_LIST_TYPE = R"(std::vector<std::shared_ptr<imperative::VarBase>>)";
const char* ARG_TEMPLATE = R"(const %s& %s)";

const char* RETURN_TUPLE_TYPE = R"(std::tuple<%s>)";
const char* RETURN_TYPE = R"(%s)";
const char* RETURN_TUPLE_TEMPLATE = R"(std::make_tuple(%s))";
const char* RETURN_LIST_TEMPLATE = R"(outs["%s"])";
const char* RETURN_TEMPLATE = R"(outs["%s"][0])";

const char* FUNCTION_ARGS = R"(%s, const py::args& args)";
const char* FUNCTION_ARGS_NO_INPUT = R"(const py::args& args)";

const char* OP_FUNCTION_TEMPLATE =
R"(
%s %s(%s)
{
  framework::AttributeMap attrs;
  ConstructAttrMapFromPyArgs(&attrs, args);
  {
    py::gil_scoped_release release;
    auto tracer = imperative::GetCurrentTracer();
    imperative::NameVarBaseMap outs = %s;
    imperative::NameVarBaseMap ins = %s;
    %s
    tracer->TraceOp("%s", ins, outs, attrs);
    return %s;
  }
})";

const char* PYBIND_ITEM_TEMPLATE = R"(  %s.def("%s", &%s);)";

// clang-format on
static inline bool FindInsMap(const std::string& op_type,
                              const std::string& in_name) {
  return op_ins_map[op_type].count(in_name);
}

static inline bool FindOutsMap(const std::string& op_type,
                               const std::string& out_name) {
  return op_outs_map[op_type].count(out_name);
}

static inline bool FindPassingOutsMap(const std::string& op_type,
                                      const std::string& out_name) {
  return op_passing_outs_map[op_type].count(out_name);
}

static std::tuple<std::vector<std::string>, std::vector<std::string>>
GenerateOpFunctions(const std::string& module_name) {
  auto& op_info_map = paddle::framework::OpInfoMap::Instance().map();

  std::vector<std::string> op_function_list, bind_function_list;
  auto& all_kernels = paddle::framework::OperatorWithKernel::AllOpKernels();

  for (auto& pair : op_info_map) {
    auto& op_info = pair.second;
    auto op_proto = op_info.proto_;
    if (op_proto == nullptr) {
      continue;
    }
    auto& op_type = op_proto->type();
    // Skip ooerator which is not inherit form OperatorWithKernel, like while,
    // since only OperatorWithKernel can run in dygraph mode.
    if (!all_kernels.count(op_type)) {
      continue;
    }
    std::string input_args = "";
    std::string ins_initializer = "{";
    std::string ins_initializer_with_null = "";
    std::string py_arg = "";
    for (auto& input : op_proto->inputs()) {
      auto& in_name = input.name();
      // skip those dispensable inputs, like ResidualData in conv2d
      if (input.dispensable() && !FindInsMap(op_type, in_name)) {
        continue;
      }
      const auto in_type = input.duplicable() ? VAR_LIST_TYPE : VAR_TYPE;
      auto input_arg = paddle::string::Sprintf(ARG_TEMPLATE, in_type, in_name);
      input_args += input_arg;
      input_args += ",";

      if (input.dispensable()) {
        const auto in_template = input.duplicable()
                                     ? INPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST
                                     : INPUT_INITIALIZER_TEMPLATE_WITH_NULL;
        ins_initializer_with_null +=
            paddle::string::Sprintf(in_template, in_name, in_name, in_name);
      } else {
        const auto in_template = input.duplicable()
                                     ? INPUT_LIST_INITIALIZER_TEMPLATE
                                     : INPUT_INITIALIZER_TEMPLATE;
        ins_initializer +=
            paddle::string::Sprintf(in_template, in_name, in_name);
        ins_initializer += ",";
      }
    }
    if (ins_initializer.back() == ',') {
      ins_initializer.pop_back();
    }
    ins_initializer += "}";

    if (input_args.back() == ',') {
      input_args.pop_back();
    }

    // Generate outs initializer
    std::string outs_initializer = "{";
    std::string outs_initializer_with_null = "";
    std::string return_type = "";
    std::string return_str = "";

    int outs_num = 0;
    for (auto& output : op_proto->outputs()) {
      auto& out_name = output.name();
      // skip those dispensable oututs
      if (output.dispensable() && !FindOutsMap(op_type, out_name)) {
        continue;
      }
      const auto out_type = output.duplicable() ? VAR_LIST_TYPE : VAR_TYPE;
      const auto return_template =
          output.duplicable() ? RETURN_LIST_TEMPLATE : RETURN_TEMPLATE;
      if (FindPassingOutsMap(op_type, out_name)) {
        if (input_args != "") {
          input_args += ",";
        }
        input_args += out_type;
        input_args += out_name;

        if (output.dispensable()) {
          const auto out_template =
              output.duplicable() ? OUTPUT_INITIALIZER_TEMPLATE_WITH_NULL_LIST
                                  : OUTPUT_INITIALIZER_TEMPLATE_WITH_NULL;
          outs_initializer_with_null += paddle::string::Sprintf(
              out_template, out_name, out_name, out_name);
        } else {
          const auto out_template = output.duplicable()
                                        ? INPUT_LIST_INITIALIZER_TEMPLATE
                                        : INPUT_INITIALIZER_TEMPLATE;
          outs_initializer +=
              paddle::string::Sprintf(out_template, out_name, out_name);
          outs_initializer += ",";
        }
      } else {
        // There are few Operators that have duplicable output, like `Out` in
        // split op. We need to specify the number of variables for the
        // duplicable output, as the argument OutNum;
        if (output.duplicable()) {
          if (input_args != "") {
            input_args += ",";
          }
          auto out_num_str = paddle::string::Sprintf(ARG_OUT_NUM, out_name);
          input_args += ARG_OUT_NUM_TYPE;
          input_args += out_num_str;
          outs_initializer += paddle::string::Sprintf(
              OUT_DUPLICABLE_INITIALIZER_TEMPLATE, out_name, out_num_str);
        } else {
          outs_initializer +=
              paddle::string::Sprintf(OUT_INITIALIZER_TEMPLATE, out_name);
        }
        outs_initializer += ",";
      }

      return_type += out_type;
      return_type += ",";
      return_str += paddle::string::Sprintf(return_template, out_name);
      return_str += ",";
      outs_num += 1;
    }
    if (outs_initializer.back() == ',') {
      outs_initializer.pop_back();
      return_type.pop_back();
      return_str.pop_back();
    }
    outs_initializer += "}";
    if (outs_num == 0) {
      return_type = "void";
    }
    if (outs_num > 1) {
      return_str = paddle::string::Sprintf(RETURN_TUPLE_TEMPLATE, return_str);
      return_type = paddle::string::Sprintf(RETURN_TUPLE_TYPE, return_type);
    }
    std::string function_args = "";
    if (input_args == "") {
      function_args = FUNCTION_ARGS_NO_INPUT;
    } else {
      function_args = paddle::string::Sprintf(FUNCTION_ARGS, input_args);
    }

    std::string func_name = "imperative_" + op_type;
    // generate op funtcion body
    auto op_function_str = paddle::string::Sprintf(
        OP_FUNCTION_TEMPLATE, return_type, func_name, function_args,
        outs_initializer, ins_initializer,
        ins_initializer_with_null + outs_initializer_with_null, op_type,
        return_str);

    // generate pybind item
    auto bind_function_str = paddle::string::Sprintf(
        PYBIND_ITEM_TEMPLATE, module_name, op_type, func_name);

    op_function_list.emplace_back(std::move(op_function_str));
    bind_function_list.emplace_back(std::move(bind_function_str));
  }
  return std::make_tuple(op_function_list, bind_function_list);
}

int main(int argc, char* argv[]) {
  if (argc != 2) {
    std::cerr << "argc must be 2" << std::endl;
    return -1;
  }

  std::vector<std::string> headers{"\"paddle/fluid/imperative/tracer.h\""};

  std::ofstream out(argv[1], std::ios::out);

  out << "#pragma once\n\n";

  for (auto& header : headers) {
    out << "#include  " + header + "\n";
  }

  auto op_funcs = GenerateOpFunctions("m");

  out << "namespace py = pybind11;"
      << "\n";
  out << "namespace paddle {\n"
      << "namespace pybind {\n";
  out << paddle::string::join_strings(std::get<0>(op_funcs), '\n');
  out << "\n\n";

  out << "inline void BindOpFunctions(pybind11::module *module) {\n"
      << "  auto m = module->def_submodule(\"ops\");\n\n";

  out << paddle::string::join_strings(std::get<1>(op_funcs), '\n');
  out << "\n";
  out << "}\n\n"
      << "} // namespace pybind\n"
      << "} // namespace paddle\n";

  out.close();
  return 0;
}
<|endoftext|>


<commit_before>// Filename: collisionHandlerPusher.cxx
// Created by:  drose (16Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "collisionHandlerPusher.h"
#include "collisionNode.h"
#include "collisionEntry.h"
#include "collisionPolygon.h"
#include "config_collide.h"
#include "dcast.h"

TypeHandle CollisionHandlerPusher::_type_handle;

///////////////////////////////////////////////////////////////////
//       Class : ShoveData
// Description : The ShoveData class is used within
//               CollisionHandlerPusher::handle_entries(), to track
//               multiple shoves onto a given collider.  It's not
//               exported outside this file.
////////////////////////////////////////////////////////////////////
class ShoveData {
public:
  LVector3f _vector;
  float _length;
  bool _valid;
  CollisionEntry *_entry;
};

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
CollisionHandlerPusher::
CollisionHandlerPusher() {
  _horizontal = true;
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
CollisionHandlerPusher::
~CollisionHandlerPusher() {
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::handle_entries
//       Access: Protected, Virtual
//  Description: Called by the parent class after all collisions have
//               been detected, this manages the various collisions
//               and moves around the nodes as necessary.
//
//               The return value is normally true, but it may be
//               false to indicate the CollisionTraverser should
//               disable this handler from being called in the future.
////////////////////////////////////////////////////////////////////
bool CollisionHandlerPusher::
handle_entries() {
  bool okflag = true;

  FromEntries::const_iterator fi;
  for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) {
    CollisionNode *from_node = (*fi).first;
    nassertr(from_node != (CollisionNode *)NULL, false);
    const Entries &entries = (*fi).second;

    Colliders::iterator ci;
    ci = _colliders.find(from_node);
    if (ci == _colliders.end()) {
      // Hmm, someone added a CollisionNode to a traverser and gave
      // it this CollisionHandler pointer--but they didn't tell us
      // about the node.
      collide_cat.error()
        << "CollisionHandlerPusher doesn't know about "
        << *from_node << ", disabling.\n";
      okflag = false;
    } else {
      ColliderDef &def = (*ci).second;
      if (!def.is_valid()) {
        collide_cat.error()
          << "Removing invalid collider " << *from_node << " from "
          << get_type() << "\n";
        _colliders.erase(ci);
      } else {
        // How to apply multiple shoves from different solids onto the
        // same collider?  One's first intuition is to vector sum all
        // the shoves.  However, this causes problems when two parallel
        // walls shove on the collider, because we end up with a double
        // shove.  We hack around this by testing if two shove vectors
        // share nearly the same direction, and if so, we keep only the
        // longer of the two.

        typedef pvector<ShoveData> Shoves;
        Shoves shoves;

        Entries::const_iterator ei;
        for (ei = entries.begin(); ei != entries.end(); ++ei) {
          CollisionEntry *entry = (*ei);
          nassertr(entry != (CollisionEntry *)NULL, false);
          nassertr(from_node == entry->get_from_node(), false);

          if (!entry->has_from_surface_normal() ||
              !entry->has_from_depth()) {
            #ifndef NDEBUG
            if (collide_cat.is_debug()) {
              collide_cat.debug()
                << "Cannot shove on " << *from_node << " for collision into "
                << *entry->get_into_node() << "; no normal/depth information.\n";
            }
            #endif
          } else {
            // Shove it just enough to clear the volume.
            if (entry->get_from_depth() != 0.0f) {
              LVector3f normal = entry->get_from_surface_normal();
              if (_horizontal) {
                normal[2] = 0.0f;
              }
              // Just to be on the safe size, we normalize the normal
              // vector, even though it really ought to be unit-length
              // already (unless we just forced it horizontal, above).
              normal.normalize();

              ShoveData sd;
              sd._vector = normal;
              sd._length = entry->get_from_depth();
              sd._valid = true;
              sd._entry = entry;

              #ifndef NDEBUG
              if (collide_cat.is_debug()) {
                collide_cat.debug()
                  << "Shove on " << *from_node << " from "
                  << *entry->get_into_node() << ": " << sd._vector
                  << " times " << sd._length << "\n";
              }
              #endif

              shoves.push_back(sd);
            }
          }
        }

        if (!shoves.empty()) {
          // Now we look for two shoves that are largely in the same
          // direction, so we can combine them into a single shove of
          // the same magnitude; we also check for two shoves at 90
          // degrees, so we can detect whether we are hitting an inner
          // or an outer corner.

          Shoves::iterator si;
          for (si = shoves.begin(); si != shoves.end(); ++si) {
            ShoveData &sd = (*si);
            Shoves::iterator sj;
            for (sj = shoves.begin(); sj != si; ++sj) {
              ShoveData &sd2 = (*sj);
              if (sd2._valid) {

                float d = sd._vector.dot(sd2._vector);
                if (collide_cat.is_debug()) {
                  collide_cat.debug()
                    << "Considering dot product " << d << "\n";
                }

                if (d > 0.9) {
                  // These two shoves are largely in the same direction;
                  // save the larger of the two.
                  if (sd2._length < sd._length) {
                    sd2._valid = false;
                  } else {
                    sd._valid = false;
                  }

                } else {
                  // These two shoves are not in the same direction.
                  // If they are both from polygons that are a child
                  // of the same node, try to determine the shape of
                  // the corner (convex or concave).
                  const CollisionSolid *s1 = sd._entry->get_into();
                  const CollisionSolid *s2 = sd2._entry->get_into();
                  if (s1 != (CollisionSolid *)NULL &&
                      s2 != (CollisionSolid *)NULL &&
                      s1->is_exact_type(CollisionPolygon::get_class_type()) &&
                      s2->is_exact_type(CollisionPolygon::get_class_type()) &&
                      sd._entry->get_into_node_path() ==
                      sd2._entry->get_into_node_path()) {
                    const CollisionPolygon *p1 = DCAST(CollisionPolygon, s1);
                    const CollisionPolygon *p2 = DCAST(CollisionPolygon, s2);
                    if (p1->dist_to_plane(p2->get_collision_origin()) < 0 &&
                        p2->dist_to_plane(p1->get_collision_origin()) < 0) {
                      // Each polygon is behind the other one.  That
                      // means we have a convex corner, and therefore
                      // we should discard one of the shoves (or the
                      // user will get stuck coming at a convex
                      // corner).
                      if (collide_cat.is_debug()) {
                        collide_cat.debug()
                          << "Discarding shove from convex corner.\n";
                      }

                      // This time, unlike the case of two parallel
                      // walls above, we discard the larger of the two
                      // shoves, not the smaller.  This is because as
                      // we slide off the convex corner, the wall we
                      // are sliding away from will get a bigger and
                      // bigger shove--and we need to keep ignoring
                      // the same wall as we slide.
                      if (sd2._length < sd._length) {
                        sd._valid = false;
                      } else {
                        sd2._valid = false;
                      }
                    }
                  }
                }
              }
            }
          }

          // Now we can determine the net shove.
          LVector3f net_shove(0.0f, 0.0f, 0.0f);
          LVector3f force_normal(0.0f, 0.0f, 0.0f);
          for (si = shoves.begin(); si != shoves.end(); ++si) {
            const ShoveData &sd = (*si);
            if (sd._valid) {
              net_shove += sd._vector * sd._length;
              force_normal += sd._vector;
            }
          }

          #ifndef NDEBUG
          if (collide_cat.is_debug()) {
            collide_cat.debug()
              << "Net shove on " << *from_node << " is: "
              << net_shove << "\n";
          }
          #endif

          if (def._node != (PandaNode *)NULL) {
            // If we are adjusting a plain PandaNode, get the
            // transform and adjust just the position to preserve
            // maximum precision.
            CPT(TransformState) trans = def._node->get_transform();
            LVecBase3f pos = trans->get_pos();
            pos += net_shove * trans->get_mat();
            def._node->set_transform(trans->set_pos(pos));
          } else {
            // Otherwise, go ahead and do the matrix math to do things
            // the old and clumsy way.
            LMatrix4f mat;
            def.get_mat(mat);
            def.set_mat(LMatrix4f::translate_mat(net_shove) * mat);
          }
          apply_linear_force(def, force_normal);
        }
      }
    }
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::apply_linear_force
//       Access: Protected, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
void CollisionHandlerPusher::
apply_linear_force(ColliderDef &, const LVector3f &) {
}
<commit_msg>calling apply_linear_force if node is a PandaNode<commit_after>// Filename: collisionHandlerPusher.cxx
// Created by:  drose (16Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "collisionHandlerPusher.h"
#include "collisionNode.h"
#include "collisionEntry.h"
#include "collisionPolygon.h"
#include "config_collide.h"
#include "dcast.h"

TypeHandle CollisionHandlerPusher::_type_handle;

///////////////////////////////////////////////////////////////////
//       Class : ShoveData
// Description : The ShoveData class is used within
//               CollisionHandlerPusher::handle_entries(), to track
//               multiple shoves onto a given collider.  It's not
//               exported outside this file.
////////////////////////////////////////////////////////////////////
class ShoveData {
public:
  LVector3f _vector;
  float _length;
  bool _valid;
  CollisionEntry *_entry;
};

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
CollisionHandlerPusher::
CollisionHandlerPusher() {
  _horizontal = true;
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
CollisionHandlerPusher::
~CollisionHandlerPusher() {
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::handle_entries
//       Access: Protected, Virtual
//  Description: Called by the parent class after all collisions have
//               been detected, this manages the various collisions
//               and moves around the nodes as necessary.
//
//               The return value is normally true, but it may be
//               false to indicate the CollisionTraverser should
//               disable this handler from being called in the future.
////////////////////////////////////////////////////////////////////
bool CollisionHandlerPusher::
handle_entries() {
  bool okflag = true;

  FromEntries::const_iterator fi;
  for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) {
    CollisionNode *from_node = (*fi).first;
    nassertr(from_node != (CollisionNode *)NULL, false);
    const Entries &entries = (*fi).second;

    Colliders::iterator ci;
    ci = _colliders.find(from_node);
    if (ci == _colliders.end()) {
      // Hmm, someone added a CollisionNode to a traverser and gave
      // it this CollisionHandler pointer--but they didn't tell us
      // about the node.
      collide_cat.error()
        << "CollisionHandlerPusher doesn't know about "
        << *from_node << ", disabling.\n";
      okflag = false;
    } else {
      ColliderDef &def = (*ci).second;
      if (!def.is_valid()) {
        collide_cat.error()
          << "Removing invalid collider " << *from_node << " from "
          << get_type() << "\n";
        _colliders.erase(ci);
      } else {
        // How to apply multiple shoves from different solids onto the
        // same collider?  One's first intuition is to vector sum all
        // the shoves.  However, this causes problems when two parallel
        // walls shove on the collider, because we end up with a double
        // shove.  We hack around this by testing if two shove vectors
        // share nearly the same direction, and if so, we keep only the
        // longer of the two.

        typedef pvector<ShoveData> Shoves;
        Shoves shoves;

        Entries::const_iterator ei;
        for (ei = entries.begin(); ei != entries.end(); ++ei) {
          CollisionEntry *entry = (*ei);
          nassertr(entry != (CollisionEntry *)NULL, false);
          nassertr(from_node == entry->get_from_node(), false);

          if (!entry->has_from_surface_normal() ||
              !entry->has_from_depth()) {
            #ifndef NDEBUG
            if (collide_cat.is_debug()) {
              collide_cat.debug()
                << "Cannot shove on " << *from_node << " for collision into "
                << *entry->get_into_node() << "; no normal/depth information.\n";
            }
            #endif
          } else {
            // Shove it just enough to clear the volume.
            if (entry->get_from_depth() != 0.0f) {
              LVector3f normal = entry->get_from_surface_normal();
              if (_horizontal) {
                normal[2] = 0.0f;
              }
              // Just to be on the safe size, we normalize the normal
              // vector, even though it really ought to be unit-length
              // already (unless we just forced it horizontal, above).
              normal.normalize();

              ShoveData sd;
              sd._vector = normal;
              sd._length = entry->get_from_depth();
              sd._valid = true;
              sd._entry = entry;

              #ifndef NDEBUG
              if (collide_cat.is_debug()) {
                collide_cat.debug()
                  << "Shove on " << *from_node << " from "
                  << *entry->get_into_node() << ": " << sd._vector
                  << " times " << sd._length << "\n";
              }
              #endif

              shoves.push_back(sd);
            }
          }
        }

        if (!shoves.empty()) {
          // Now we look for two shoves that are largely in the same
          // direction, so we can combine them into a single shove of
          // the same magnitude; we also check for two shoves at 90
          // degrees, so we can detect whether we are hitting an inner
          // or an outer corner.

          Shoves::iterator si;
          for (si = shoves.begin(); si != shoves.end(); ++si) {
            ShoveData &sd = (*si);
            Shoves::iterator sj;
            for (sj = shoves.begin(); sj != si; ++sj) {
              ShoveData &sd2 = (*sj);
              if (sd2._valid) {
                float d = sd._vector.dot(sd2._vector);
                if (collide_cat.is_debug()) {
                  collide_cat.debug()
                    << "Considering dot product " << d << "\n";
                }

                if (d > 0.9) {
                  // These two shoves are largely in the same direction;
                  // save the larger of the two.
                  if (sd2._length < sd._length) {
                    sd2._valid = false;
                  } else {
                    sd._valid = false;
                  }
                } else {
                  // These two shoves are not in the same direction.
                  // If they are both from polygons that are a child
                  // of the same node, try to determine the shape of
                  // the corner (convex or concave).
                  const CollisionSolid *s1 = sd._entry->get_into();
                  const CollisionSolid *s2 = sd2._entry->get_into();
                  if (s1 != (CollisionSolid *)NULL &&
                      s2 != (CollisionSolid *)NULL &&
                      s1->is_exact_type(CollisionPolygon::get_class_type()) &&
                      s2->is_exact_type(CollisionPolygon::get_class_type()) &&
                      sd._entry->get_into_node_path() ==
                      sd2._entry->get_into_node_path()) {
                    const CollisionPolygon *p1 = DCAST(CollisionPolygon, s1);
                    const CollisionPolygon *p2 = DCAST(CollisionPolygon, s2);
                    if (p1->dist_to_plane(p2->get_collision_origin()) < 0 &&
                        p2->dist_to_plane(p1->get_collision_origin()) < 0) {
                      // Each polygon is behind the other one.  That
                      // means we have a convex corner, and therefore
                      // we should discard one of the shoves (or the
                      // user will get stuck coming at a convex
                      // corner).
                      if (collide_cat.is_debug()) {
                        collide_cat.debug()
                          << "Discarding shove from convex corner.\n";
                      }

                      // This time, unlike the case of two parallel
                      // walls above, we discard the larger of the two
                      // shoves, not the smaller.  This is because as
                      // we slide off the convex corner, the wall we
                      // are sliding away from will get a bigger and
                      // bigger shove--and we need to keep ignoring
                      // the same wall as we slide.
                      if (sd2._length < sd._length) {
                        sd._valid = false;
                      } else {
                        sd2._valid = false;
                      }
                    }
                  }
                }
              }
            }
          }

          // Now we can determine the net shove.
          LVector3f net_shove(0.0f, 0.0f, 0.0f);
          LVector3f force_normal(0.0f, 0.0f, 0.0f);
          for (si = shoves.begin(); si != shoves.end(); ++si) {
            const ShoveData &sd = (*si);
            if (sd._valid) {
              net_shove += sd._vector * sd._length;
              force_normal += sd._vector;
            }
          }

          #ifndef NDEBUG
          if (collide_cat.is_debug()) {
            collide_cat.debug()
              << "Net shove on " << *from_node << " is: "
              << net_shove << "\n";
          }
          #endif

          if (def._node != (PandaNode *)NULL) {
            // If we are adjusting a plain PandaNode, get the
            // transform and adjust just the position to preserve
            // maximum precision.
            CPT(TransformState) trans = def._node->get_transform();
            LVecBase3f pos = trans->get_pos();
            pos += net_shove * trans->get_mat();
            def._node->set_transform(trans->set_pos(pos));

            apply_linear_force(def, force_normal);
          } else {
            // Otherwise, go ahead and do the matrix math to do things
            // the old and clumsy way.
            LMatrix4f mat;
            def.get_mat(mat);
            def.set_mat(LMatrix4f::translate_mat(net_shove) * mat);
          }
        }
      }
    }
  }

  return okflag;
}

////////////////////////////////////////////////////////////////////
//     Function: CollisionHandlerPusher::apply_linear_force
//       Access: Protected, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
void CollisionHandlerPusher::
apply_linear_force(ColliderDef &, const LVector3f &) {
}
<|endoftext|>


<commit_before>// Filename: config_parametrics.cxx
// Created by:  drose (19Mar00)
//
////////////////////////////////////////////////////////////////////

#include "classicNurbsCurve.h"
#include "config_parametrics.h"
#include "cubicCurveseg.h"
#include "curveFitter.h"
#include "hermiteCurve.h"
#include "nurbsCurveDrawer.h"
#include "nurbsCurveInterface.h"
#include "parametricCurve.h"
#include "parametricCurveDrawer.h"
#include "piecewiseCurve.h"

#ifdef HAVE_NURBSPP
#include "nurbsPPCurve.h"
#endif

#include "get_config_path.h"

Configure(config_parametrics);
NotifyCategoryDef(parametrics, "");

ConfigureFn(config_parametrics) {
  ClassicNurbsCurve::init_type();
  CubicCurveseg::init_type();
  CurveFitter::init_type();
  HermiteCurve::init_type();
  NurbsCurveDrawer::init_type();
  NurbsCurveInterface::init_type();
  NurbsPPCurve::init_type();
  ParametricCurve::init_type();
  ParametricCurveDrawer::init_type();
  PiecewiseCurve::init_type();

#ifdef HAVE_NURBSPP
  NurbsPPCurve::init_type();
#endif

  ClassicNurbsCurve::register_with_read_factory();
  CubicCurveseg::register_with_read_factory();
  HermiteCurve::register_with_read_factory();
}

const DSearchPath &
get_parametrics_path() {
  static DSearchPath *parametrics_path = NULL;
  return get_config_path("parametrics-path", parametrics_path);
}
<commit_msg>*** empty log message ***<commit_after>// Filename: config_parametrics.cxx
// Created by:  drose (19Mar00)
//
////////////////////////////////////////////////////////////////////

#include "classicNurbsCurve.h"
#include "config_parametrics.h"
#include "cubicCurveseg.h"
#include "curveFitter.h"
#include "hermiteCurve.h"
#include "nurbsCurveDrawer.h"
#include "nurbsCurveInterface.h"
#include "parametricCurve.h"
#include "parametricCurveDrawer.h"
#include "piecewiseCurve.h"

#ifdef HAVE_NURBSPP
#include "nurbsPPCurve.h"
#endif

#include "get_config_path.h"

Configure(config_parametrics);
NotifyCategoryDef(parametrics, "");

ConfigureFn(config_parametrics) {
  ClassicNurbsCurve::init_type();
  CubicCurveseg::init_type();
  CurveFitter::init_type();
  HermiteCurve::init_type();
  NurbsCurveDrawer::init_type();
  NurbsCurveInterface::init_type();
  ParametricCurve::init_type();
  ParametricCurveDrawer::init_type();
  PiecewiseCurve::init_type();

#ifdef HAVE_NURBSPP
  NurbsPPCurve::init_type();
#endif

  ClassicNurbsCurve::register_with_read_factory();
  CubicCurveseg::register_with_read_factory();
  HermiteCurve::register_with_read_factory();
}

const DSearchPath &
get_parametrics_path() {
  static DSearchPath *parametrics_path = NULL;
  return get_config_path("parametrics-path", parametrics_path);
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <rapidcheck/catch.h>

#include <numeric>

#include "rapidcheck/detail/BitStream.h"
#include "rapidcheck/detail/Utility.h"

using namespace rc;
using namespace rc::detail;

template <typename T>
class SeqSource {
public:
  template <typename Arg,
            typename = typename std::enable_if<
                !std::is_same<Decay<Arg>, SeqSource>::value>::type>
  SeqSource(Arg &&arg)
      : m_seq(std::forward<Arg>(arg))
      , m_requested(0) {}

  T next() {
    auto value = m_seq.next();
    RC_ASSERT(value);
    m_requested++;
    return *value;
  }

  int requested() const { return m_requested; }

private:
  Seq<T> m_seq;
  int m_requested;
};

template <typename T>
SeqSource<T> makeSource(Seq<T> seq) {
  return SeqSource<T>(std::move(seq));
}

TEST_CASE("BitStream") {
  SECTION("next") {
    const auto bitSizes =
        gen::container<std::vector<int>>(gen::inRange(0, 100));

    prop("requests the correct number of bits",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           const auto sizes = *bitSizes;
           int totalSize = 0;
           for (int size : sizes) {
             totalSize += size;
             stream.next<uint64_t>(size);
           }

           int expected = totalSize / 8;
           if ((totalSize % 8) != 0) {
             expected++;
           }
           RC_ASSERT(source.requested() == expected);
         });

    prop("spills no bits",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);

           const auto sizes = *gen::suchThat(bitSizes,
                                       [](const std::vector<int> &x) {
                                         return std::accumulate(
                                                    begin(x), end(x), 0) >= 64;
                                       });

           uint64_t value = 0;
           int n = 64;
           for (int size : sizes) {
             if (n == 0) {
               break;
             }
             const auto r = std::min(n, size);
             const auto bits = stream.next<uint64_t>(r);
             value |= (bits << (64ULL - n));
             n -= r;
           }

           RC_ASSERT(value == x);
         });

    prop("takes multiple values per request if required to fill result",
         [](uint8_t byte) {
           auto source = makeSource(seq::take(8, seq::repeat(byte)));
           auto stream = bitStreamOf(source);
           uint64_t value = stream.next<uint64_t>(64);
           uint64_t expected = 0;
           for (int i = 0; i < 8; i++) {
             expected <<= 8ULL;
             expected |= byte;
           }

           RC_ASSERT(value == expected);
         });

    prop("does not return more bits than requested (unsigned)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           int n = *gen::inRange(1, 64);
           RC_ASSERT((stream.next<uint64_t>(n) & ~bitMask<uint64_t>(n)) == 0U);
         });

    prop("does not return more bits than requested (signed)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           const auto n = *gen::inRange(1, 64);
           const bool sign = (x & (1LL << (n - 1LL))) != 0;
           const auto mask = ~bitMask<int64_t>(n);
           if (sign) {
             RC_ASSERT((stream.next<int64_t>(n) & mask) == mask);
           } else {
             RC_ASSERT((stream.next<int64_t>(n) & mask) == 0);
           }
         });

    prop("does not return any bits when none are requested",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           RC_ASSERT((stream.next<uint64_t>(0) & bitMask<uint64_t>(64)) == 0U);
         });

    prop("does not return any bits when none are requested (signed)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           RC_ASSERT((stream.next<int64_t>(0) & bitMask<int64_t>(64)) == 0);
         });

    prop("works with booleans",
         [](uint64_t x) {
           auto source = makeSource(seq::just(x));
           auto stream = bitStreamOf(source);
           uint64_t value = 0;
           for (uint64_t i = 0; i < 64ULL; i++) {
             if (stream.next<bool>(1)) {
               value |= 1ULL << i;
             }
           }

           RC_ASSERT(value == x);
         });
  }

  SECTION("nextWithSize") {
    prop("requests full number of bits for kNominalSize",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::inRange(0, 100);
           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(kNominalSize);
           }

           RC_ASSERT(source.requested() == n);
         });

    prop("requests half number of bits for kNominalSize / 2",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::suchThat(gen::inRange(0, 100),
                                  [](int x) { return (x % 2) == 0; });

           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(kNominalSize / 2);
           }

           RC_ASSERT(source.requested() == (n / 2));
         });

    prop("requests no bits for size 0",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::inRange(0, 100);
           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(0);
           }

           RC_ASSERT(source.requested() == 0);
         });
  }

  SECTION("bitStreamOf") {
    SECTION("copies source if const") {
      auto source = makeSource(seq::just(0, 1));
      const auto &constSource = source;
      auto stream = bitStreamOf(constSource);
      stream.next<int>();
      REQUIRE(source.next() == 0);
    }

    SECTION("references source if non-const") {
      auto source = makeSource(seq::just(0, 1));
      auto &nonConstSource = source;
      auto stream = bitStreamOf(nonConstSource);
      stream.next<int>();
      REQUIRE(source.next() == 1);
    }
  }
}
<commit_msg>Simplify a pair of test cases<commit_after>#include <catch.hpp>
#include <rapidcheck/catch.h>

#include <numeric>

#include "rapidcheck/detail/BitStream.h"
#include "rapidcheck/detail/Utility.h"

using namespace rc;
using namespace rc::detail;

template <typename T>
class SeqSource {
public:
  template <typename Arg,
            typename = typename std::enable_if<
                !std::is_same<Decay<Arg>, SeqSource>::value>::type>
  SeqSource(Arg &&arg)
      : m_seq(std::forward<Arg>(arg))
      , m_requested(0) {}

  T next() {
    auto value = m_seq.next();
    RC_ASSERT(value);
    m_requested++;
    return *value;
  }

  int requested() const { return m_requested; }

private:
  Seq<T> m_seq;
  int m_requested;
};

template <typename T>
SeqSource<T> makeSource(Seq<T> seq) {
  return SeqSource<T>(std::move(seq));
}

TEST_CASE("BitStream") {
  SECTION("next") {
    const auto bitSizes =
        gen::container<std::vector<int>>(gen::inRange(0, 100));

    prop("requests the correct number of bits",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           const auto sizes = *bitSizes;
           int totalSize = 0;
           for (int size : sizes) {
             totalSize += size;
             stream.next<uint64_t>(size);
           }

           int expected = totalSize / 8;
           if ((totalSize % 8) != 0) {
             expected++;
           }
           RC_ASSERT(source.requested() == expected);
         });

    prop("spills no bits",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);

           const auto sizes = *gen::suchThat(bitSizes,
                                       [](const std::vector<int> &x) {
                                         return std::accumulate(
                                                    begin(x), end(x), 0) >= 64;
                                       });

           uint64_t value = 0;
           int n = 64;
           for (int size : sizes) {
             if (n == 0) {
               break;
             }
             const auto r = std::min(n, size);
             const auto bits = stream.next<uint64_t>(r);
             value |= (bits << (64ULL - n));
             n -= r;
           }

           RC_ASSERT(value == x);
         });

    prop("takes multiple values per request if required to fill result",
         [](uint8_t byte) {
           auto source = makeSource(seq::take(8, seq::repeat(byte)));
           auto stream = bitStreamOf(source);
           uint64_t value = stream.next<uint64_t>(64);
           uint64_t expected = 0;
           for (int i = 0; i < 8; i++) {
             expected <<= 8ULL;
             expected |= byte;
           }

           RC_ASSERT(value == expected);
         });

    prop("does not return more bits than requested (unsigned)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           int n = *gen::inRange(1, 64);
           RC_ASSERT((stream.next<uint64_t>(n) & ~bitMask<uint64_t>(n)) == 0U);
         });

    prop("does not return more bits than requested (signed)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           const auto n = *gen::inRange(1, 64);
           const bool sign = (x & (1LL << (n - 1LL))) != 0;
           const auto mask = ~bitMask<int64_t>(n);
           if (sign) {
             RC_ASSERT((stream.next<int64_t>(n) & mask) == mask);
           } else {
             RC_ASSERT((stream.next<int64_t>(n) & mask) == 0);
           }
         });

    prop("does not return any bits when none are requested",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           RC_ASSERT(stream.next<uint64_t>(0) == 0U);
         });

    prop("does not return any bits when none are requested (signed)",
         [=](uint64_t x) {
           auto source = makeSource(seq::repeat(x));
           auto stream = bitStreamOf(source);
           RC_ASSERT(stream.next<int64_t>(0) == 0);
         });

    prop("works with booleans",
         [](uint64_t x) {
           auto source = makeSource(seq::just(x));
           auto stream = bitStreamOf(source);
           uint64_t value = 0;
           for (uint64_t i = 0; i < 64ULL; i++) {
             if (stream.next<bool>(1)) {
               value |= 1ULL << i;
             }
           }

           RC_ASSERT(value == x);
         });
  }

  SECTION("nextWithSize") {
    prop("requests full number of bits for kNominalSize",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::inRange(0, 100);
           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(kNominalSize);
           }

           RC_ASSERT(source.requested() == n);
         });

    prop("requests half number of bits for kNominalSize / 2",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::suchThat(gen::inRange(0, 100),
                                  [](int x) { return (x % 2) == 0; });

           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(kNominalSize / 2);
           }

           RC_ASSERT(source.requested() == (n / 2));
         });

    prop("requests no bits for size 0",
         [=] {
           auto source = makeSource(seq::repeat('\xAB'));
           auto stream = bitStreamOf(source);

           int n = *gen::inRange(0, 100);
           for (int i = 0; i < n; i++) {
             stream.nextWithSize<char>(0);
           }

           RC_ASSERT(source.requested() == 0);
         });
  }

  SECTION("bitStreamOf") {
    SECTION("copies source if const") {
      auto source = makeSource(seq::just(0, 1));
      const auto &constSource = source;
      auto stream = bitStreamOf(constSource);
      stream.next<int>();
      REQUIRE(source.next() == 0);
    }

    SECTION("references source if non-const") {
      auto source = makeSource(seq::just(0, 1));
      auto &nonConstSource = source;
      auto stream = bitStreamOf(nonConstSource);
      stream.next<int>();
      REQUIRE(source.next() == 1);
    }
  }
}
<|endoftext|>


<commit_before><commit_msg>Added comments.<commit_after><|endoftext|>


<commit_before>#include "benchmark/benchmark_api.h"
#include "test_configs.h"
#include "test_utils.h"

#include<algorithm>
#include<deque>
#include<map>
#include<list>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<vector>

// TODO: get, operator[], count, equal_range, erase, lower_bound, upper_bound

template<typename V>
void BM_advance(benchmark::State& state) {
  int N = state.range(0);
  V v;
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.begin();
      std::advance(it, i);
      benchmark::DoNotOptimize(it);
    }
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_access(benchmark::State& state) {
  int N = state.range(0);
  V v;
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.begin();
      std::advance(it, i);
      benchmark::DoNotOptimize(*it);
    }
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_at(benchmark::State& state) {
  int N = state.range(0);
  V v(N);
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i)
      benchmark::DoNotOptimize(v.at(i));
  }
  state.SetComplexityN(N);
}

// Insert random elements
template<typename V>
void BM_assoc_find_random(benchmark::State& state) {
  int N = state.range(0);
  using CVT = typename V::value_type;
  using VT = typename remove_const<CVT>::type;
  using KT = typename std::remove_const<typename V::key_type>::type;
  std::vector<KT> temp(N);
  fill_random(temp, N);
  V v;
  random_device r;
  for (int i = 0; i < N; ++i)
    v.insert(get_rand<VT>(r, RAND_MAX));
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i)
      benchmark::DoNotOptimize(v.find(temp[i]));
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_assoc_find_seq(benchmark::State& state) {
  int N = state.range(0);
  using CVT = typename V::value_type;
  using VT = typename remove_const<CVT>::type;
  using KT = typename std::remove_const<typename V::key_type>::type;
  std::vector<VT> temp(N);
  fill_seq(temp);
  V v;
  for (int i = 0; i < N; ++i)
    v.insert(temp[i]);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.find(i);
      benchmark::DoNotOptimize(it);
      assert (it != v.end());
    }
  }
  state.SetComplexityN(N);
}

static const int MSize = L1;

#define BENCH_STD_MAP(T) SINGLE_ARG(std::map<T, T>)
#define BENCH_STD_UNORDERED_MAP(T) SINGLE_ARG(std::unordered_map<T, T>)

#define COMPLEXITY_BENCHMARK_GEN_T(T) \
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::list<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::list<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_at, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_at, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, std::set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, std::unordered_set<T>, MSize);\
\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, BENCH_STD_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, BENCH_STD_UNORDERED_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, std::set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, std::unordered_set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, BENCH_STD_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, BENCH_STD_UNORDERED_MAP(T), MSize);

COMPLEXITY_BENCHMARK_GEN_T(int)
COMPLEXITY_BENCHMARK_GEN_T(aggregate)

BENCHMARK_MAIN()
<commit_msg>Fix segfault in case of deque<aggregate><commit_after>#include "benchmark/benchmark_api.h"
#include "test_configs.h"
#include "test_utils.h"

#include<algorithm>
#include<deque>
#include<map>
#include<list>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<vector>

// TODO: get, operator[], count, equal_range, erase, lower_bound, upper_bound

template<typename V>
void BM_advance(benchmark::State& state) {
  int N = state.range(0);
  V v(N);
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.begin();
      std::advance(it, i);
      benchmark::DoNotOptimize(it);
    }
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_access(benchmark::State& state) {
  int N = state.range(0);
  V v(N);
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.begin();
      std::advance(it, i);
      benchmark::DoNotOptimize(*it);
    }
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_at(benchmark::State& state) {
  int N = state.range(0);
  V v(N);
  fill_seq(v);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i)
      benchmark::DoNotOptimize(v.at(i));
  }
  state.SetComplexityN(N);
}

// Insert random elements
template<typename V>
void BM_assoc_find_random(benchmark::State& state) {
  int N = state.range(0);
  using CVT = typename V::value_type;
  using VT = typename remove_const<CVT>::type;
  using KT = typename std::remove_const<typename V::key_type>::type;
  std::vector<KT> temp(N);
  fill_random(temp, N);
  V v;
  random_device r;
  for (int i = 0; i < N; ++i)
    v.insert(get_rand<VT>(r, RAND_MAX));
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i)
      benchmark::DoNotOptimize(v.find(temp[i]));
  }
  state.SetComplexityN(N);
}

template<typename V>
void BM_assoc_find_seq(benchmark::State& state) {
  int N = state.range(0);
  using CVT = typename V::value_type;
  using VT = typename remove_const<CVT>::type;
  using KT = typename std::remove_const<typename V::key_type>::type;
  std::vector<VT> temp(N);
  fill_seq(temp);
  V v;
  for (int i = 0; i < N; ++i)
    v.insert(temp[i]);
  while (state.KeepRunning()) {
    for (int i = 0; i < N; ++i) {
      auto it = v.find(i);
      benchmark::DoNotOptimize(it);
      assert (it != v.end());
    }
  }
  state.SetComplexityN(N);
}

static const int MSize = L1;

#define BENCH_STD_MAP(T) SINGLE_ARG(std::map<T, T>)
#define BENCH_STD_UNORDERED_MAP(T) SINGLE_ARG(std::unordered_map<T, T>)

#define COMPLEXITY_BENCHMARK_GEN_T(T) \
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::list<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_advance, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::list<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_access, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_at, std::vector<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_at, std::deque<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, std::set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, std::unordered_set<T>, MSize);\
\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, BENCH_STD_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_random, BENCH_STD_UNORDERED_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, std::set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, std::unordered_set<T>, MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, BENCH_STD_MAP(T), MSize);\
    COMPLEXITY_BENCHMARK_GEN(BM_assoc_find_seq, BENCH_STD_UNORDERED_MAP(T), MSize);

COMPLEXITY_BENCHMARK_GEN_T(int)
COMPLEXITY_BENCHMARK_GEN_T(aggregate)

BENCHMARK_MAIN()
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_capture/android/device_info_android.h"

#include <algorithm>
#include <sstream>
#include <vector>

#include "json/json.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "webrtc/modules/video_capture/android/video_capture_android.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/ref_count.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace videocapturemodule {

// Helper for storing lists of pairs of ints.  Used e.g. for resolutions & FPS
// ranges.
typedef std::pair<int, int> IntPair;
typedef std::vector<IntPair> IntPairs;

static std::string IntPairsToString(const IntPairs& pairs, char separator) {
  std::stringstream stream;
  for (size_t i = 0; i < pairs.size(); ++i) {
    if (i > 0)
      stream << ", ";
    stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
  }
  return stream.str();
}

struct AndroidCameraInfo {
  std::string name;
  bool front_facing;
  int orientation;
  IntPairs resolutions;  // Pairs are: (width,height).
  // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
  IntPairs mfpsRanges;

  std::string ToString() {
    std::stringstream stream;
    stream << "Name: [" << name << "], MFPS ranges: ["
           << IntPairsToString(mfpsRanges, ':')
           << "], front_facing: " << front_facing
           << ", orientation: " << orientation << ", resolutions: ["
           << IntPairsToString(resolutions, 'x') << "]";
    return stream.str();
  }
};

// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable
// thereafter.
static std::vector<AndroidCameraInfo>* g_camera_info = NULL;

// Set |*index| to the index of |name| in g_camera_info or return false if no
// match found.
static bool FindCameraIndexByName(const std::string& name, size_t* index) {
  for (size_t i = 0; i < g_camera_info->size(); ++i) {
    if (g_camera_info->at(i).name == name) {
      *index = i;
      return true;
    }
  }
  return false;
}

// Returns a pointer to the named member of g_camera_info, or NULL if no match
// is found.
static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
  size_t index = 0;
  if (FindCameraIndexByName(name, &index))
    return &g_camera_info->at(index);
  return NULL;
}

// static
void DeviceInfoAndroid::Initialize(JNIEnv* jni) {
  // TODO(henrike): this "if" would make a lot more sense as an assert, but
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to
  // prevent this.  Once that code is made to only
  // VideoEngine::SetAndroidObjects() once per process, this can turn into an
  // assert.
  if (g_camera_info)
    return;

  g_camera_info = new std::vector<AndroidCameraInfo>();
  jclass j_info_class =
      jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
  assert(j_info_class);
  jmethodID j_initialize = jni->GetStaticMethodID(
      j_info_class, "getDeviceInfo", "()Ljava/lang/String;");
  jstring j_json_info = static_cast<jstring>(
      jni->CallStaticObjectMethod(j_info_class, j_initialize));

  const jchar* jchars = jni->GetStringChars(j_json_info, NULL);
  icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info));
  jni->ReleaseStringChars(j_json_info, jchars);
  std::string json_info;
  ustr.toUTF8String(json_info);

  Json::Value cameras;
  Json::Reader reader(Json::Features::strictMode());
  bool parsed = reader.parse(json_info, cameras);
  if (!parsed) {
    std::stringstream stream;
    stream << "Failed to parse configuration:\n"
           << reader.getFormattedErrorMessages();
    assert(false);
    return;
  }
  for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) {
    const Json::Value& camera = cameras[i];
    AndroidCameraInfo info;
    info.name = camera["name"].asString();
    info.front_facing = camera["front_facing"].asBool();
    info.orientation = camera["orientation"].asInt();
    Json::Value sizes = camera["sizes"];
    for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) {
      const Json::Value& size = sizes[j];
      info.resolutions.push_back(std::make_pair(
          size["width"].asInt(), size["height"].asInt()));
    }
    Json::Value mfpsRanges = camera["mfpsRanges"];
    for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) {
      const Json::Value& mfpsRange = mfpsRanges[j];
      info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(),
                                               mfpsRange["max_mfps"].asInt()));
    }
    g_camera_info->push_back(info);
  }
}

void DeviceInfoAndroid::DeInitialize() {
  if (g_camera_info) {
    delete g_camera_info;
    g_camera_info = NULL;
  }
}

VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
    const int32_t id) {
  return new videocapturemodule::DeviceInfoAndroid(id);
}

DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) :
    DeviceInfoImpl(id) {
}

DeviceInfoAndroid::~DeviceInfoAndroid() {
}

bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
                                        size_t* index) {
  return FindCameraIndexByName(deviceUniqueIdUTF8, index);
}

int32_t DeviceInfoAndroid::Init() {
  return 0;
}

uint32_t DeviceInfoAndroid::NumberOfDevices() {
  return g_camera_info->size();
}

int32_t DeviceInfoAndroid::GetDeviceName(
    uint32_t deviceNumber,
    char* deviceNameUTF8,
    uint32_t deviceNameLength,
    char* deviceUniqueIdUTF8,
    uint32_t deviceUniqueIdUTF8Length,
    char* /*productUniqueIdUTF8*/,
    uint32_t /*productUniqueIdUTF8Length*/) {
  if (deviceNumber >= g_camera_info->size())
    return -1;
  const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
  if (info.name.length() + 1 > deviceNameLength ||
      info.name.length() + 1 > deviceUniqueIdUTF8Length) {
    return -1;
  }
  memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
  memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
  return 0;
}

int32_t DeviceInfoAndroid::CreateCapabilityMap(
    const char* deviceUniqueIdUTF8) {
  _captureCapabilities.clear();
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return -1;

  for (size_t i = 0; i < info->resolutions.size(); ++i) {
    for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
      const IntPair& size = info->resolutions[i];
      const IntPair& mfpsRange = info->mfpsRanges[j];
      VideoCaptureCapability cap;
      cap.width = size.first;
      cap.height = size.second;
      cap.maxFPS = mfpsRange.second / 1000;
      cap.expectedCaptureDelay = kExpectedCaptureDelay;
      cap.rawType = kVideoNV21;
      _captureCapabilities.push_back(cap);
    }
  }
  return _captureCapabilities.size();
}

int32_t DeviceInfoAndroid::GetOrientation(
    const char* deviceUniqueIdUTF8,
    VideoCaptureRotation& orientation) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL ||
      !VideoCaptureImpl::RotationFromDegrees(info->orientation, &orientation)) {
    return -1;
  }
  return 0;
}

void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
                                     int max_fps_to_match,
                                     int* min_mfps, int* max_mfps) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return;
  int desired_mfps = max_fps_to_match * 1000;
  int best_diff_mfps = 0;
  LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
  // Search for best fps range with preference shifted to constant fps modes.
  for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
    int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) +
        abs(info->mfpsRanges[i].second - desired_mfps) +
        (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
    LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" <<
        info->mfpsRanges[i].second << ". Distance: " << diff_mfps;
    if (i == 0 || diff_mfps < best_diff_mfps) {
      best_diff_mfps = diff_mfps;
      *min_mfps = info->mfpsRanges[i].first;
      *max_mfps = info->mfpsRanges[i].second;
    }
  }
}

}  // namespace videocapturemodule
}  // namespace webrtc
<commit_msg>Getting orientation is not working properly. VideoCaptureImpl::RotationFromDegrees returns -1 in case fails not 0. So we need to change the if statement.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_capture/android/device_info_android.h"

#include <algorithm>
#include <sstream>
#include <vector>

#include "json/json.h"
#include "third_party/icu/source/common/unicode/unistr.h"
#include "webrtc/modules/video_capture/android/video_capture_android.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/ref_count.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace videocapturemodule {

// Helper for storing lists of pairs of ints.  Used e.g. for resolutions & FPS
// ranges.
typedef std::pair<int, int> IntPair;
typedef std::vector<IntPair> IntPairs;

static std::string IntPairsToString(const IntPairs& pairs, char separator) {
  std::stringstream stream;
  for (size_t i = 0; i < pairs.size(); ++i) {
    if (i > 0)
      stream << ", ";
    stream << "(" << pairs[i].first << separator << pairs[i].second << ")";
  }
  return stream.str();
}

struct AndroidCameraInfo {
  std::string name;
  bool front_facing;
  int orientation;
  IntPairs resolutions;  // Pairs are: (width,height).
  // Pairs are (min,max) in units of FPS*1000 ("milli-frame-per-second").
  IntPairs mfpsRanges;

  std::string ToString() {
    std::stringstream stream;
    stream << "Name: [" << name << "], MFPS ranges: ["
           << IntPairsToString(mfpsRanges, ':')
           << "], front_facing: " << front_facing
           << ", orientation: " << orientation << ", resolutions: ["
           << IntPairsToString(resolutions, 'x') << "]";
    return stream.str();
  }
};

// Camera info; populated during DeviceInfoAndroid::Initialize() and immutable
// thereafter.
static std::vector<AndroidCameraInfo>* g_camera_info = NULL;

// Set |*index| to the index of |name| in g_camera_info or return false if no
// match found.
static bool FindCameraIndexByName(const std::string& name, size_t* index) {
  for (size_t i = 0; i < g_camera_info->size(); ++i) {
    if (g_camera_info->at(i).name == name) {
      *index = i;
      return true;
    }
  }
  return false;
}

// Returns a pointer to the named member of g_camera_info, or NULL if no match
// is found.
static AndroidCameraInfo* FindCameraInfoByName(const std::string& name) {
  size_t index = 0;
  if (FindCameraIndexByName(name, &index))
    return &g_camera_info->at(index);
  return NULL;
}

// static
void DeviceInfoAndroid::Initialize(JNIEnv* jni) {
  // TODO(henrike): this "if" would make a lot more sense as an assert, but
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine() and
  // Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate() conspire to
  // prevent this.  Once that code is made to only
  // VideoEngine::SetAndroidObjects() once per process, this can turn into an
  // assert.
  if (g_camera_info)
    return;

  g_camera_info = new std::vector<AndroidCameraInfo>();
  jclass j_info_class =
      jni->FindClass("org/webrtc/videoengine/VideoCaptureDeviceInfoAndroid");
  assert(j_info_class);
  jmethodID j_initialize = jni->GetStaticMethodID(
      j_info_class, "getDeviceInfo", "()Ljava/lang/String;");
  jstring j_json_info = static_cast<jstring>(
      jni->CallStaticObjectMethod(j_info_class, j_initialize));

  const jchar* jchars = jni->GetStringChars(j_json_info, NULL);
  icu::UnicodeString ustr(jchars, jni->GetStringLength(j_json_info));
  jni->ReleaseStringChars(j_json_info, jchars);
  std::string json_info;
  ustr.toUTF8String(json_info);

  Json::Value cameras;
  Json::Reader reader(Json::Features::strictMode());
  bool parsed = reader.parse(json_info, cameras);
  if (!parsed) {
    std::stringstream stream;
    stream << "Failed to parse configuration:\n"
           << reader.getFormattedErrorMessages();
    assert(false);
    return;
  }
  for (Json::ArrayIndex i = 0; i < cameras.size(); ++i) {
    const Json::Value& camera = cameras[i];
    AndroidCameraInfo info;
    info.name = camera["name"].asString();
    info.front_facing = camera["front_facing"].asBool();
    info.orientation = camera["orientation"].asInt();
    Json::Value sizes = camera["sizes"];
    for (Json::ArrayIndex j = 0; j < sizes.size(); ++j) {
      const Json::Value& size = sizes[j];
      info.resolutions.push_back(std::make_pair(
          size["width"].asInt(), size["height"].asInt()));
    }
    Json::Value mfpsRanges = camera["mfpsRanges"];
    for (Json::ArrayIndex j = 0; j < mfpsRanges.size(); ++j) {
      const Json::Value& mfpsRange = mfpsRanges[j];
      info.mfpsRanges.push_back(std::make_pair(mfpsRange["min_mfps"].asInt(),
                                               mfpsRange["max_mfps"].asInt()));
    }
    g_camera_info->push_back(info);
  }
}

void DeviceInfoAndroid::DeInitialize() {
  if (g_camera_info) {
    delete g_camera_info;
    g_camera_info = NULL;
  }
}

VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
    const int32_t id) {
  return new videocapturemodule::DeviceInfoAndroid(id);
}

DeviceInfoAndroid::DeviceInfoAndroid(const int32_t id) :
    DeviceInfoImpl(id) {
}

DeviceInfoAndroid::~DeviceInfoAndroid() {
}

bool DeviceInfoAndroid::FindCameraIndex(const char* deviceUniqueIdUTF8,
                                        size_t* index) {
  return FindCameraIndexByName(deviceUniqueIdUTF8, index);
}

int32_t DeviceInfoAndroid::Init() {
  return 0;
}

uint32_t DeviceInfoAndroid::NumberOfDevices() {
  return g_camera_info->size();
}

int32_t DeviceInfoAndroid::GetDeviceName(
    uint32_t deviceNumber,
    char* deviceNameUTF8,
    uint32_t deviceNameLength,
    char* deviceUniqueIdUTF8,
    uint32_t deviceUniqueIdUTF8Length,
    char* /*productUniqueIdUTF8*/,
    uint32_t /*productUniqueIdUTF8Length*/) {
  if (deviceNumber >= g_camera_info->size())
    return -1;
  const AndroidCameraInfo& info = g_camera_info->at(deviceNumber);
  if (info.name.length() + 1 > deviceNameLength ||
      info.name.length() + 1 > deviceUniqueIdUTF8Length) {
    return -1;
  }
  memcpy(deviceNameUTF8, info.name.c_str(), info.name.length() + 1);
  memcpy(deviceUniqueIdUTF8, info.name.c_str(), info.name.length() + 1);
  return 0;
}

int32_t DeviceInfoAndroid::CreateCapabilityMap(
    const char* deviceUniqueIdUTF8) {
  _captureCapabilities.clear();
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return -1;

  for (size_t i = 0; i < info->resolutions.size(); ++i) {
    for (size_t j = 0; j < info->mfpsRanges.size(); ++j) {
      const IntPair& size = info->resolutions[i];
      const IntPair& mfpsRange = info->mfpsRanges[j];
      VideoCaptureCapability cap;
      cap.width = size.first;
      cap.height = size.second;
      cap.maxFPS = mfpsRange.second / 1000;
      cap.expectedCaptureDelay = kExpectedCaptureDelay;
      cap.rawType = kVideoNV21;
      _captureCapabilities.push_back(cap);
    }
  }
  return _captureCapabilities.size();
}

int32_t DeviceInfoAndroid::GetOrientation(
    const char* deviceUniqueIdUTF8,
    VideoCaptureRotation& orientation) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL ||
      VideoCaptureImpl::RotationFromDegrees(info->orientation,
                                            &orientation) != 0) {
    return -1;
  }
  return 0;
}

void DeviceInfoAndroid::GetMFpsRange(const char* deviceUniqueIdUTF8,
                                     int max_fps_to_match,
                                     int* min_mfps, int* max_mfps) {
  const AndroidCameraInfo* info = FindCameraInfoByName(deviceUniqueIdUTF8);
  if (info == NULL)
    return;
  int desired_mfps = max_fps_to_match * 1000;
  int best_diff_mfps = 0;
  LOG(LS_INFO) << "Search for best target mfps " << desired_mfps;
  // Search for best fps range with preference shifted to constant fps modes.
  for (size_t i = 0; i < info->mfpsRanges.size(); ++i) {
    int diff_mfps = abs(info->mfpsRanges[i].first - desired_mfps) +
        abs(info->mfpsRanges[i].second - desired_mfps) +
        (info->mfpsRanges[i].second - info->mfpsRanges[i].first) / 2;
    LOG(LS_INFO) << "Fps range " << info->mfpsRanges[i].first << ":" <<
        info->mfpsRanges[i].second << ". Distance: " << diff_mfps;
    if (i == 0 || diff_mfps < best_diff_mfps) {
      best_diff_mfps = diff_mfps;
      *min_mfps = info->mfpsRanges[i].first;
      *max_mfps = info->mfpsRanges[i].second;
    }
  }
}

}  // namespace videocapturemodule
}  // namespace webrtc
<|endoftext|>


<commit_before>/*
 * LucasCandaePyramidTracker.cpp
 *
 *  Created on: Feb 21, 2013
 *      Author: link
 */

#include "LucasCandaePyramidTracker.hpp"
#include "opencv2/video/tracking.hpp"

const cv::TermCriteria DEFAULT_TERM_CRITERIA = cv::TermCriteria(
		CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 40, 0.001);
const cv::Size DEFAULT_WINDOW_SIZE = cv::Size(21, 21);
const unsigned int DEFAULT_MAX_LEVEL = 3;
const unsigned int DEFAULT_FLAGS = 0;
const double DEFAULT_MIN_EIGENVALUE_THRESHOLD = 1e-4;
const double DEFAULT_MAX_ERROR_THRESHOLD = 500;

LucasCandaePyramidTracker::LucasCandaePyramidTracker() :
		_windowSize(DEFAULT_WINDOW_SIZE), _maxLevel(DEFAULT_MAX_LEVEL), _flags(
				DEFAULT_FLAGS), _minEigenvalueThreshold(
				DEFAULT_MIN_EIGENVALUE_THRESHOLD), _maxErrorThreshold(
				DEFAULT_MAX_ERROR_THRESHOLD), _termCrit(DEFAULT_TERM_CRITERIA) {
}

LucasCandaePyramidTracker::~LucasCandaePyramidTracker() {
	// TODO Auto-generated destructor stub
}

LucasCandaePyramidTracker::LucasCandaePyramidTracker(
		const LucasCandaePyramidTracker &toCopy) :
		_windowSize(toCopy._windowSize), _maxLevel(toCopy._maxLevel), _flags(
				toCopy._flags), _minEigenvalueThreshold(
				toCopy._minEigenvalueThreshold), _maxErrorThreshold(
				toCopy._maxErrorThreshold), _termCrit(toCopy._termCrit) {

}

LucasCandaePyramidTracker::LucasCandaePyramidTracker(const cv::Size &windowSize,
		const unsigned int &maxLevel, const int &flags,
		const cv::TermCriteria &terminationCriteria,
		const double &minEigenvalueThreshold, const double &maxErrorValue):
			_windowSize(windowSize), _maxLevel(maxLevel), _flags(flags),
			_minEigenvalueThreshold(minEigenvalueThreshold),
			_maxErrorThreshold(maxErrorValue), _termCrit(terminationCriteria){

}

FeatureTracker *LucasCandaePyramidTracker::constructCopy()const{
	return new LucasCandaePyramidTracker(*this);
}

void LucasCandaePyramidTracker::trackFeatures(const cv::Mat &oldInput,
		const cv::Mat &newInput,
		std::vector<std::list<cv::Point2f> > &trackedFeatures) {
	std::vector<uchar> status;
	std::vector<float> err; //thou shall not use double instead of float!!
	std::vector<cv::Point2f> oldFeatures(trackedFeatures.size());
	std::vector<cv::Point2f> newFeatures(trackedFeatures.size());
	for (unsigned int i = 0; i < trackedFeatures.size(); ++i) {
		oldFeatures[i] = trackedFeatures[i].front();
	}
	cv::calcOpticalFlowPyrLK(oldInput, newInput, oldFeatures, newFeatures, status,
			err, _windowSize, _maxLevel, _termCrit, _flags,
			_minEigenvalueThreshold);

	for (unsigned i = 0; i < newFeatures.size(); ++i) {
		if (!status[i] || (err[i] > _maxErrorThreshold)) {
			newFeatures.erase(newFeatures.begin() + i);
			//oldFeatures.erase(oldFeatures.begin() + i);
			status.erase(status.begin() + i);
			err.erase(err.begin() + i);
			trackedFeatures.erase(trackedFeatures.begin() + i);
			--i;
		} else {
			trackedFeatures[i].push_front(newFeatures[i]);
		}
	}
}
<commit_msg>Fixed code formatting of LucasCandaePyramidTracker.cpp<commit_after>/*
 * LucasCandaePyramidTracker.cpp
 *
 *  Created on: Feb 21, 2013
 *      Author: link
 */

#include "LucasCandaePyramidTracker.hpp"
#include "opencv2/video/tracking.hpp"

const cv::TermCriteria DEFAULT_TERM_CRITERIA = cv::TermCriteria(
		CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 40, 0.001);
const cv::Size DEFAULT_WINDOW_SIZE = cv::Size(21, 21);
const unsigned int DEFAULT_MAX_LEVEL = 3;
const unsigned int DEFAULT_FLAGS = 0;
const double DEFAULT_MIN_EIGENVALUE_THRESHOLD = 1e-4;
const double DEFAULT_MAX_ERROR_THRESHOLD = 500;

LucasCandaePyramidTracker::LucasCandaePyramidTracker() :
		_windowSize(DEFAULT_WINDOW_SIZE), _maxLevel(DEFAULT_MAX_LEVEL), _flags(
				DEFAULT_FLAGS), _minEigenvalueThreshold(
				DEFAULT_MIN_EIGENVALUE_THRESHOLD), _maxErrorThreshold(
				DEFAULT_MAX_ERROR_THRESHOLD), _termCrit(DEFAULT_TERM_CRITERIA) {
}

LucasCandaePyramidTracker::~LucasCandaePyramidTracker() {
	// TODO Auto-generated destructor stub
}

LucasCandaePyramidTracker::LucasCandaePyramidTracker(
		const LucasCandaePyramidTracker &toCopy) :
		_windowSize(toCopy._windowSize), _maxLevel(toCopy._maxLevel), _flags(
				toCopy._flags), _minEigenvalueThreshold(
				toCopy._minEigenvalueThreshold), _maxErrorThreshold(
				toCopy._maxErrorThreshold), _termCrit(toCopy._termCrit) {

}

LucasCandaePyramidTracker::LucasCandaePyramidTracker(const cv::Size &windowSize,
		const unsigned int &maxLevel, const int &flags,
		const cv::TermCriteria &terminationCriteria,
		const double &minEigenvalueThreshold, const double &maxErrorValue) :
		_windowSize(windowSize), _maxLevel(maxLevel), _flags(flags), _minEigenvalueThreshold(
				minEigenvalueThreshold), _maxErrorThreshold(maxErrorValue), _termCrit(
				terminationCriteria) {

}

FeatureTracker *LucasCandaePyramidTracker::constructCopy() const {
	return new LucasCandaePyramidTracker(*this);
}

void LucasCandaePyramidTracker::trackFeatures(const cv::Mat &oldInput,
		const cv::Mat &newInput,
		std::vector<std::list<cv::Point2f> > &trackedFeatures) {
	std::vector<uchar> status;
	std::vector<float> err; //thou shall not use double instead of float!!
	std::vector<cv::Point2f> oldFeatures(trackedFeatures.size());
	std::vector<cv::Point2f> newFeatures(trackedFeatures.size());
	for (unsigned int i = 0; i < trackedFeatures.size(); ++i) {
		oldFeatures[i] = trackedFeatures[i].front();
	}
	cv::calcOpticalFlowPyrLK(oldInput, newInput, oldFeatures, newFeatures,
			status, err, _windowSize, _maxLevel, _termCrit, _flags,
			_minEigenvalueThreshold);

	for (unsigned i = 0; i < newFeatures.size(); ++i) {
		if (!status[i] || (err[i] > _maxErrorThreshold)) {
			newFeatures.erase(newFeatures.begin() + i);
			//oldFeatures.erase(oldFeatures.begin() + i);
			status.erase(status.begin() + i);
			err.erase(err.begin() + i);
			trackedFeatures.erase(trackedFeatures.begin() + i);
			--i;
		} else {
			trackedFeatures[i].push_front(newFeatures[i]);
		}
	}
}
<|endoftext|>


<commit_before>/* AddRepoWindow.cpp
 * Copyright 2016 Brian Hill
 * All rights reserved. Distributed under the terms of the BSD License.
 */

#include "AddRepoWindow.h"

#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <LayoutBuilder.h>

#include "constants.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "AddRepoWindow"

static float sAddWindowWidth = 500.0;

AddRepoWindow::AddRepoWindow(BRect size, BLooper *looper)
	:
	BWindow(BRect(0,0,sAddWindowWidth,10), "AddWindow", B_MODAL_WINDOW,
		B_ASYNCHRONOUS_CONTROLS	| B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
	fReplyLooper(looper)
{
	fView = new BView("view", B_SUPPORTS_LAYOUT);
	fText = new BTextControl("text", B_TRANSLATE_COMMENT("Depot URL:",
		"Text box label"), "", new BMessage(ADD_BUTTON_PRESSED));
	fAddButton = new BButton(B_TRANSLATE_COMMENT("Add", "Button label"),
		new BMessage(ADD_BUTTON_PRESSED));
	fAddButton->MakeDefault(true);
	fCancelButton = new BButton(kCancelLabel,
		new BMessage(CANCEL_BUTTON_PRESSED));

	BLayoutBuilder::Group<>(fView, B_VERTICAL)
		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
			B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
		.Add(fText)
		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
			.AddGlue()
			.Add(fCancelButton)
			.Add(fAddButton);
	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.Add(fView);
	_GetClipboardData();
	fText->MakeFocus();

	// Move to the center of the preflet window
	CenterIn(size);
	float widthDifference = size.Width() - Frame().Width();
	if(widthDifference < 0)
		MoveBy(widthDifference/2.0, 0);
	Show();
}

void
AddRepoWindow::Quit()
{
	fReplyLooper->PostMessage(ADD_WINDOW_CLOSED);
	BWindow::Quit();
}

void
AddRepoWindow::MessageReceived(BMessage* message)
{
	switch(message->what)
	{
		case CANCEL_BUTTON_PRESSED: {
			if(QuitRequested())
				Quit();
			break;
		}
		case ADD_BUTTON_PRESSED: {
			BString url(fText->Text());
			if(url != "") {
				// URL must have a protocol
				if(url.FindFirst("://") == B_ERROR) {
					BAlert *alert = new BAlert("error",
						B_TRANSLATE_COMMENT("The URL must start with a "
							"protocol, for example http:// or https://",
							"Add URL error message"),
						kOKLabel, NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
					alert->SetFeel(B_MODAL_APP_WINDOW_FEEL);
					alert->Go(NULL);
					// Center the alert to this window and move down some
					alert->CenterIn(Frame());
					alert->MoveBy(0, kAddWindowOffset);
				}
				else {
					BMessage *addMessage = new BMessage(ADD_REPO_URL);
					addMessage->AddString(key_url, url);
					fReplyLooper->PostMessage(addMessage);
					Quit();
				}
			}
			break;
		}
		default:
			BWindow::MessageReceived(message);
	}
}

void
AddRepoWindow::FrameResized(float newWidth, float newHeight)
{
	sAddWindowWidth = newWidth;
}

status_t
AddRepoWindow::_GetClipboardData()
{
	if (be_clipboard->Lock()) {
		const char *string;
		int32 stringLen;
	    BMessage *clip = be_clipboard->Data();
	    clip->FindData("text/plain", B_MIME_TYPE, (const void **)&string,
	        &stringLen);
	    be_clipboard->Unlock();

	    // The string must contain a web protocol
	    BString clipString(string, stringLen);
		int32 ww = clipString.FindFirst("://");
		if(ww == B_ERROR)
			return B_ERROR;
		else
			fText->SetText(clipString);
	}
	return B_OK;
}
<commit_msg>Fix variable type for GCC4<commit_after>/* AddRepoWindow.cpp
 * Copyright 2016 Brian Hill
 * All rights reserved. Distributed under the terms of the BSD License.
 */

#include "AddRepoWindow.h"

#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <LayoutBuilder.h>

#include "constants.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "AddRepoWindow"

static float sAddWindowWidth = 500.0;

AddRepoWindow::AddRepoWindow(BRect size, BLooper *looper)
	:
	BWindow(BRect(0,0,sAddWindowWidth,10), "AddWindow", B_MODAL_WINDOW,
		B_ASYNCHRONOUS_CONTROLS	| B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE),
	fReplyLooper(looper)
{
	fView = new BView("view", B_SUPPORTS_LAYOUT);
	fText = new BTextControl("text", B_TRANSLATE_COMMENT("Depot URL:",
		"Text box label"), "", new BMessage(ADD_BUTTON_PRESSED));
	fAddButton = new BButton(B_TRANSLATE_COMMENT("Add", "Button label"),
		new BMessage(ADD_BUTTON_PRESSED));
	fAddButton->MakeDefault(true);
	fCancelButton = new BButton(kCancelLabel,
		new BMessage(CANCEL_BUTTON_PRESSED));

	BLayoutBuilder::Group<>(fView, B_VERTICAL)
		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
			B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
		.Add(fText)
		.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
			.AddGlue()
			.Add(fCancelButton)
			.Add(fAddButton);
	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.Add(fView);
	_GetClipboardData();
	fText->MakeFocus();

	// Move to the center of the preflet window
	CenterIn(size);
	float widthDifference = size.Width() - Frame().Width();
	if(widthDifference < 0)
		MoveBy(widthDifference/2.0, 0);
	Show();
}

void
AddRepoWindow::Quit()
{
	fReplyLooper->PostMessage(ADD_WINDOW_CLOSED);
	BWindow::Quit();
}

void
AddRepoWindow::MessageReceived(BMessage* message)
{
	switch(message->what)
	{
		case CANCEL_BUTTON_PRESSED: {
			if(QuitRequested())
				Quit();
			break;
		}
		case ADD_BUTTON_PRESSED: {
			BString url(fText->Text());
			if(url != "") {
				// URL must have a protocol
				if(url.FindFirst("://") == B_ERROR) {
					BAlert *alert = new BAlert("error",
						B_TRANSLATE_COMMENT("The URL must start with a "
							"protocol, for example http:// or https://",
							"Add URL error message"),
						kOKLabel, NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
					alert->SetFeel(B_MODAL_APP_WINDOW_FEEL);
					alert->Go(NULL);
					// Center the alert to this window and move down some
					alert->CenterIn(Frame());
					alert->MoveBy(0, kAddWindowOffset);
				}
				else {
					BMessage *addMessage = new BMessage(ADD_REPO_URL);
					addMessage->AddString(key_url, url);
					fReplyLooper->PostMessage(addMessage);
					Quit();
				}
			}
			break;
		}
		default:
			BWindow::MessageReceived(message);
	}
}

void
AddRepoWindow::FrameResized(float newWidth, float newHeight)
{
	sAddWindowWidth = newWidth;
}

status_t
AddRepoWindow::_GetClipboardData()
{
	if (be_clipboard->Lock()) {
		const char *string;
		ssize_t stringLen;
	    BMessage *clip = be_clipboard->Data();
	    clip->FindData("text/plain", B_MIME_TYPE, (const void **)&string,
	        &stringLen);
	    be_clipboard->Unlock();

	    // The string must contain a web protocol
	    BString clipString(string, stringLen);
		int32 ww = clipString.FindFirst("://");
		if(ww == B_ERROR)
			return B_ERROR;
		else
			fText->SetText(clipString);
	}
	return B_OK;
}
<|endoftext|>