text:
//          Copyright Rein Halbersma 2010-2020.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <core/board/group.hpp>                 // action::is_realized, make_group
#include <core/board/sequence.hpp>              // nano, micro, checkers, Roman, spantsiretti, international, frisian, ktar<10, 11>,
                                                // ktar<10, 12>, Compact_10_12, Compact_12_10, basic_board<12, 10>, canadian, srilankan, dumm
#include <dctl/core/board/angle.hpp>            // _deg, inverse, rotate
#include <dctl/core/board/coordinates.hpp>      // operator==, rotate, to_sco
#include <boost/range/irange.hpp>               // irange
#include <boost/test/unit_test.hpp>             // BOOST_AUTO_TEST_SUITE, BOOST_AUTO_TEST_SUITE_END, BOOST_AUTO_TEST_CASE_TEMPLATE, BOOST_CHECK
#include <algorithm>                            // all_of
#include <type_traits>                          // common_type
#include <vector>                               // vector

using namespace dctl::core;
using namespace literals;

BOOST_AUTO_TEST_SUITE(GridCoordinates)

BOOST_AUTO_TEST_CASE_TEMPLATE(GroupActionIsRealizedForAllCyclicGroupsOnAllSquareCoordinates, T, BoardSequence)
{
        constexpr auto op = [](auto i, auto j) { return rotate(i, j); };
        constexpr auto inv = [](auto i) { return inverse(i); };

        auto const C1 = make_group(
                { 0_deg },
                op, inv
        );

        auto const C2 = make_group(
                { 0_deg, 180_deg },
                op, inv
        );

        auto const C4 = make_group(
                { 0_deg,  90_deg, 180_deg, 270_deg },
                op, inv
        );

        using CyclicGroup = std::common_type_t<decltype(C1), decltype(C2), decltype(C4)>;

        auto const C_N = std::vector<CyclicGroup>
        {
                C1, C2, C4
        };

        auto const squares = boost::irange(0, T::size());
        BOOST_CHECK(
                std::all_of(C_N.begin(), C_N.end(), [=](auto const& g) {
                        return std::all_of(squares.begin(), squares.end(), [&](auto i) {
                                auto const coord = to_sco(i, T::inner_grid);
                                return group::action::is_realized(coord, g);
                        });
                })
        );
}

BOOST_AUTO_TEST_SUITE_END()


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

#include <iostream>
#include <string>

#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>

#include <opencv2/highgui.hpp>

#include "Gnomonic.h"

int main(int argc, char **argv) {

	// ------------------------------------------------------------------------------------------------------------------------------------------
	// parse parameters

	namespace po = boost::program_options;

	po::positional_options_description p;
	p.add("input-file", -1);

	po::options_description desc("General options");
	desc.add_options()
		("help", "produce help message")
		("input-file,i", po::value< std::string >(), "Input file to be used by the tool. An image to decompose, or a json configuration file for back projection")
		("output-dir,o", po::value< std::string >(), "Choose which folder will contains the output")
		("width,w", po::value< int >(), "Width of the projected image. (default: 720)")
		("height,h", po::value< int >(), "Height of the projected image. (default: 720)")
		("fov,f", po::value< float >(), "Set size of the FOV (in degree, default: 110).")
		("threads,t", po::value< int >(), "Set the number of threads used by the program while running --decompose. (default: 12).")

		("decompose", "Automatic decomposition of the equirectangular image into several rectilinear images")
		("to-rectilinear", "Perform a single projection from equirectangular to rectilinear domain")
		("to-equirectangular", "Perform a single projection from rectilinear to equirectangular domain")
		("pitch", po::value< int >(), "Value of the pitch for the projection (in degree)")
		("yaw", po::value< int >(), "Value of the yaw for the projection (in degree)")
		("roll", po::value< int >(), "Value of the roll for the projection (in degree)")
		("output-file", po::value< std::string >(), "Choose the output file name (for back projection to equirectangular, or single projections)")
		("average-overlap", "while performing back projection from JSON file, average overalapping images (to be used with saliency map _only_. The channels R and G will be lost in the recomposition.)")
		("equatorial-regions", "Perform the processing --decompose only with a pitch of 0")
	;

	po::variables_map vm;
	try {
		po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
		po::notify(vm);
	} catch(boost::exception &) {
		std::cerr << "Error incorect program options. See --help... \n";
		return 0;
	}

	if (vm.count("help")) {
		std::cout << "--------------------------------------------------------------------------------\n";
		std::cout << "\t\t\t\tGnomonic\n";
		std::cout << "--------------------------------------------------------------------------------\n";
		std::cout << "Tool to perform gnomonic projection between equirectangular - rectilinear images\n";
		std::cout << "--------------------------------------------------------------------------------\n";
		std::cout << "\n";
		std::cout << desc << "\n";
		return 1;
	}

	Gnomonic gnomonic;

	std::string inputFile;
	if (vm.count("input-file")) {
		inputFile = vm["input-file"].as< std::string >();
	} else {
		std::cerr << "It is required to provide an imput file. See --help\n";
		return 0;
	}

	if (vm.count("output-dir")) {
		gnomonic.setOutputDir(vm["output-dir"].as< std::string >());
	}

	if (vm.count("width")) {
		gnomonic.setNrrWidth(vm["width"].as< int >());
	}

	if (vm.count("height")) {
		gnomonic.setNrrHeight(vm["height"].as< int >());
	}

	if (vm.count("fov")) {
		gnomonic.setFOV(vm["fov"].as< float >());
	}

	if (vm.count("threads")) {
		gnomonic.setNbThreads(vm["threads"].as< int >());
	}

	std::string outputFile;
	if(vm.count("output-file")) {
		outputFile = vm["output-file"].as< std::string >();
	}

	if(vm.count("average-overlap")) {
		gnomonic.setAverageOverlap(true);
	}

	if(vm.count("equatorial-regions")) {
		gnomonic.setEquatorialRegion(true);
	}

	// ----------------------------------------------------------------------------------------------------------------
	// start the program

	if(boost::filesystem::extension(inputFile) == ".json") {

		gnomonic.getEquirectangular(inputFile, outputFile);

	} else {
		cv::Mat image = cv::imread(inputFile);
		if(image.empty()) {
			std::cerr << "Cannot open file: " << inputFile << std::endl;
			return 0;
		}

		if(vm.count("to-rectilinear") || vm.count("to-equirectangular")) {
			int pitch = 0;
			int yaw = 0;
			int roll = 0;

			if (vm.count("pitch")) {
				pitch = vm["pitch"].as< int >();
			} else {
				std::cout << "[E] The pitch should be defined, see --help" << std::endl;
				return 0;
			}

			if (vm.count("yaw")) {
				yaw = vm["yaw"].as< int >();
			} else {
				std::cout << "[E] The yaw should be defined, see --help" << std::endl;
				return 0;
			}

			if (vm.count("roll")) {
				roll = vm["roll"].as< int >();
			}

			cv::Mat outputFrame(gnomonic.getHeight(), gnomonic.getWidth(), CV_8UC3, cv::Scalar(0,0,0));

			if(vm.count("to-rectilinear")) {
				gnomonic.equirectangularToRectilinear(image, outputFrame, yaw, pitch, roll);
			} else {
				gnomonic.rectilinearToEquirectangular(image, outputFrame, yaw, pitch, roll);
			}

			cv::imwrite(outputFile, outputFrame);

		} else {
			gnomonic.getRectilinearFrames(image, inputFile);
		}

	}

	return 0;
}

ext: cpp

max_stars_repo_licenses: MIT Unlicense

max_issues_repo_licenses: MIT Unlicense

max_forks_repo_licenses: MIT Unlicense


text:
///
/// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com)
///
/// Distributed under the Boost Software License, Version 1.0. (See accompanying
/// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
///
/// See https://github.com/lordoffox/amsg for latest version.
///

#include <amsg/all.hpp>
#include <boost/assert.hpp>
#include <iostream>

namespace usr
{
  struct msg_header_fix
  {
    boost::int32_t size;
    boost::int32_t type;
  };

  struct msg_header
  {
    boost::int32_t size;
    boost::int32_t type;
  };
}

AMSG(usr::msg_header_fix, (size&sfix)(type&sfix));
AMSG(usr::msg_header, (size)(type));

int main()
{
  try
  {
    usr::msg_header_fix src_fix;
    src_fix.size = 4;
    src_fix.type = 1;

    std::size_t size = amsg::size_of(src_fix);
    BOOST_ASSERT(size == sizeof(boost::int32_t) * 2);

    usr::msg_header src;
    src.size = 4;
    src.type = 1;

    size = amsg::size_of(src);
    BOOST_ASSERT(size == sizeof(boost::int8_t) * 2);
  }
  catch (std::exception& ex)
  {
    std::cerr << ex.what() << std::endl;
  }
  return 0;
}

max_stars_repo_name: nousxiong/amsg

max_issues_repo_name: nousxiong/amsg

max_forks_repo_name: nousxiong/amsg


text:
#include <map>
#include <vector>
#include <iostream>
#include <iomanip>
#include <boost/multiprecision/cpp_bin_float.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

#include "DatasetAR.h"
#include "DatasetARX.h"
#include "GaussSeq.h"
#include "ARSeq.h"
#include "utils.h"

using utils::my_float;

int main() {
    using boost::multiprecision::cpp_bin_float_50;
    using boost::random::uniform_real_distribution;

    // Dataset write
    DatasetARX dat_1("testing_one_background", 1);
    DatasetARX dat_2("testing_two_background", 2);
    DatasetARX dat_2_2("testing_two_background_2", 2);
    DatasetARX dat_3("testing_three_background", 3);
    DatasetARX dat_3_2("testing_three_background_2", 3);
    DatasetARX dat_4("testing_four_background", 4);
    DatasetARX dat_4_2("testing_four_background_2", 4);

    dat_1.write_csv();
    dat_2.write_csv();
    dat_2_2.write_csv();
    dat_3.write_csv();
    dat_3_2.write_csv();
    dat_4.write_csv();
    dat_4_2.write_csv();

    return 0;
}


text:
#include <boost/asio.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/make_shared.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread.hpp>
#include <fstream>
#include <glog/logging.h>
#include <list>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "allocation_wrapper.h"

#include "mpi.h"
#include "MPIChannel.h"

bool MPILink::query(MPI::Request &req) {
  boost::lock_guard<MPILink> guard(*this);
  return req.Test();
}

void MPILink::send(MPI::Intercomm comm,
    const void* buf,
    int count, const MPI::Datatype& datatype,
    int dest, int tag
) {
  MPI::Request req;
  {
    boost::lock_guard<MPILink> guard(*this);
    req = comm.Isend(buf, count,
        datatype, dest, tag);
    DLOG_IF(INFO, VLOG_IS_ON(4)) << "Send to " << dest
               << " from " << MPI::COMM_WORLD.Get_rank()
               << " tag: " << tag;
  }
  while (!query(req)) {
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
  }
}

void MPILink::recv(MPI::Intercomm comm, void* buf,
    int count, const MPI::Datatype& datatype,
    int source, int tag
) {
  MPI::Request req;
  {
    boost::lock_guard<MPILink> guard(*this);
    req = comm.Irecv(buf, count,
        datatype, source, tag);

    DLOG_IF(INFO, VLOG_IS_ON(4)) << "Recv from " << source
               << " to " << MPI::COMM_WORLD.Get_rank()
               << " tag: " << tag;
  }
  while (!query(req)) {
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
  }
}

int Channel::counter_ = 0;

Channel::Channel(MPILink* link):
  link_(link),
  is_send_finished_(false),
  is_recv_finished_(false)
{
  // accumulate the class id
  id_ = counter_;
  counter_++;

  rank_  = MPI::COMM_WORLD.Get_rank();
  nproc_ = MPI::COMM_WORLD.Get_size();

#if 0 // removed and re-enable later
  /* Register/broadcast senders:
   * all procs enter, and communicate who are the senders of this Channel
   */
  std::vector<int> sender_list;
  std::vector<int> receiver_list;

  for (int p = 0; p < nproc_; p++) {
    // no matter if p == rank_ at this point, cause is_p_sender
    // would be overwritten if p != rank
    int is_p_sender = is_sender ? 1 : 0;

    MPI::COMM_WORLD.Bcast(&is_p_sender, 1, MPI::INT, p);

    if (is_p_sender) {
      sender_list.push_back(p);
    }
    else {
      receiver_list.push_back(p);
    }
  }

  // create mpi group and communicators
  MPI::Group world_group = MPI::COMM_WORLD.Get_group();
  MPI::Group send_group = world_group.Incl(sender_list.size(), &sender_list[0]);
  MPI::Group recv_group = world_group.Incl(receiver_list.size(), &receiver_list[0]);

  send_comm_ = MPI::COMM_WORLD.Create(send_group);
  recv_comm_ = MPI::COMM_WORLD.Create(recv_group);

  num_send_ = send_comm_.Get_size();
  num_recv_ = recv_comm_.Get_size();

  if (is_sender) {
    g_rank_  = send_comm_.Get_rank();
  }
  else {
    g_rank_  = recv_comm_.Get_rank();
  }
#endif
}

int Channel::getTag(Msg m) {
  int tag = ((int)Msg::MsgMax+1)*id_ + (int)m;
  return tag;
}

SourceChannel::SourceChannel(MPILink* link,
    int source_rank,
    bool send_to_source):
  Channel(link),
  source_rank_(source_rank)
{
  for (int p = 0; p < nproc_; p++) {
    if (send_to_source || p != source_rank) {
      active_receiver_.insert(p);
    }
  }
}

// dispatch data to receivers of this channel
void SourceChannel::send(const char* data, int length) {
  // pid of the requester
  int req_id = -1;

  link_->recv(MPI::COMM_WORLD, &req_id, 1,
      MPI::INT, MPI::ANY_SOURCE, getTag(Msg::req));
  link_->send(MPI::COMM_WORLD, &length, 1,
      MPI::INT, req_id, getTag(Msg::length));
  link_->send(MPI::COMM_WORLD, data, length,
      MPI::CHAR, req_id, getTag(Msg::data));
}

void SourceChannel::retire() {
  if (rank_ != source_rank_) {
    throw std::runtime_error("unexpected caller of finish()");
  }

  for (auto p : active_receiver_) {
  //for (int p = 0; p < nproc_; p++) {
    int proc_id = 0;
    int length = 0;
    link_->recv(MPI::COMM_WORLD, &proc_id, 1,
        MPI::INT, MPI::ANY_SOURCE, getTag(Msg::req));

    // Send finish signal to child-process
    link_->send(MPI::COMM_WORLD, &length, 1,
        MPI::INT, p, getTag(Msg::length));
  }
  is_send_finished_ = true;
}

void* SourceChannel::recv(int & length) {

  link_->send(MPI::COMM_WORLD, &rank_, 1,
      MPI::INT, source_rank_, getTag(Msg::req));

  //DLOG_IF(INFO, VLOG_IS_ON(2)) << __func__ << ":" << "receiving from " << source_rank_;

  link_->recv(MPI::COMM_WORLD, &length, 1,
      MPI::INT, source_rank_, getTag(Msg::length));

  if (length > 0) {
    // allocate return buffer for data
    // allow one extra 0 for c strings
    void* data = calloc(length+1, 1);

    link_->recv(MPI::COMM_WORLD, data, length,
        MPI::CHAR, source_rank_, getTag(Msg::data));

    return data;
  }
  else {
    is_recv_finished_ = true;
    return NULL;
  }
}

SinkChannel::SinkChannel(MPILink* link,
    int sink_rank,
    bool recv_from_sink):
  Channel(link),
  sink_rank_(sink_rank)
{
  for (int p = 0; p < nproc_; p++) {
    if (recv_from_sink || p != sink_rank) {
      active_senders_.insert(p);
    }
  }
}

void SinkChannel::send(const char* data, int length) {
  link_->send(MPI::COMM_WORLD, &rank_, 1,
      MPI::INT, sink_rank_, getTag(Msg::req));
  DLOG_IF(INFO, VLOG_IS_ON(2)) << __func__ << ":" << "sending to " << sink_rank_;
  link_->send(MPI::COMM_WORLD, &length, 1,
      MPI::INT, sink_rank_, getTag(Msg::length));
  link_->send(MPI::COMM_WORLD, data, length,
      MPI::CHAR, sink_rank_, getTag(Msg::data));
}

void* SinkChannel::recv(int & length) {
  if (active_senders_.empty()) return NULL;

  // non-blocking query for tasks
  int req_id = 0;
  link_->recv(MPI::COMM_WORLD, &req_id, 1, MPI::INT, MPI::ANY_SOURCE, getTag(Msg::req));
  //DLOG_IF(INFO, VLOG_IS_ON(2)) << __func__ << ":" << "receiving from " << req_id;

  link_->recv(MPI::COMM_WORLD, &length, 1, MPI::INT, req_id, getTag(Msg::length));
  while (length == 0) {
    active_senders_.erase(req_id);
    if (active_senders_.empty()) break;
    link_->recv(MPI::COMM_WORLD, &req_id, 1, MPI::INT, MPI::ANY_SOURCE, getTag(Msg::req));
    link_->recv(MPI::COMM_WORLD, &length, 1, MPI::INT, req_id, getTag(Msg::length));
  }
  if (active_senders_.empty()) {
    is_recv_finished_ = true;
    return NULL;
  }
  else {
    // allocate return buffer for data
    // allow one extra 0 for c strings
    void* data = calloc(length+1, 1);

    link_->recv(MPI::COMM_WORLD, data, length, MPI::CHAR, req_id, getTag(Msg::data));

    return data;
  }
}

void SinkChannel::retire() {
  //DLOG(INFO) << "Retiring sender " << rank_;
  int length = 0;
  link_->send(MPI::COMM_WORLD, &rank_, 1, MPI::INT, sink_rank_, getTag(Msg::req));
  link_->send(MPI::COMM_WORLD, &length, 1, MPI::INT, sink_rank_, getTag(Msg::length));

  is_send_finished_ = true;
}

max_stars_repo_name: falcon-computing/bwa-flow

max_issues_repo_name: falcon-computing/bwa-flow

max_forks_repo_name: falcon-computing/bwa-flow


text:
/*
 * tms_ts_nodelet.hpp
 *
 *  Created on: 2013/10/01
 *      Author: hashiguchi
 */

#ifndef TMS_TS_NODELET_HPP_
#define TMS_TS_NODELET_HPP_

#include <ros/ros.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <assert.h>

#include <sstream>
#include <fstream>
#include <boost/date_time/local_time/local_time.hpp>
#include <time.h>

#include <nodelet/nodelet.h>
#include <pluginlib/class_list_macros.h>

#include <tms_msg_ts/ts_req.h>        // from UR
#include <tms_msg_db/TmsdbGetData.h>  // to DB

namespace tms_ts_nodelet
{
class ROS_TMS_TS : public nodelet::Nodelet
{
public:
  ROS_TMS_TS()
    : sid(100000)
    , robot_id(0)
    , object_id(0)
    , user_id(0)
    , place_id(0)
    , import("#!/usr/bin/env python\n\n"
             "import roslib; roslib.load_manifest('tms_ts_smach')\n"
             "import rospy\n"
             "import smach\n"
             "import smach_ros\n\n"
             "from smach_ros import ServiceState\n"
             "from smach import Concurrence\n\n"
             "from tms_msg_rp.srv import *\n"
             "from tms_msg_ts.srv import *\n\n")
    , main_function1("def main():\n"
                     "    rospy.init_node('tms_ts_smach_executive")
    , main_function2("')\n\n"
                     "    sm_root = smach.StateMachine(['succeeded','aborted','preempted'])\n\n"
                     "    with sm_root:\n\n")
    , introspection_server("    sis = smach_ros.IntrospectionServer('tms_ts_smach_test',"
                           " sm_root, '/ROS_TMS')\n"
                           "    sis.start()\n\n"
                           "    outcome = sm_root.execute()\n\n"
                           "    rospy.spin()\n"
                           "    sis.stop()\n\n"
                           "if __name__ == '__main__':\n"
                           "    main()\n")
  {
  }

private:
  virtual void onInit();

  std::string rosCheckTime(boost::posix_time::ptime time);

  std::string IntToString(int number);
  int StringToInt(std::string str);

  std::string BoolToString(bool b);

  int ArrayPush(std::string *stack, std::string data, int *sp, size_t n);
  std::string ArrayPop(std::string *stack, int *sp);

  int ConvertArgType(std::string arg_type);
  int JudgeArgType(std::string state1, std::string state2);
  void GenerateContainer(std::string f_name, std::string state_name1, std::string state_name2);
  int GenerateCC(std::string state1, std::string state2, int cc_count);
  int AddOneStateSQ(std::string state1);
  int AddStateCC(int cc_count, int sub_count);
  int BuildStateVector(std::string state1, std::string state2);
  int AddStateSQ(std::string state1, std::string state2);
  void GenerateScript(void);

  bool ExeScript(void);

  bool tsCallback(tms_msg_ts::ts_req::Request &req, tms_msg_ts::ts_req::Response &res);
  static int count_callback;

  const int sid;
  int robot_id;
  int object_id;
  int user_id;
  int place_id;

  const std::string import;
  const std::string main_function1, main_function2;
  const std::string introspection_server;

  struct StateData
  {
    int state_id;
    std::string state_name;
    std::vector< int > arg;
    int cc_subtasks;  // num of CC subtasks
  };

  std::vector< StateData > state_data;

  std::string file_name;
  std::string generated_container;
  std::string generated_main;

  ros::ServiceServer service;           // connect to UR
  ros::ServiceClient db_reader_client;  // connect to DB
};

PLUGINLIB_DECLARE_CLASS(tms_ts_nodelet, ROS_TMS_TS, tms_ts_nodelet::ROS_TMS_TS, nodelet::Nodelet);
}

#endif /* ROS_TMS_TS_NODELET_HPP_ */

ext: hpp


text:
// Implementation of the GCPR 2016 Paper "Joint Object Pose Estimation and
// Shape Reconstruction in Urban Street Scenes Using 3D Shape Priors" by Engelmann et al.
// Copyright (C) 2016  Francis Engelmann - Visual Computing Institute RWTH Aachen University
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// C/C++ includes
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <string>
#include <iostream>
#include <fstream>
#include <string>

// Boost includes
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

// OpenCV incudes
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/contrib/contrib.hpp>

// Own includes
#include "utils.h"

namespace gvl {

double jet_interpolate( double val, double y0, double x0, double y1, double x1 ) {
    return (val-x0)*(y1-y0)/(x1-x0) + y0;
}

double jet_base( double val ) {
    if ( val <= -0.75 ) return 0;
    else if ( val <= -0.25 ) return jet_interpolate( val, 0.0, -0.75, 1.0, -0.25 );
    else if ( val <= 0.25 ) return 1.0;
    else if ( val <= 0.75 ) return jet_interpolate( val, 1.0, 0.25, 0.0, 0.75 );
    else return 0.0;
}

double jet_red( double gray ) {
    return jet_base( gray - 0.5 );
}
double jet_green( double gray ) {
    return jet_base( gray );
}
double jet_blue( double gray ) {
    return jet_base( gray + 0.5 );
}

void imshow(const std::string &windowName, const cv::Mat &image)
{
  double mmin, mmax;
  cv::Mat temp;
  cv::minMaxIdx(image, &mmin, &mmax);
  image.convertTo(temp,CV_8UC1, 255 / (mmax-mmin), -mmin*255 / (mmax-mmin));
  cv::applyColorMap(temp, temp, cv::COLORMAP_JET);
  cv::imshow(windowName, temp);
}

Eigen::Vector3d applyJetColorMap(double v) {
  return Eigen::Vector3d(jet_red(v), jet_green(v), jet_blue(v));
}

cv::Mat generateColorMap(const cv::Mat &image)
{
  double mmin, mmax;
  cv::Mat temp;
  cv::minMaxIdx(image, &mmin, &mmax);
  image.convertTo(temp,CV_8UC1, 255.0 / (mmax-mmin), -mmin*255.0 / (mmax-mmin));
  cv::applyColorMap(temp, temp, cv::COLORMAP_JET);
  return temp;
}

void generateColor(unsigned int id, float* color)
{
  if (id%10 == 0) { color[0] = 240; color[1] = 62; color[2] = 36;}
  if (id%10 == 1) { color[0] = 245; color[1] = 116; color[2] = 32;}
  if (id%10 == 2) { color[0] = 251; color[1] = 174; color[2] = 24;}
  if (id%10 == 3) { color[0] = 213; color[1] = 223; color[2] = 38;}
  if (id%10 == 4) { color[0] = 153; color[1] = 204; color[2] = 112;}
  if (id%10 == 5) { color[0] = 136; color[1] = 201; color[2] = 141;}
  if (id%10 == 6) { color[0] = 124; color[1] = 201; color[2] = 169;}
  if (id%10 == 7) { color[0] = 100; color[1] = 199; color[2] = 230;}
  if (id%10 == 8) { color[0] = 64; color[1] = 120; color[2] = 188;}
  if (id%10 == 9) { color[0] = 61; color[1] = 88; color[2] = 167;}
}

void generateColor(const unsigned int id, unsigned char* r, unsigned char* g, unsigned char *b)
{
  float color[3];
  generateColor(id,color);
  *r = color[0];
  *g = color[1];
  *b = color[2];
}

Eigen::Vector3f generateColor(unsigned int id) {
  float c[3];
  generateColor(id,c);
  Eigen::Vector3f color;
  color[0] = c[0];
  color[1] = c[1];
  color[2] = c[2];
  return color;
}

std::string extractFilename(const std::string &path)
{
  std::string filename = path;
  size_t slashPosition = filename.rfind('/');
  if (slashPosition != std::string::npos) filename.erase(0, slashPosition+1);
  size_t dotPosition = filename.rfind('.');
  if (dotPosition != std::string::npos) filename.erase(dotPosition);
  return filename;
}

std::string getTimestamp()
{
  time_t rawtime;
  struct tm * timeinfo;
  char buffer[80];

  time (&rawtime);
  timeinfo = localtime(&rawtime);

  strftime(buffer,80,"%d-%m-%Y_%I:%M:%S",timeinfo);
  std::string timestamp(buffer);

  return timestamp;
}

std::string zfill(int input, int length) {
  std::string result = std::to_string(input);
  size_t n = length-result.length();
  result = std::string (n, '0') + result;
  return result;
}

void plot(std::vector<double> values) {
  cv::Mat img(500,500,CV_8UC3,cv::Scalar(255,255,255));
  cv::imshow("plot", img);
  cv::waitKey(0);
}

void populate_neighborhood(std::vector<Eigen::Vector3i>& n_ids) {
  n_ids.clear();
  n_ids.reserve(8);
  n_ids.push_back(Eigen::Vector3i(0,0,0));
  n_ids.push_back(Eigen::Vector3i(0,0,1));
  n_ids.push_back(Eigen::Vector3i(0,1,0));
  n_ids.push_back(Eigen::Vector3i(1,0,0));
  n_ids.push_back(Eigen::Vector3i(1,0,1));
  n_ids.push_back(Eigen::Vector3i(0,1,1));
  n_ids.push_back(Eigen::Vector3i(1,1,0));
  n_ids.push_back(Eigen::Vector3i(1,1,1));
}

gvl::BoundingBox computeBoundingboxFromDetection(const gvl::Detection& detection, const Eigen::Vector3f& color) {
  gvl::BoundingBox bb;
  bb.height = 1.7;
  bb.width = 2.0;
  bb.length = 4.5;
  bb.x = detection.translation[0];
  bb.y = detection.translation[1];
  bb.z = detection.translation[2];
  bb.rotation_y = detection.rotation_y;
  bb.r = color[0]/255;
  bb.g = color[1]/255;
  bb.b = color[2]/255;
  bb.score = 1.0;
  return bb;
}

void show_poses(std::vector<Eigen::Matrix4d>& poses) {
  std::vector<Eigen::Vector2d> proj(poses.size());
  int min_x=INT_MAX, min_y=INT_MAX;
  int max_x=INT_MIN, max_y=INT_MIN;
  for (auto P : poses) {
    Eigen::Vector4d o(0,0,0,1);
    Eigen::Vector4d o_t = P*o; o_t/=o_t[3];
    Eigen::Vector2d pr(o_t[0], o_t[2]);
    if (pr[0] < min_x) min_x = pr[0];
    if (pr[0] > max_x) max_x = pr[0];
    if (pr[1] < min_y) min_y = pr[1];
    if (pr[1] > max_y) max_y = pr[1];
    proj.push_back(pr);
  }
  int width = std::max(max_x-min_x, 200);
  int height = std::max(max_y-min_y, 200);
  cv::Mat pose_fig(height, width, CV_8UC1, cv::Scalar(255));
  for (auto p : proj) {
    int x = std::round(p[0])+100;
    int y = std::round(p[1])+100;
    pose_fig.at<uint8_t>(y,x)=0.0;
  }
  cv::imshow("Poses",pose_fig);
  cv::waitKey(0);
}

void remove_road_plane_from_pointcloud(gvl::Pointcloud& pointcloud,
                                       Eigen::Vector4d road_plane,
                                       gvl::Pointcloud& pointcloud_filtered) {
  pointcloud_filtered.points.reserve(pointcloud.points.size());
  double &a = road_plane[0];
  double &b = road_plane[1];
  double &c = road_plane[2];
  double &d = road_plane[3];
  gvl::Point p_zero;
  for (unsigned int i=0; i<pointcloud.points.size(); i++) {
    auto& p = pointcloud.points.at(i);
    double dist2groundplane = a*p.x + b*p.y + c*p.z + d;
    double distance2camera = p.x*p.x + p.z*p.z;
    if (dist2groundplane < 3 &&
        dist2groundplane > 0.1 &&
        distance2camera  < lambda_dist2cam*lambda_dist2cam) {
      pointcloud_filtered.points.push_back(p);
    } else{
      p_zero.u=p.u;
      p_zero.v=p.v;
      pointcloud_filtered.points.push_back(p_zero);
    }
  }
}

void keep_road_plane_from_pointcloud(gvl::Pointcloud& pointcloud,
                                       Eigen::Vector4d road_plane,
                                       gvl::Pointcloud& pointcloud_filtered) {
  pointcloud_filtered.points.reserve(pointcloud.points.size());
  double &a = road_plane[0];
  double &b = road_plane[1];
  double &c = road_plane[2];
  double &d = road_plane[3];
  gvl::Point p_zero;
  for (unsigned int i=0; i<pointcloud.points.size(); i++) {
    auto& p = pointcloud.points.at(i);
    double dist2groundplane = a*p.x + b*p.y + c*p.z + d;
    double distance2camera = p.x*p.x + p.z*p.z;
    if (dist2groundplane < 0.1 &&
        distance2camera  < 20*20) {
      pointcloud_filtered.points.push_back(p);
    } else{
      p_zero.u=p.u;
      p_zero.v=p.v;
      pointcloud_filtered.points.push_back(p_zero);
    }
  }
}

void extract_points_to_detection(cv::Mat& color_image,
                                 gvl::Pointcloud& pointcloud_scene,
                                 gvl::Detection& detection,
                                 Eigen::Matrix4d& pose,
                                 double distance_threshold) {

  // Pose is the current position of the camere where color_image was recorded
  // Pointcloud_scene is already in world coordinates

  detection.pointcloud->points.clear();
  // Iterate over 2D rectangle of detection boundingbox
  auto bb = detection.boundingbox;
  auto t = detection.translation;
  for (int v=bb->top; v<bb->bottom; v++) {
    for (int u=bb->left; u<bb->right; u++) {
      int index = v*color_image.cols + u; // compute pointcloud index of current pixel
      gvl::Point p = pointcloud_scene.points.at(index); // get 3d point
      //std::cout << "ndex " << index << " p=" << p.x << std::endl;

      if (std::abs(p.x-pose(0,3)) < 1 &&
          std::abs(p.y-pose(1,3)) < 1 &&
          std::abs(p.z-pose(2,3)) < 1) continue; // ignore of point is close to position of recording camera, TODO: what does zero mean?
      // in the following only consider points within a radius of 5m to orginal detection translation

      Eigen::Vector3d poi(p.x, p.y, p.z);
      double squaredDistance = (poi-t).transpose() * (poi-t);
      //if ( gvl::computeSquaredDistance(p, gvl::Point(t[0], t[1], t[2])) > bb->z + 5 ) continue;
      if (squaredDistance > distance_threshold*distance_threshold) continue;
      detection.pointcloud->points.push_back(p);
      //pointcloud_scene.points.at(index).x = 0;
      //pointcloud_scene.points.at(index).y = 0;
      //pointcloud_scene.points.at(index).z = 0;
      // Color segmented points in original image
      //color_image.at<cv::Vec3b>(v,u) = color_image.at<cv::Vec3b>(v,u)/2.0 + cv::Vec3b(0,0,255);
    }
  }
  //cv::imshow("color image", color_image);
  //cv::waitKey(0);
}

void remove_cars_from_pointcloud(cv::Mat& cars_depth,
                                 gvl::Pointcloud& pointcloud_scene) {

  // Iterate over 2D rectangle of detection boundingbox
  for (int v=0; v<cars_depth.rows; v++) {
    for (int u=0; u<cars_depth.cols; u++) {
      int index = v*cars_depth.cols + u; // compute pointcloud index of current pixel
      if ( cars_depth.at<cv::Vec3d>(v,u)[0] != 0 ||
            cars_depth.at<cv::Vec3d>(v,u)[1] != 0 ||
            cars_depth.at<cv::Vec3d>(v,u)[2] != 0) {
        pointcloud_scene.points.at(index).x = 0;
        pointcloud_scene.points.at(index).y = 0;
        pointcloud_scene.points.at(index).z = 0;
      }
    }
  }
}

void draw_2d_detections(cv::Mat &image_2, std::vector<gvl::BoundingBox> &detections, bool tracking) {
  for (auto & d : detections) {
    if (tracking) {
      int& trackId = d.trackId;
      Eigen::Vector3f color = (trackId>-1) ? gvl::generateColor(trackId) : Eigen::Vector3f(255,255,255);
      int lineWith = (trackId>-1) ? 4:1;
      cv::rectangle(image_2,cv::Point(d.left, d.top),
                            cv::Point(d.right, d.bottom),
                            cv::Scalar(color[2],color[1],color[0]), lineWith);
      if (trackId==-1) continue; // do not draw track id if detection is not assigned to a track
      cv::putText(image_2, std::to_string(trackId),
                  cv::Point(d.left+2, d.bottom-5), // position
                  cv::FONT_HERSHEY_SCRIPT_SIMPLEX, // font face
                  1, // font scale
                  cv::Scalar(color[2],color[1],color[0]), // color
                  3, // thickness
                  8);
    } else {
      int lineWidth = 4;
      cv::rectangle(image_2,cv::Point(d.left, d.top),
                            cv::Point(d.right, d.bottom),
                            cv::Scalar(255*d.score,0*d.score,0*d.score), lineWidth);
    }
  }
}

void show_2d_detections(cv::Mat &image_2, std::vector<gvl::BoundingBox> &detections) {
  cv::Mat det = image_2.clone();
  draw_2d_detections(det, detections);
  cv::imshow("2D Detections", det);
  cv::waitKey(0);
}

}

/*std::cout << "Loading V, S, mean matrices..." << std::endl;
gvl::readMatrixFromFile("/Users/francis/S_new.matrix", S); // "good" originates from the subset of valid cars
gvl::readMatrixFromFile("/Users/francis/mean_shape_new.matrix", mean);
gvl::readMatrixFromFile("/Users/francis/V_new.matrix", V);
//gvl::readMatrixFromSharedMemory("MySharedMemory", "V_new", V);

std::cout << "V: " << V.rows() << "x" << V.cols() << std::endl;
std::cout << "S: " << S.rows() << "x" << S.cols() << std::endl;
std::cout << "mean: " << mean.rows() << "x" << mean.cols() << std::endl;

Eigen::MatrixXd data(p,1);
gvl::readMatrixFromFile("/Users/francis/Downloads/models/tsdfs/AlfaRomeo_Brera_100000_values.tsdf",data);

//Eigen::MatrixXd Y = V_test*V_test.transpose()*data_matrix.block<1,p>(1,0) + mean;
//Eigen::MatrixXd Vr = V;//.block<p,9>(0,0);
Eigen::MatrixXd x = data - mean;// mean is already substracted
Eigen::MatrixXd z = V.transpose() * x;
Eigen::MatrixXd y = V * z + mean;
//std::cout << z << std::endl;
gvl::Visualization vis2(800,800);
vis2.addAxes();
vis2.addZeroSurfaceFromGrid(y, Eigen::Matrix4d::Identity(), Eigen::Vector3f(0,200 ,0));
vis2.show();
return 0;*/

// Project proposals bounding box to ground -----------------------------------------------------
/*int proj_width =  1000;
int proj_height = 1000;
double scaling = 20;
cv::Mat projection_value(proj_height, proj_width, CV_64F, cv::Scalar(0) );
cv::Mat projection_count(proj_height, proj_width, CV_64F, cv::Scalar(0) );
for (auto bb : bounding_boxes) {

  int bb_x_start = std::round((bb->x - bb->width)*scaling);
  int bb_x_end = std::round((bb->x + bb->width)*scaling);
  int bb_z_start = std::round((bb->z - bb->length)*scaling);
  int bb_z_end = std::round((bb->z + bb->length)*scaling);

  // Iterate over pixels that are inside projection of bb
  for (int x=bb_x_start; x<bb_x_end; x++){
    for (int z=bb_z_start; z<bb_z_end; z++){
      int u = x + proj_width/2.0;
      int v = proj_height - z;
      // Only draw if inside image bounds
      if (u < proj_width && u > 0 && v < proj_height && v > 0) {
        projection_value.at<double>(v,u) += (bb->score);
        projection_count.at<double>(v,u) += 1.0;
      }
    }
  }
}*/

// Create ground plane projection of proposals pointcloud ---------------------------------------
/*auto prop_cloud(std::make_shared<gvl::Pointcloud>());
{
  double mmin, mmax;
  cv::Mat temp;
  cv::Mat proj_norm = projection_value;///projection_count;

  cv::minMaxIdx(proj_norm, &mmin, &mmax);
  proj_norm.convertTo(temp,CV_8UC1, 255 / (mmax-mmin), -mmin*255 / (mmax-mmin));
  cv::applyColorMap(temp, temp, cv::COLORMAP_JET);

  for (int v=0; v<projection_value.rows; v++) {
    for (int u=0; u<projection_value.cols; u++) {
       gvl::Point p;
       p.x = (u - proj_width/2.0)/scaling;
       p.y = (-d-a*p.x-c*p.z)/b;
       p.z = (proj_height - v)/scaling;
       p.r = 255-temp.at<cv::Vec3b>(v,u)[0];
       p.g = 255-temp.at<cv::Vec3b>(v,u)[1];
       p.b = 255-temp.at<cv::Vec3b>(v,u)[2];
       prop_cloud->points.push_back(p);
    }
  }
}*/

// Read groundtruth annotations

//cv::Mat proj_count = gvl::generateColorMap(projection_count);
//cv::Mat proj_value = gvl::generateColorMap(projection_value);
//cv::Mat proj_norm = gvl::generateColorMap(projection_value/projection_count);

//cv::Mat proj_gt(proj_height,proj_width,CV_8UC3, cv::Scalar(255, 255, 100));
//proj_gt.at<cv::Vec3b>(50, 50) = cv::Vec3b(0, 0, 0);

// Iterate over the object image, add 3d points to car-pointcloud
/*  for (int v=0; v<obj_map.rows; v++) {
  for (int u=0; u<obj_map.cols; u++) {
    int id = obj_map.at<uchar>(v,u);
    if (id==0) continue; // not a valid label
    std::shared_ptr<gvl::Car> car;
    try {
      car = cars.at(id);
    } catch (const std::out_of_range& oor) {
      car = std::make_shared<gvl::Car>();
      cars[id] = car;
    }

    { // Groundtruth disparity
      double disp = (uint16_t)disparity_gt.at<unsigned short>(v,u)/256.0;
      if (disp == 0) continue;
      double depth = (baseline*f)/disp;

      gvl::Point point;
      point.x = (u - c_x)/f*depth;
      point.y = (v - c_y)/f*depth;
      point.z = depth;
      gvl::generateColor(id, &point.r, &point.g, &point.b);
      car->pointcloud_gt->points.push_back(point);

    }

    { // Estimated disparity
      double disp = (uint16_t)disparity.at<unsigned short>(v,u)/256.0;
      if (disp == 0) continue;

      gvl::Point point;
      point.x = vertices.at<cv::Vec3d>(v,u)[0];
      point.y = vertices.at<cv::Vec3d>(v,u)[1];
      point.z = vertices.at<cv::Vec3d>(v,u)[2];
      gvl::generateColor(id, &point.r, &point.g, &point.b);
      car->pointcloud->points.push_back(point);
    }
  }
}*/

max_stars_repo_name: davidstutz/daml-shape-completion

max_issues_repo_name: jtpils/aml-improved-shape-completion

max_forks_repo_name: jtpils/aml-improved-shape-completion


text:
#include "phase_limiter/auto_mastering.h"

#include <cmath>
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <fstream>
#include <mutex>
#include "gflags/gflags.h"
#include "picojson.h"
#include "tbb/tbb.h"
#include <optim.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include "bakuage/sound_quality2.h"
#include "bakuage/ms_compressor_filter.h"
#include "bakuage/utils.h"
#include "bakuage/fir_design.h"
#include "bakuage/fir_filter2.h"

DECLARE_string(sound_quality2_cache);
DECLARE_string(mastering5_optimization_algorithm);
DECLARE_int32(mastering5_optimization_max_eval_count);
DECLARE_double(mastering5_mastering_level);
DECLARE_string(mastering5_mastering_reference_file);

typedef float Float;
using namespace bakuage;

namespace {
    // compress(x) -> wet_gain -> output
    // x -> dry_gain -> output
    class LoudnessMapping {
    public:
        LoudnessMapping() {}
        LoudnessMapping(Float original_mean, Float relative_threshold,
                        Float wet_gain, Float relative_dry_gain, Float ratio):
        original_mean_(original_mean),
        target_mean_(original_mean + wet_gain),
        threshold_(original_mean + relative_threshold),
        dry_gain_(wet_gain + relative_dry_gain), inv_ratio_(1.0 / ratio) {}

        Float operator () (Float x) const {
            static const float log10_div_20 = std::log(10) / 20;
            Float w = std::max(threshold_, x);
            Float gain = (w - original_mean_) * inv_ratio_ + target_mean_ - w;
            Float y = x + gain;
            Float z = x + dry_gain_;
            return 20 * std::log10(1e-37 + 0.5 * std::exp(log10_div_20 * y) + 0.5 * std::exp(log10_div_20 * z));
        }

        Float threshold() const { return threshold_; }
    private:
        Float original_mean_;
        Float target_mean_;
        Float threshold_;
        Float dry_gain_;
        Float inv_ratio_;
    };
    typedef MsCompressorFilter<Float, LoudnessMapping, LoudnessMapping> Compressor;

    typedef arma::vec EffectParams;

    struct BandEffect {
        LoudnessMapping loudness_mapping;
        LoudnessMapping ms_loudness_mapping;
    };

    // 空間は重要。最適化のしやすさに関わる (あきらかに同じ値を返すような点が複数あると効率が悪い)
    // param変換。param in [a, b]。0で恒等変換になるようにする
    // 両側に均等なものはparam in [-1, 1]だが、そうでないものは[0, 1]とかもありえる
    Float ToRelThreshold(Float x) {
        return 20 * x;
    }
    Float ToWetGain(Float x) {
        return 10 * x;
    }
    Float ToRelativeDryGain(Float x) {
        return 10 * x;
    }
    Float ToRatio(Float x) {
        return std::pow(5, x);
    }

    // すべてゼロで恒等変換になるようにする
    struct Effect {
        Effect(const Eigen::VectorXd &original_mean, const EffectParams& params) {
            const int band_count = params.size() / 8;
            band_effects.resize(band_count);
            for (int i = 0; i < band_count; i++) {
                band_effects[i].loudness_mapping = LoudnessMapping(original_mean[2 * i + 0], ToRelThreshold(params(8 * i + 0)), ToWetGain(params(8 * i + 1)), ToRelativeDryGain(params(8 * i + 2)), ToRatio(params(8 * i + 3)));
                band_effects[i].ms_loudness_mapping = LoudnessMapping(original_mean[2 * i + 1], ToRelThreshold(params(8 * i + 4)), ToWetGain(params(8 * i + 5)), ToRelativeDryGain(params(8 * i + 6)), ToRatio(params(8 * i + 7)));
            }
        }
        std::vector<BandEffect> band_effects;
    };

}

namespace phase_limiter {

    // audio_analyzer(CalculateMultibandLoudness2)の仕様に合わせて、mean, covを計算する。
    // エフェクトはloudness vector上でシミュレーションする
    // 基準ラウドネスの違いとかはホワイトノイズを処理して補正値を計算して補正する
    void AutoMastering5(std::vector<float> *_wave, const int sample_rate, const std::function<void(float)> &progress_callback) {
        const int frames = _wave->size() / 2;
        const int channels = 2;
        const float block_sec = 0.4;

        // initialize sound quality calculator
        bakuage::SoundQuality2Calculator calculator;
        {
            std::ifstream ifs(FLAGS_sound_quality2_cache);
            boost::archive::binary_iarchive ia(ifs);
            ia >> calculator;
        }
        const auto band_count = calculator.band_count();
        const auto bands = calculator.bands();

        // initialize reference
        bakuage::MasteringReference2 mastering_reference;
        if (!FLAGS_mastering5_mastering_reference_file.empty()) {
            Eigen::VectorXd mean;
            Eigen::MatrixXd cov;
            bakuage::SoundQuality2CalculatorUnit::ParseReference(bakuage::LoadStrFromFile(FLAGS_mastering5_mastering_reference_file.c_str()).c_str(), &mean, &cov);
            mastering_reference = bakuage::MasteringReference2(mean, cov);
        }

        // calculate original band loudness vectors
        std::vector<bakuage::AlignedPodVector<float>> band_loudnesses;
        {
            // 400ms block
            const int sample_freq = sample_rate;
            const int width = bakuage::CeilInt<int>(sample_freq * block_sec, 4);
            const int shift = width / 2; // 本当は75% overlapだけど、高速化のために50% overlap
            const int samples = frames;

            bakuage::AlignedPodVector<Float> filtered(channels * samples);
            for (int i = 0; i < channels; i++) {
                LoudnessFilter<float> filter(sample_freq);
                for (int j = 0; j < samples; j++) {
                    int k = channels * j + i;
                    filtered[k] = filter.Clock((*_wave)[k]);
                }
            }

            const int spec_len = width / 2 + 1;

            // FFTの正規化も行う (sqrt(hanning)窓)
            bakuage::AlignedPodVector<float> window(width);
            bakuage::CopyHanning(width, window.data(), 1.0 / std::sqrt(width));

            // 規格では最後のブロックは使わないけど、
            // 使ったほうが実用的なので使う
            band_loudnesses.resize(bakuage::CeilInt(samples, shift) / shift);
            tbb::parallel_for<int>(0, band_loudnesses.size(), [&](int pos_idx) {
                const int pos = pos_idx * shift;
                bakuage::AlignedPodVector<float> band_loudness(2 * band_count);
                int end = std::min<int>(pos + width, samples);

                auto &pool = bakuage::ThreadLocalDftPool<bakuage::RealDft<Float>>::GetThreadInstance();
                const auto dft = pool.Get(width);

                bakuage::AlignedPodVector<float> fft_input(width);
                std::vector<bakuage::AlignedPodVector<std::complex<float>>> fft_outputs(channels);
                for (int ch = 0; ch < channels; ch++) {
                    fft_outputs[ch].resize(spec_len);
                }

                // FFT
                for (int ch = 0; ch < channels; ch++) {
                    for (int i = 0; i < width; i++) {
                        fft_input[i] = pos + i < end ? filtered[channels * (pos + i) + ch] * window[i] : 0;
                    }
                    dft->Forward(fft_input.data(), (float *)fft_outputs[ch].data(), pool.work());
                }

                // binをbandに振り分けていく
                for (int band_index = 0; band_index < band_count; band_index++) {
                    int low_bin_index = std::floor(width * bands[band_index].low_freq / sample_freq);
                    int high_bin_index = std::min<int>(std::floor(width * (bands[band_index].high_freq == 0 ? 0.5 : bands[band_index].high_freq / sample_freq)), spec_len);

                    // mid
                    double sum = 0;
                    for (int i = low_bin_index; i < high_bin_index; i++) {
                        sum += std::norm(fft_outputs[0][i] + fft_outputs[1][i]) ;
                    }
                    band_loudness[2 * band_index + 0] = 10 * std::log10(1e-7//1e-37
                                                                     + sum / (0.5 * width));
                    // side
                    sum = 0;
                    for (int i = low_bin_index; i < high_bin_index; i++) {
                        sum += std::norm(fft_outputs[0][i] - fft_outputs[1][i]);
                    }
                    band_loudness[2 * band_index + 1] = 10 * std::log10(1e-7//1e-37
                                                                      + sum / (0.5 * width));
                }

                band_loudnesses[pos_idx] = std::move(band_loudness);
            });
        }
        progress_callback(0.1);

        // エフェクト補正値計算
        // ホワイトノイズに窓掛けFFTで上記処理をしたラウドネスと、
        // ホワイトノイズをコンプレッサーで解析したラウドネスを比較する
        // -> いったんなしで、差分を出力してみて大きいなら考える。

        // エフェクト適用シミュレーション (ms compressor filter)
        const auto apply_effect = [](const Effect &effect, const Float *input, Float *output) {
            for (int i = 0; i < effect.band_effects.size(); i++) {
                const auto &band_effect = effect.band_effects[i];
                // static const float sqrt_0_5 = std::sqrt(0.5); // 元のMsCompressorFilterはmsにするときにこれをかけていた。誤差が問題になるなら考える
                static const float log10_div_20 = std::log(10) / 20;

                Float input_m = input[2 * i + 0];
                Float input_s = input[2 * i + 1];
                Float rms_m = std::pow(10, 0.1 * input_m);
                Float rms_s = std::pow(10, 0.1 * input_s);

                Float total_loudness = -0.691 + 10 * std::log10(rms_m + rms_s + 1e-37);
                Float mapped_loudness = band_effect.loudness_mapping(total_loudness);

                Float mid_to_side_loudness = input_s - input_m;
                Float side_gain = std::exp(log10_div_20 * (band_effect.ms_loudness_mapping(mid_to_side_loudness) - mid_to_side_loudness));

                Float total_loudness_with_side_gain = -0.691 + 10 * std::log10(rms_m + rms_s * bakuage::Sqr(side_gain) + 1e-37);
                Float gain = std::exp(log10_div_20 * (mapped_loudness - total_loudness_with_side_gain));

                output[2 * i + 0] = 10 * std::log10(rms_m * bakuage::Sqr(gain));
                output[2 * i + 1] = 10 * std::log10(rms_s * bakuage::Sqr(side_gain * gain));
            }
        };

        // エフェクトパラメータからエフェクト適用後のmean, covと各バンドの平均誤差を計算する
        const auto calc_mean_cov = [apply_effect, band_count, &band_loudnesses](const Effect *effect, Eigen::VectorXd *mean_vec, Eigen::MatrixXd *cov, float *mse) {
            const auto relative_threshold_db = -20;
            mean_vec->resize(2 * band_count);
            cov->resize(2 * band_count, 2 * band_count);
            *mse = 0;

            // apply effect
            bakuage::AlignedPodVector<float> applied(2 * band_count);
            std::vector<bakuage::AlignedPodVector<float>> loudness_blocks(2 * band_count);
            for (int i = 0; i < 2 * band_count; i++) {
                loudness_blocks[i].resize(band_loudnesses.size());
            }
            for (int i = 0; i < band_loudnesses.size(); i++) {
                if (effect) {
                    apply_effect(*effect, band_loudnesses[i].data(), applied.data());
                } else {
                    bakuage::TypedMemcpy(applied.data(), band_loudnesses[i].data(), applied.size());
                }
                for (int j = 0; j < applied.size(); j++) {
                    *mse += bakuage::Sqr(band_loudnesses[i][j] - applied[j]);
                    loudness_blocks[j][i] = applied[j];
                }
            }
            *mse /= band_loudnesses.size() * applied.size();

            // calculate mean
            bakuage::AlignedPodVector<Float> thresholds(2 * band_count);
            for (int band_index = 0; band_index < 2 * band_count; band_index++) {
                const auto &band_blocks = loudness_blocks[band_index];

                double threshold = -1e10;//-70;
                for (int k = 0; k < 2; k++) {
                    Float count = 0;
                    Float sum = 0;
                    for (const auto &z: band_blocks) {
                        const bool valid = z >= threshold; // for easy optimization
                        count += valid;
                        sum += valid ? z : 0;
                    }

                    double mean = sum / (1e-37 + count);
                    if (k == 0) {
                        threshold = mean + relative_threshold_db;
                        thresholds[band_index] = threshold;
                    }
                    else if (k == 1) {
                        (*mean_vec)[band_index] = mean;
                    }
                }
            }

            // calculate covariance
            for (int band_index1 = 0; band_index1 < 2 * band_count; band_index1++) {
                for (int band_index2 = band_index1; band_index2 < 2 * band_count; band_index2++) {
                    const Float mean1 = (*mean_vec)[band_index1];
                    const Float mean2 = (*mean_vec)[band_index2];
                    const Float threshold1 = thresholds[band_index1];
                    const Float threshold2 = thresholds[band_index2];

                    const auto &band_blocks1 = loudness_blocks[band_index1];
                    const auto &band_blocks2 = loudness_blocks[band_index2];

                    Float v = 0;
                    Float c = 0;
                    for (int i = 0; i < band_blocks1.size(); i++) {
                        const auto x1 = band_blocks1[i];
                        const auto x2 = band_blocks2[i];
                        const bool valid = (x1 >= threshold1) & (x2 >= threshold2); // for easy optimization (not && instead &)
                        v += valid * (x1 - mean1) * (x2 - mean2);
                        c += valid;
                    }
                    v  /= (1e-37 + c);
                    (*cov)(band_index1, band_index2) = v;
                    (*cov)(band_index2, band_index1) = v;
                }
            }
        };

        // calculate original
        Eigen::VectorXd original_mean;
        Eigen::MatrixXd original_cov;
        float original_mse;
        calc_mean_cov(nullptr, &original_mean, &original_cov, &original_mse);

        // define bound
        arma::vec lower_bounds(8 * band_count);
        arma::vec upper_bounds(8 * band_count);
        for (int i = 0; i < band_count; i++) {
            lower_bounds(8 * i + 0) = -1; // rel threshold
            upper_bounds(8 * i + 0) = 0.01;
            lower_bounds(8 * i + 1) = -1; // wet gain
            upper_bounds(8 * i + 1) = 1;
            lower_bounds(8 * i + 2) = -1; // relative dry gain
            upper_bounds(8 * i + 2) = 0.01;
            lower_bounds(8 * i + 3) = -0.01; // ratio
            upper_bounds(8 * i + 3) = 1;
            lower_bounds(8 * i + 4) = -1;
            upper_bounds(8 * i + 4) = 0.01;
            lower_bounds(8 * i + 5) = -1;
            upper_bounds(8 * i + 5) = 1;
            lower_bounds(8 * i + 6) = -1;
            upper_bounds(8 * i + 6) = 0.01;
            lower_bounds(8 * i + 7) = -0.01;
            upper_bounds(8 * i + 7) = 1;
        }
        {
            const double scale = 1e-2 + FLAGS_mastering5_mastering_level;
            lower_bounds *= scale;
            upper_bounds *= scale;
        }

        // エフェクトパラメータから評価関数を計算する
        std::mutex eval_mtx;
        float min_eval = 1e100;
        int eval_count = 0;
        const auto calc_eval = [calc_mean_cov, &calculator, &original_mean, &min_eval, &eval_count, &eval_mtx, &progress_callback, &lower_bounds, &upper_bounds, &mastering_reference](const EffectParams &params) -> double {
            Eigen::VectorXd mean;
            Eigen::MatrixXd cov;
            float msp = 0;
            for (int i = 0; i < params.size(); i++) {
                msp += bakuage::Sqr(params(i));
            }
            msp /= params.size();
            float bound_error = 0;
            for (int i = 0; i < params.size(); i++) {
                bound_error += bakuage::Sqr(std::max<float>(0, lower_bounds[i] - params[i]));
                bound_error += bakuage::Sqr(std::max<float>(0, params[i] - upper_bounds[i]));
            }
            float mse;
            Effect effect(original_mean, params);
            calc_mean_cov(&effect, &mean, &cov, &mse);

            const bakuage::MasteringReference2 target(mean, cov);
            float main_eval = 0;
            if (FLAGS_mastering5_mastering_reference_file.empty()) {
                float sound_quality;
                calculator.CalculateSoundQuality(target, &sound_quality, nullptr);
                main_eval = -sound_quality;
            } else {
                main_eval = calculator.CalculateDistance(mastering_reference, target);
            }

            // 事前の実験でalphaをいろいろ変えて最適化してmseを見たところ
            // 最適解のところで sound_qualityの微分とmseの微分が一致していると仮定すると、
            // alpha = 0.02 / sqrt(mse)になった。
            // mseの許容量(target_mse)からalphaを逆算して決める。
            // target_mseはFLAGS_mastering5_mastering_levelを元に適当に決める
            // betaはエフェクトのパラメータを変えたときにどのくらいmseが変わるかを考えて、alphaに比例させて決める。(paramを1変化させて、特徴量が10dB変化するなら、beta = 10^2 * alpha -> いろいろ試して微調整)
            // 実際これでやってみてtarget_mseになるかどうかで妥当性検証可能
            const float target_mse = bakuage::Sqr(4 * (1e-2 + FLAGS_mastering5_mastering_level));
            const float alpha = 0.02 / std::sqrt(target_mse);
            const float beta = bakuage::Sqr(10.0) * alpha;
            const float eval = main_eval + alpha * mse + beta * msp + bound_error * 1e4;
            {
                std::lock_guard<std::mutex> lock(eval_mtx);
                eval_count++;
                if (eval_count % (FLAGS_mastering5_optimization_max_eval_count / 10) == 0 && eval_count < FLAGS_mastering5_optimization_max_eval_count) {
                    progress_callback(0.1 + 0.5 * eval_count / FLAGS_mastering5_optimization_max_eval_count);
                }
                if (min_eval > eval) {
                    min_eval = eval;
                    std::cerr << "optimization " << eval_count << "\t" << min_eval << "\t" << main_eval << "\t" << mse << "\t" << msp << std::endl;
                }
            }
            return eval;
        };

        // calc initial eval
        EffectParams zero_params(8 * band_count);
        for (int i = 0; i < zero_params.size(); i++) {
            zero_params(i) = 0;
        }
        const auto initial_eval = calc_eval(zero_params);
        std::cerr << "optimization initial_eval: " << initial_eval << std::endl;

        // エフェクトパラメータ探索
        const auto find_params = [calc_eval, band_count, &zero_params, initial_eval, &lower_bounds, &upper_bounds]() {
            optim::algo_settings_t settings;
#if 0
            // boundしているとうまく最適化できないので使わない。
            // grep inv_transform in optim
            // optimは有界な値を実数全体に変換して最適化している
            // 境界そのものはinfに変換されてしまうからうまく処理できない
            // 原点が境界そのものにならないように注意。
            // 最初の分布も重要。
            // boundして最適化すると境界付近の値になりやすい気がする (変換の形的に境界付近の存在確率が高まる？次元の呪い？)
            // 正則化強めだと、boundなしのほうが最適化性能が高い。正則化弱めだと少しだけboundありのほうが性能高いが大差無い
            // だから、boundなしで行こう。こっちのほうが安定している。
            // 評価関数側でなんとかする
            settings.lower_bounds = lower_bounds;
            settings.upper_bounds = upper_bounds;
            settings.vals_bound = true;
#endif
#if 1
            settings.de_initial_lb = lower_bounds;
            settings.de_initial_ub = upper_bounds;
            settings.pso_initial_lb = lower_bounds;
            settings.pso_initial_ub = upper_bounds;
#endif
            auto result = zero_params;
            bool success;
            // それぞれ最大繰り返し回数の指定方法が違うので注意。ソースコード参照
            if (FLAGS_mastering5_optimization_algorithm == "nm") {
                settings.iter_max = FLAGS_mastering5_optimization_max_eval_count / lower_bounds.size();
                success = optim::nm(result, [calc_eval](const arma::vec& vec, arma::vec* grad_out, void *opt_data) {
                    return calc_eval(vec);
                }, nullptr, settings);
            }
            else if (FLAGS_mastering5_optimization_algorithm == "pso") {
                settings.pso_n_gen = FLAGS_mastering5_optimization_max_eval_count / settings.pso_n_pop;
                success = optim::pso(result, [calc_eval](const arma::vec& vec, arma::vec* grad_out, void *opt_data) {
                    return calc_eval(vec);
                }, nullptr, settings);
            } else if (FLAGS_mastering5_optimization_algorithm == "pso_dv") {
                settings.pso_n_gen = FLAGS_mastering5_optimization_max_eval_count / settings.pso_n_pop;
                success = optim::pso_dv(result, [calc_eval](const arma::vec& vec, arma::vec* grad_out, void *opt_data) {
                    return calc_eval(vec);
                }, nullptr, settings);
            } else if (FLAGS_mastering5_optimization_algorithm == "de") {
                settings.de_max_fn_eval = FLAGS_mastering5_optimization_max_eval_count;
                success = optim::de(result, [calc_eval](const arma::vec& vec, arma::vec* grad_out, void *opt_data) {
                    return calc_eval(vec);
                }, nullptr, settings);
            } else if (FLAGS_mastering5_optimization_algorithm == "de_prmm") {
                settings.de_max_fn_eval = FLAGS_mastering5_optimization_max_eval_count;
                success = optim::de_prmm(result, [calc_eval](const arma::vec& vec, arma::vec* grad_out, void *opt_data) {
                    return calc_eval(vec);
                }, nullptr, settings);
            } else {
                throw std::logic_error(std::string("unknown FLAGS_mastering5_optimization_algorithm " + FLAGS_mastering5_optimization_algorithm));
            }
            const auto result_eval = calc_eval(result);
            std::cerr << "optimization success: " << success << std::endl;
            std::cerr << "optimization solution y: " << result_eval << std::endl;
            for (int i = 0; i < band_count; i++) {
                std::cerr << "optimization solution x " << i << "\t" << result(8 * i + 0) << "\t" << result(8 * i + 1) << "\t" << result(8 * i + 2) << "\t" << result(8 * i + 3) << std::endl;
                std::cerr << "optimization solution x ms " << i << "\t" << result(8 * i + 4) << "\t" << result(8 * i + 5) << "\t" << result(8 * i + 6) << "\t" << result(8 * i + 7) << std::endl;
            }
            if (result_eval < initial_eval) {
                return result;
            } else {
                return zero_params;
            }
        };

        const auto effect_params = find_params();
        const Effect effect(original_mean, effect_params);

        std::mutex result_mtx;
        std::mutex progression_mtx;
        std::vector<std::function<void ()>> tasks;
        std::vector<Float> result(_wave->size());
        bakuage::AlignedPodVector<Float> progressions(band_count);

        const auto update_progression = [&progressions, &progression_mtx, progress_callback](int i, Float p) {
            std::lock_guard<std::mutex> lock(progression_mtx);
            Float total = 0;
            progressions[i] = p;
            for (const auto &a : progressions) {
                total += a;
            }
            progress_callback(0.6 + 0.4 * total / progressions.size());
        };

        for (int band_index = 0; band_index < band_count; band_index++) {
            const auto &band = calculator.bands()[band_index];
            const auto update_progression_bound = std::bind(update_progression, band_index, std::placeholders::_1);
            const auto &band_effect = effect.band_effects[band_index];
            tasks.push_back([band, band_effect, sample_rate, frames, _wave, &result, &result_mtx, update_progression_bound]() {
                const float *wave_ptr = &(*_wave)[0];

                int fir_delay_samples;
                std::vector<Float> fir;
                {
                    fir_delay_samples = static_cast<int>(0.2 * sample_rate);
                    const int n = 2 * fir_delay_samples + 1;
                    Float freq1 = std::min<Float>(0.5, band.low_freq / sample_rate);
                    Float freq2 = std::min<Float>(0.5, band.high_freq == 0 ? 0.5 : band.high_freq / sample_rate);
                    fir = CalculateBandPassFir<Float>(freq1, freq2, n, 4);
                }
                update_progression_bound(0.1);

                const int len = frames + fir.size() - 1;
                bakuage::AlignedPodVector<float> filtered(channels * len);
                {
                    FirFilter2<Float> fir_filter(fir.begin(), fir.end());
                    bakuage::AlignedPodVector<Float> filter_temp_input(frames + fir_delay_samples);
                    bakuage::AlignedPodVector<Float> filter_temp_output(frames + fir_delay_samples);
                    for (int ch = 0; ch < channels; ch++) {
                        fir_filter.Clear();
                        for (int i = 0; i < frames; i++) {
                            filter_temp_input[i] = wave_ptr[channels * i + ch];
                        }
                        fir_filter.Clock(filter_temp_input.data(), filter_temp_input.data() + frames + fir_delay_samples, filter_temp_output.data());
                        for (int i = 0; i < frames; i++) {
                            filtered[channels * i + ch] = filter_temp_output[i + fir_delay_samples];
                        }
                    }
                }
                update_progression_bound(0.2);

                Compressor::Config compressor_config;
                compressor_config.loudness_mapping_func = band_effect.loudness_mapping;
                compressor_config.ms_loudness_mapping_func = band_effect.ms_loudness_mapping;
                compressor_config.max_mean_sec = 0.2;
                compressor_config.num_channels = channels;
                compressor_config.sample_rate = sample_rate;
                Compressor compressor(compressor_config);

                const int shift = compressor.delay_samples();
                const int len2 = frames + shift;
                filtered.resize(channels * len2);
                bakuage::AlignedPodVector<Float> temp_input(channels);
                bakuage::AlignedPodVector<Float> temp_output(channels);

                // filteredにin-placeで書き込んでから共有のresultに足しこむ
                for (int j = 0; j < len2; j++) {
                    for (int i = 0; i < channels; i++) {
                        temp_input[i] = filtered[channels * j + i];
                    }
                    compressor.Clock(&temp_input[0], &temp_output[0]);
                    for (int i = 0; i < channels; i++) {
                        filtered[channels * j + i] = temp_output[i];
                    }
                }
                update_progression_bound(0.8);

                // flush filtered (dry sound)
                {
                    std::lock_guard<std::mutex> lock(result_mtx);
                    const int len3 = frames * channels;
                    const int channels_shift = channels * shift;
                    bakuage::VectorAddInplace(filtered.data() + channels_shift, result.data(), len3);
                }
                update_progression_bound(1);
            });
        }

        tbb::parallel_for(0, (int)tasks.size(), [&tasks](int task_i) {
            tasks[task_i]();
        });

        *_wave = std::move(result);
    }

}

max_stars_repo_name: nankasuisui/phaselimiter

max_issues_repo_name: nankasuisui/phaselimiter

max_forks_repo_name: nankasuisui/phaselimiter


text:
// Author: Tianwei Shen <shentianweipku@gmail.com>
// This is adapted from Boost serialization example

#include <iostream>
#include <fstream>
#include <string>

// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/version.hpp>

// a member class to test pointer serialization
class gps_device {
public:
	gps_device() {}
	gps_device(std::string name_): name(name_) {}
	std::string name;
};

class gps_position
{
public:
    int degrees;
    int minutes;
    float seconds;
	gps_device *device;		// pointer to the device that collect gps data
	gps_position() {}
    gps_position(int d, int m, float s, gps_device *dev) :
        degrees(d), minutes(m), seconds(s), device(dev)
    {}
	const std::string get_device_name() const
	{
		return device->name;
	}
};

// a non-intrusive way for serialization with boost
namespace boost {
namespace serialization {

template<class Archive>
void serialize(Archive & ar, gps_device & g, const unsigned int version)
{
	ar & g.name;
}

template<class Archive>
void serialize(Archive & ar, gps_position & g, const unsigned int version)
{
    ar & g.degrees;
    ar & g.minutes;
    ar & g.seconds;
	if(version > 0)
		ar & g.device;
}

} // namespace serialization
} // namespace boost

BOOST_CLASS_VERSION(gps_position, 1)

int main() {
    // create and open a character archive for output
    std::ofstream ofs("filename");

    // create class instance
	std::string name = "gps_device";
	gps_device d(name);
    const gps_position g(35, 59, 24.567f, &d);

    // save data to archive
    {
        boost::archive::text_oarchive oa(ofs);
        // write class instance to archive
        oa << g;
    	// archive and stream closed when destructors are called
    }

    // ... some time later restore the class instance to its orginal state
    gps_position newg;
    {
        // create and open an archive for input
        std::ifstream ifs("filename");
        boost::archive::text_iarchive ia(ifs);
        // read class state from archive
        ia >> newg;
        // archive and stream closed when destructors are called
    }
	const std::string device_name = newg.get_device_name();
	if(device_name != "gps_device")
		return -1;

    return 0;
}

max_stars_repo_name: zyxrrr/GraphSfM

max_issues_repo_name: zyxrrr/GraphSfM

max_forks_repo_name: zyxrrr/GraphSfM


text:
///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (C) 2018-2020, University of Edinburgh
// Copyright note valid unless otherwise stated in individual files.
// All rights reserved.
///////////////////////////////////////////////////////////////////////////////

#ifndef BINDINGS_PYTHON_CROCODDYL_CORE_FWD_HPP_
#define BINDINGS_PYTHON_CROCODDYL_CORE_FWD_HPP_

#include <eigenpy/eigenpy.hpp>
#include <boost/python.hpp>
#include <boost/python/enum.hpp>

namespace crocoddyl {
namespace python {

namespace bp = boost::python;

void exposeCore();
void exposeMultibody();

}  // namespace python
}  // namespace crocoddyl

#endif  // BINDINGS_PYTHON_CROCODDYL_CORE_FWD_HPP_

max_stars_repo_name: paLeziart/crocoddyl

max_issues_repo_name: paLeziart/crocoddyl

max_forks_repo_name: paLeziart/crocoddyl


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

#include "open3d/camera/PinholeCameraIntrinsic.h"

#include <json/json.h>

#include <Eigen/Dense>

#include "open3d/utility/Console.h"

namespace open3d {
namespace camera {

PinholeCameraIntrinsic::PinholeCameraIntrinsic()
    : width_(-1), height_(-1), intrinsic_matrix_(Eigen::Matrix3d::Zero()) {}

PinholeCameraIntrinsic::PinholeCameraIntrinsic(
        int width, int height, double fx, double fy, double cx, double cy) {
    SetIntrinsics(width, height, fx, fy, cx, cy);
}

PinholeCameraIntrinsic::PinholeCameraIntrinsic(
        PinholeCameraIntrinsicParameters param) {
    if (param == PinholeCameraIntrinsicParameters::PrimeSenseDefault)
        SetIntrinsics(640, 480, 525.0, 525.0, 319.5, 239.5);
    else if (param ==
             PinholeCameraIntrinsicParameters::Kinect2DepthCameraDefault)
        SetIntrinsics(512, 424, 365.456, 365.456, 254.878, 205.395);
    else if (param ==
             PinholeCameraIntrinsicParameters::Kinect2ColorCameraDefault)
        SetIntrinsics(1920, 1080, 1059.9718, 1059.9718, 975.7193, 545.9533);
}

PinholeCameraIntrinsic::~PinholeCameraIntrinsic() {}

bool PinholeCameraIntrinsic::ConvertToJsonValue(Json::Value &value) const {
    value["width"] = width_;
    value["height"] = height_;
    if (!EigenMatrix3dToJsonArray(intrinsic_matrix_,
                                  value["intrinsic_matrix"])) {
        return false;
    }
    return true;
}

bool PinholeCameraIntrinsic::ConvertFromJsonValue(const Json::Value &value) {
    if (!value.isObject()) {
        utility::LogWarning(
                "PinholeCameraParameters read JSON failed: unsupported json "
                "format.");
        return false;
    }
    width_ = value.get("width", -1).asInt();
    height_ = value.get("height", -1).asInt();
    if (!EigenMatrix3dFromJsonArray(intrinsic_matrix_,
                                    value["intrinsic_matrix"])) {
        utility::LogWarning(
                "PinholeCameraParameters read JSON failed: wrong format.");
        return false;
    }
    return true;
}
}  // namespace camera
}  // namespace open3d


text:
// Copyright (C) 2019-2020 Zilliz. 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 <numeric>
#include <queue>
#include <thread>
#include <boost/iterator/counting_iterator.hpp>

#include "common/Consts.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "query/PlanNode.h"
#include "query/SearchOnSealed.h"
#include "query/generated/ExecPlanNodeVisitor.h"
#include "segcore/Reduce.h"
#include "segcore/SegmentGrowingImpl.h"
#include "utils/Utils.h"

namespace milvus::segcore {

int64_t
SegmentGrowingImpl::PreInsert(int64_t size) {
    auto reserved_begin = record_.reserved.fetch_add(size);
    return reserved_begin;
}

int64_t
SegmentGrowingImpl::PreDelete(int64_t size) {
    auto reserved_begin = deleted_record_.reserved.fetch_add(size);
    return reserved_begin;
}

std::shared_ptr<DeletedRecord::TmpBitmap>
SegmentGrowingImpl::get_deleted_bitmap(int64_t del_barrier,
                                       Timestamp query_timestamp,
                                       int64_t insert_barrier,
                                       bool force) const {
    auto old = deleted_record_.get_lru_entry();
    if (old->bitmap_ptr->count() == insert_barrier) {
        if (old->del_barrier == del_barrier) {
            return old;
        }
    }

    auto current = old->clone(insert_barrier);
    current->del_barrier = del_barrier;

    auto bitmap = current->bitmap_ptr;

    int64_t start, end;
    if (del_barrier < old->del_barrier) {
        start = del_barrier;
        end = old->del_barrier;
    } else {
        start = old->del_barrier;
        end = del_barrier;
    }
    for (auto del_index = start; del_index < end; ++del_index) {
        // get uid in delete logs
        auto uid = deleted_record_.uids_[del_index];

        // map uid to corresponding offsets, select the max one, which should be the target
        // the max one should be closest to query_timestamp, so the delete log should refer to it
        int64_t the_offset = -1;
        auto [iter_b, iter_e] = uid2offset_.equal_range(uid);

        for (auto iter = iter_b; iter != iter_e; ++iter) {
            auto offset = iter->second;
            AssertInfo(offset < insert_barrier, "Timestamp offset is larger than insert barrier");
            the_offset = std::max(the_offset, offset);
            if (the_offset == -1) {
                continue;
            }
            if (record_.timestamps_[the_offset] >= query_timestamp) {
                bitmap->clear(the_offset);
            } else {
                bitmap->set(the_offset);
            }
        }
    }
    this->deleted_record_.insert_lru_entry(current);
    return current;
}

BitsetView
SegmentGrowingImpl::get_filtered_bitmap(const BitsetView& bitset, int64_t ins_barrier, Timestamp timestamp) const {
    auto del_barrier = get_barrier(get_deleted_record(), timestamp);
    if (del_barrier == 0) {
        return bitset;
    }
    auto bitmap_holder = get_deleted_bitmap(del_barrier, timestamp, ins_barrier);
    if (bitmap_holder == nullptr) {
        return bitset;
    }
    AssertInfo(bitmap_holder, "bitmap_holder is null");
    auto deleted_bitmap = bitmap_holder->bitmap_ptr;
    if (bitset.size() == 0) {
        return BitsetView(deleted_bitmap);
    }
    AssertInfo(deleted_bitmap->count() == bitset.size(), "Deleted bitmap count not equal to filtered bitmap count");

    auto filtered_bitmap = std::make_shared<faiss::ConcurrentBitset>(bitset.size(), bitset.data());
    auto final_bitmap = (*deleted_bitmap.get()) | (*filtered_bitmap.get());
    BitsetView res = BitsetView(final_bitmap);
    return res;
}

Status
SegmentGrowingImpl::Insert(int64_t reserved_begin,
                           int64_t size,
                           const int64_t* uids_raw,
                           const Timestamp* timestamps_raw,
                           const RowBasedRawData& entities_raw) {
    AssertInfo(entities_raw.count == size, "Entities_raw count not equal to insert size");
    // step 1: check schema if valid
    if (entities_raw.sizeof_per_row != schema_->get_total_sizeof()) {
        std::string msg = "entity length = " + std::to_string(entities_raw.sizeof_per_row) +
                          ", schema length = " + std::to_string(schema_->get_total_sizeof());
        throw std::runtime_error(msg);
    }

    // step 2: sort timestamp
    auto raw_data = reinterpret_cast<const char*>(entities_raw.raw_data);
    auto len_per_row = entities_raw.sizeof_per_row;
    std::vector<std::tuple<Timestamp, idx_t, int64_t>> ordering;
    ordering.resize(size);
    // #pragma omp parallel for
    for (int i = 0; i < size; ++i) {
        ordering[i] = std::make_tuple(timestamps_raw[i], uids_raw[i], i);
    }
    std::sort(ordering.begin(), ordering.end());

    // step 3: and convert row-based data to column-based data accordingly
    auto sizeof_infos = schema_->get_sizeof_infos();
    std::vector<int> offset_infos(schema_->size() + 1, 0);
    std::partial_sum(sizeof_infos.begin(), sizeof_infos.end(), offset_infos.begin() + 1);
    std::vector<aligned_vector<uint8_t>> entities(schema_->size());

    for (int fid = 0; fid < schema_->size(); ++fid) {
        auto len = sizeof_infos[fid];
        entities[fid].resize(len * size);
    }

    std::vector<idx_t> uids(size);
    std::vector<Timestamp> timestamps(size);
    // #pragma omp parallel for
    for (int index = 0; index < size; ++index) {
        auto [t, uid, order_index] = ordering[index];
        timestamps[index] = t;
        uids[index] = uid;
        for (int fid = 0; fid < schema_->size(); ++fid) {
            auto len = sizeof_infos[fid];
            auto offset = offset_infos[fid];
            auto src = raw_data + order_index * len_per_row + offset;
            auto dst = entities[fid].data() + index * len;
            memcpy(dst, src, len);
        }
    }

    do_insert(reserved_begin, size, uids.data(), timestamps.data(), entities);
    return Status::OK();
}

void
SegmentGrowingImpl::do_insert(int64_t reserved_begin,
                              int64_t size,
                              const idx_t* row_ids,
                              const Timestamp* timestamps,
                              const std::vector<aligned_vector<uint8_t>>& columns_data) {
    // step 4: fill into Segment.ConcurrentVector
    record_.timestamps_.set_data(reserved_begin, timestamps, size);
    record_.uids_.set_data(reserved_begin, row_ids, size);
    for (int fid = 0; fid < schema_->size(); ++fid) {
        auto field_offset = FieldOffset(fid);
        record_.get_field_data_base(field_offset)->set_data_raw(reserved_begin, columns_data[fid].data(), size);
    }

    if (schema_->get_is_auto_id()) {
        for (int i = 0; i < size; ++i) {
            auto row_id = row_ids[i];
            // NOTE: this must be the last step, cannot be put above
            uid2offset_.insert(std::make_pair(row_id, reserved_begin + i));
        }
    } else {
        auto offset = schema_->get_primary_key_offset().value_or(FieldOffset(-1));
        AssertInfo(offset.get() != -1, "Primary key offset is -1");
        auto& row = columns_data[offset.get()];
        auto row_ptr = reinterpret_cast<const int64_t*>(row.data());
        for (int i = 0; i < size; ++i) {
            uid2offset_.insert(std::make_pair(row_ptr[i], reserved_begin + i));
        }
    }

    record_.ack_responder_.AddSegment(reserved_begin, reserved_begin + size);
    if (enable_small_index_) {
        int64_t chunk_rows = segcore_config_.get_chunk_rows();
        indexing_record_.UpdateResourceAck(record_.ack_responder_.GetAck() / chunk_rows, record_);
    }
}

Status
SegmentGrowingImpl::Delete(int64_t reserved_begin,
                           int64_t size,
                           const int64_t* uids_raw,
                           const Timestamp* timestamps_raw) {
    std::vector<std::tuple<Timestamp, idx_t>> ordering;
    ordering.resize(size);
    // #pragma omp parallel for
    for (int i = 0; i < size; ++i) {
        ordering[i] = std::make_tuple(timestamps_raw[i], uids_raw[i]);
    }
    std::sort(ordering.begin(), ordering.end());
    std::vector<idx_t> uids(size);
    std::vector<Timestamp> timestamps(size);
    // #pragma omp parallel for
    for (int index = 0; index < size; ++index) {
        auto [t, uid] = ordering[index];
        timestamps[index] = t;
        uids[index] = uid;
    }
    deleted_record_.timestamps_.set_data(reserved_begin, timestamps.data(), size);
    deleted_record_.uids_.set_data(reserved_begin, uids.data(), size);
    deleted_record_.ack_responder_.AddSegment(reserved_begin, reserved_begin + size);
    return Status::OK();
}

int64_t
SegmentGrowingImpl::GetMemoryUsageInBytes() const {
    int64_t total_bytes = 0;
    auto chunk_rows = segcore_config_.get_chunk_rows();
    int64_t ins_n = upper_align(record_.reserved, chunk_rows);
    total_bytes += ins_n * (schema_->get_total_sizeof() + 16 + 1);
    int64_t del_n = upper_align(deleted_record_.reserved, chunk_rows);
    total_bytes += del_n * (16 * 2);
    return total_bytes;
}

SpanBase
SegmentGrowingImpl::chunk_data_impl(FieldOffset field_offset, int64_t chunk_id) const {
    auto vec = get_insert_record().get_field_data_base(field_offset);
    return vec->get_span_base(chunk_id);
}

int64_t
SegmentGrowingImpl::num_chunk() const {
    auto size = get_insert_record().ack_responder_.GetAck();
    return upper_div(size, segcore_config_.get_chunk_rows());
}

void
SegmentGrowingImpl::vector_search(int64_t vec_count,
                                  query::SearchInfo search_info,
                                  const void* query_data,
                                  int64_t query_count,
                                  Timestamp timestamp,
                                  const BitsetView& bitset,
                                  SearchResult& output) const {
    auto& sealed_indexing = this->get_sealed_indexing_record();
    if (sealed_indexing.is_ready(search_info.field_offset_)) {
        query::SearchOnSealed(this->get_schema(), sealed_indexing, search_info, query_data, query_count, bitset, output,
                              id_);
    } else {
        SearchOnGrowing(*this, vec_count, search_info, query_data, query_count, bitset, output);
    }
}

void
SegmentGrowingImpl::bulk_subscript(FieldOffset field_offset,
                                   const int64_t* seg_offsets,
                                   int64_t count,
                                   void* output) const {
    // TODO: support more types
    auto vec_ptr = record_.get_field_data_base(field_offset);
    auto& field_meta = schema_->operator[](field_offset);
    if (field_meta.is_vector()) {
        if (field_meta.get_data_type() == DataType::VECTOR_FLOAT) {
            bulk_subscript_impl<FloatVector>(field_meta.get_sizeof(), *vec_ptr, seg_offsets, count, output);
        } else if (field_meta.get_data_type() == DataType::VECTOR_BINARY) {
            bulk_subscript_impl<BinaryVector>(field_meta.get_sizeof(), *vec_ptr, seg_offsets, count, output);
        } else {
            PanicInfo("logical error");
        }
        return;
    }

    AssertInfo(!field_meta.is_vector(), "Scalar field meta type is vector type");
    switch (field_meta.get_data_type()) {
        case DataType::BOOL: {
            bulk_subscript_impl<bool>(*vec_ptr, seg_offsets, count, false, output);
            break;
        }
        case DataType::INT8: {
            bulk_subscript_impl<int8_t>(*vec_ptr, seg_offsets, count, -1, output);
            break;
        }
        case DataType::INT16: {
            bulk_subscript_impl<int16_t>(*vec_ptr, seg_offsets, count, -1, output);
            break;
        }
        case DataType::INT32: {
            bulk_subscript_impl<int32_t>(*vec_ptr, seg_offsets, count, -1, output);
            break;
        }
        case DataType::INT64: {
            bulk_subscript_impl<int64_t>(*vec_ptr, seg_offsets, count, -1, output);
            break;
        }
        case DataType::FLOAT: {
            bulk_subscript_impl<float>(*vec_ptr, seg_offsets, count, -1.0, output);
            break;
        }
        case DataType::DOUBLE: {
            bulk_subscript_impl<double>(*vec_ptr, seg_offsets, count, -1.0, output);
            break;
        }
        default: {
            PanicInfo("unsupported type");
        }
    }
}

template <typename T>
void
SegmentGrowingImpl::bulk_subscript_impl(int64_t element_sizeof,
                                        const VectorBase& vec_raw,
                                        const int64_t* seg_offsets,
                                        int64_t count,
                                        void* output_raw) const {
    static_assert(IsVector<T>);
    auto vec_ptr = dynamic_cast<const ConcurrentVector<T>*>(&vec_raw);
    AssertInfo(vec_ptr, "Pointer of vec_raw is nullptr");
    auto& vec = *vec_ptr;
    std::vector<uint8_t> empty(element_sizeof, 0);
    auto output_base = reinterpret_cast<char*>(output_raw);
    for (int i = 0; i < count; ++i) {
        auto dst = output_base + i * element_sizeof;
        auto offset = seg_offsets[i];
        const uint8_t* src = (offset == INVALID_SEG_OFFSET ? empty.data() : (const uint8_t*)vec.get_element(offset));
        memcpy(dst, src, element_sizeof);
    }
}

template <typename T>
void
SegmentGrowingImpl::bulk_subscript_impl(
    const VectorBase& vec_raw, const int64_t* seg_offsets, int64_t count, T default_value, void* output_raw) const {
    static_assert(IsScalar<T>);
    auto vec_ptr = dynamic_cast<const ConcurrentVector<T>*>(&vec_raw);
    AssertInfo(vec_ptr, "Pointer of vec_raw is nullptr");
    auto& vec = *vec_ptr;
    auto output = reinterpret_cast<T*>(output_raw);
    for (int64_t i = 0; i < count; ++i) {
        auto offset = seg_offsets[i];
        output[i] = (offset == INVALID_SEG_OFFSET ? default_value : vec[offset]);
    }
}

void
SegmentGrowingImpl::bulk_subscript(SystemFieldType system_type,
                                   const int64_t* seg_offsets,
                                   int64_t count,
                                   void* output) const {
    switch (system_type) {
        case SystemFieldType::Timestamp:
            PanicInfo("timestamp unsupported");
        case SystemFieldType::RowId:
            bulk_subscript_impl<int64_t>(this->record_.uids_, seg_offsets, count, INVALID_ID, output);
            break;
        default:
            PanicInfo("unknown subscript fields");
    }
}

// copied from stack overflow
template <typename T>
std::vector<size_t>
sort_indexes(const T* src, int64_t size) {
    // initialize original index locations
    std::vector<size_t> idx(size);
    iota(idx.begin(), idx.end(), 0);

    // sort indexes based on comparing values in v
    // using std::stable_sort instead of std::sort
    // to avoid unnecessary index re-orderings
    // when v contains elements of equal values
    std::stable_sort(idx.begin(), idx.end(), [src](size_t i1, size_t i2) { return src[i1] < src[i2]; });

    return idx;
}

void
SegmentGrowingImpl::Insert(int64_t reserved_offset,
                           int64_t size,
                           const int64_t* row_ids_raw,
                           const Timestamp* timestamps_raw,
                           const ColumnBasedRawData& values) {
    auto indexes = sort_indexes(timestamps_raw, size);
    std::vector<Timestamp> timestamps(size);
    std::vector<idx_t> row_ids(size);
    AssertInfo(values.count == size, "Insert values count not equal to insert size");
    for (int64_t i = 0; i < size; ++i) {
        auto offset = indexes[i];
        timestamps[i] = timestamps_raw[offset];
        row_ids[i] = row_ids_raw[i];
    }
    std::vector<aligned_vector<uint8_t>> columns_data;

    for (int field_offset = 0; field_offset < schema_->size(); ++field_offset) {
        auto& field_meta = schema_->operator[](FieldOffset(field_offset));
        aligned_vector<uint8_t> column;
        auto element_sizeof = field_meta.get_sizeof();
        auto& src_vec = values.columns_[field_offset];
        AssertInfo(src_vec.size() == element_sizeof * size, "Vector size is not aligned");
        for (int64_t i = 0; i < size; ++i) {
            auto offset = indexes[i];
            auto beg = src_vec.data() + offset * element_sizeof;
            column.insert(column.end(), beg, beg + element_sizeof);
        }
        columns_data.emplace_back(std::move(column));
    }
    do_insert(reserved_offset, size, row_ids.data(), timestamps.data(), columns_data);
}

std::vector<SegOffset>
SegmentGrowingImpl::search_ids(const BitsetType& bitset, Timestamp timestamp) const {
    std::vector<SegOffset> res_offsets;

    for (int i = 0; i < bitset.size(); i++) {
        if (bitset[i]) {
            SegOffset the_offset(-1);
            auto offset = SegOffset(i);
            if (record_.timestamps_[offset.get()] < timestamp) {
                the_offset = std::max(the_offset, offset);
            }

            if (the_offset == SegOffset(-1)) {
                continue;
            }
            res_offsets.push_back(the_offset);
        }
    }
    return res_offsets;
}

std::vector<SegOffset>
SegmentGrowingImpl::search_ids(const BitsetView& bitset, Timestamp timestamp) const {
    std::vector<SegOffset> res_offsets;

    for (int i = 0; i < bitset.size(); ++i) {
        if (!bitset.test(i)) {
            SegOffset the_offset(-1);
            auto offset = SegOffset(i);
            if (record_.timestamps_[offset.get()] < timestamp) {
                the_offset = std::max(the_offset, offset);
            }

            if (the_offset == SegOffset(-1)) {
                continue;
            }
            res_offsets.push_back(the_offset);
        }
    }
    return res_offsets;
}

std::pair<std::unique_ptr<IdArray>, std::vector<SegOffset>>
SegmentGrowingImpl::search_ids(const IdArray& id_array, Timestamp timestamp) const {
    AssertInfo(id_array.has_int_id(), "Id array doesn't have int_id element");
    auto& src_int_arr = id_array.int_id();
    auto res_id_arr = std::make_unique<IdArray>();
    auto res_int_id_arr = res_id_arr->mutable_int_id();
    std::vector<SegOffset> res_offsets;
    for (auto uid : src_int_arr.data()) {
        auto [iter_b, iter_e] = uid2offset_.equal_range(uid);
        SegOffset the_offset(-1);
        for (auto iter = iter_b; iter != iter_e; ++iter) {
            auto offset = SegOffset(iter->second);
            if (record_.timestamps_[offset.get()] < timestamp) {
                the_offset = std::max(the_offset, offset);
            }
            // if not found, skip
            if (the_offset == SegOffset(-1)) {
                continue;
            }
            res_int_id_arr->add_data(uid);
            res_offsets.push_back(the_offset);
        }
    }
    return {std::move(res_id_arr), std::move(res_offsets)};
}

std::string
SegmentGrowingImpl::debug() const {
    return "Growing\n";
}

int64_t
SegmentGrowingImpl::get_active_count(Timestamp ts) const {
    auto row_count = this->get_row_count();
    auto& ts_vec = this->get_insert_record().timestamps_;
    auto iter = std::upper_bound(boost::make_counting_iterator((int64_t)0), boost::make_counting_iterator(row_count),
                                 ts, [&](Timestamp ts, int64_t index) { return ts < ts_vec[index]; });
    return *iter;
}

void
SegmentGrowingImpl::mask_with_timestamps(BitsetType& bitset_chunk, Timestamp timestamp) const {
    // DO NOTHING
}

}  // namespace milvus::segcore

max_stars_repo_name: bcEric/milvus

max_issues_repo_name: bcEric/milvus

max_forks_repo_name: bcEric/milvus


text:
// Copyright (c) 2015-2016
// Author: Chrono Law
#ifndef _NGX_VAR_HPP
#define _NGX_VAR_HPP

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

#include "NgxString.hpp"
#include "NgxException.hpp"

class NgxVariableValue final : public NgxWrapper<ngx_variable_value_t>
{
public:
    typedef NgxWrapper<ngx_variable_value_t> super_type;
    typedef NgxVariableValue this_type;
public:
    NgxVariableValue(ngx_variable_value_t* v):
        super_type(v)
    {}

    ~NgxVariableValue() = default;
public:
    void set(ngx_str_t& str)
    {
        set(&str);
    }

    void set(ngx_str_t* str)
    {
        get()->len = str->len;
        get()->data = str->data;

        get()->valid = true;
        get()->not_found = false;
        get()->no_cacheable = false;
    }

    void clear()
    {
        get()->len = 0;
        get()->data = nullptr;

        get()->valid = false;
        get()->not_found = true;
    }
public:
    bool valid() const
    {
        return get() && get()->valid && !get()->not_found;
    }

    ngx_str_t str() const
    {
        return valid()?
               ngx_str_t{get()->len, get()->data}:
               ngx_str_t ngx_null_string;
    }
};

inline namespace ngx_variable_types {
#ifdef ngx_http_variable

typedef ngx_http_request_t          ngx_variable_ctx_t;
typedef ngx_http_variable_t         ngx_variable_t;
typedef ngx_http_set_variable_pt    ngx_set_variable_pt;
typedef ngx_http_get_variable_pt    ngx_get_variable_pt;

static auto ngx_add_variable = &ngx_http_add_variable;
static auto ngx_get_variable = &ngx_http_get_variable;

#else   //ngx_stream_variable

typedef ngx_stream_session_t        ngx_variable_ctx_t;
typedef ngx_stream_variable_t       ngx_variable_t;
typedef ngx_stream_set_variable_pt  ngx_set_variable_pt;
typedef ngx_stream_get_variable_pt  ngx_get_variable_pt;

static auto ngx_add_variable = &ngx_stream_add_variable;
static auto ngx_get_variable = &ngx_stream_get_variable;

#endif
}

// step 1: var = ngx_http_add_variable(cf, name, flags);
// step 2: var.handler(func);
class NgxVariable final : public NgxWrapper<ngx_variable_t>
{
public:
    typedef NgxWrapper<ngx_variable_t> super_type;
    typedef NgxVariable this_type;
public:
    NgxVariable(ngx_variable_t* v):
        super_type(v)
    {}

    ~NgxVariable() = default;
public:
    template<typename T>    // T= uintptr_t
    void handler(ngx_set_variable_pt p, T data = nullptr) const
    {
        get()->set_handler = p;
        get()->data = reinterpret_cast<uintptr_t>(data);
    }

    template<typename T>    // T= uintptr_t
    void handler(ngx_get_variable_pt p, T data = nullptr) const
    {
        get()->get_handler = p;
        get()->data = reinterpret_cast<uintptr_t>(data);
    }

};

template<ngx_variable_t*(*get_vars)() = nullptr>
class NgxVariables final
{
public:
    typedef NgxVariables this_type;
    typedef NgxVariable var_type;
public:
    static ngx_int_t init(ngx_conf_t *cf)
    {
        if(!get_vars)
        {
            return NGX_OK;
        }

        for (auto v = get_vars(); v->name.len; ++v)
        {
            var_type var = ngx_add_variable(cf, &v->name, v->flags);

            NgxException::fail(!var);

            var.handler(v->get_handler, v->data);
        }

        return NGX_OK;
    }
public:
    static var_type create(ngx_conf_t *cf, ngx_str_t& name, ngx_uint_t flags = 0)
    {
        auto p = ngx_add_variable(cf, &name, flags);

        NgxException::require(p);

        return p;
    }
};

#include <boost/core/explicit_operator_bool.hpp>

class NgxVariableValueProxy final
{
public:
    typedef NgxVariableValueProxy this_type;
    typedef boost::string_ref string_ref_type;
public:
    NgxVariableValueProxy(ngx_variable_value_t* v, ngx_variable_ctx_t* r):
        m_v(v), m_pool(r)
    {}
    ~NgxVariableValueProxy() = default;
public:
    operator ngx_str_t() const
    {
        return m_v.str();
    }

    void operator=(string_ref_type value)
    {
        if(!m_v.valid())
        {
            return;
        }

        if(value.empty())
        {
            m_v.clear();
            return;
        }

        auto s = m_pool.dup(value);

        m_v.set(s);
    }
public:
    BOOST_EXPLICIT_OPERATOR_BOOL()

    // check invalid
    bool operator!() const
    {
        return !m_v.valid();
    }

public:
    template<typename T>
    friend T& operator<<(T& o, const this_type& x)
    {
        o << x.m_v.str();
        return o;
    }
private:
    NgxVariableValue m_v;
    NgxPool m_pool;
};

class NgxVarManager final
{
public:
    typedef NgxVarManager this_type;
    typedef boost::string_ref string_ref_type;
public:
    NgxVarManager(ngx_variable_ctx_t* r): m_r(r)
    {}
    ~NgxVarManager() = default;
public:
    ngx_str_t get(string_ref_type name) const
    {
        auto v = var(name);

        return NgxVariableValue(v).str();
    }

    void set(string_ref_type name, string_ref_type value) const
    {
        auto s = NgxPool(m_r).dup(value);

        auto v = var(name);

        NgxVariableValue(v).set(s);
    }

    void clear(string_ref_type name) const
    {
        auto v = var(name);

        NgxVariableValue(v).clear();
    }
public:
    NgxVariableValueProxy operator[](string_ref_type name) const
    {
        auto v = var(name);

        return NgxVariableValueProxy(v, m_r);
    }
private:
    ngx_variable_ctx_t* m_r = nullptr;
private:
    ngx_variable_value_t* var(string_ref_type name) const
    {
        auto s = NgxPool(m_r).dup(name);
        auto key = ngx_hash_strlow(s.data, s.data, s.len);

        return ngx_get_variable(m_r, &s, key);
    }
};

#endif  //_NGX_VAR_HPP