<commit_before>#pragma once
#include <cstdint>
#include <depthai-shared/common/optional.hpp>
#include <nlohmann/json.hpp>
#include <vector>

#include "DatatypeEnum.hpp"
#include "RawBuffer.hpp"

namespace dai {

/**
 * Median filter config for disparity post-processing
 */
enum class MedianFilter : int32_t { MEDIAN_OFF = 0, KERNEL_3x3 = 3, KERNEL_5x5 = 5, KERNEL_7x7 = 7 };

/// RawStereoDepthConfig configuration structure
struct RawStereoDepthConfig : public RawBuffer {
    using MedianFilter = dai::MedianFilter;

    struct AlgorithmControl {
        /**
         * Computes and combines disparities in both L-R and R-L directions, and combine them.
         * For better occlusion handling
         */
        bool enableLeftRightCheck = true;

        /**
         * Disparity range increased from 95 to 190, combined from full resolution and downscaled images.
         * Suitable for short range objects
         */
        bool enableExtended = false;

        /**
         * Computes disparity with sub-pixel interpolation (5 fractional bits), suitable for long range
         */
        bool enableSubpixel = false;

        /**
         * Left-right check threshold for left-right, right-left disparity map combine, 0..128
         * Used only when left-right check mode is enabled.
         * Defines the maximum difference between the confidence of pixels from left-right and right-left confidence maps
         */
        std::int32_t leftRightCheckThreshold = 4;

        /**
         * Number of fractional bits for subpixel mode.
         * Valid values: 3,4,5.
         * Defines the number of fractional disparities: 2^x.
         * Median filter postprocessing is supported only for 3 fractional bits.
         */
        std::int32_t subpixelFractionalBits = 3;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(AlgorithmControl, enableLeftRightCheck, enableExtended, enableSubpixel, leftRightCheckThreshold, subpixelFractionalBits);
    };

    /**
     * Controls the flow of stereo algorithm: left-right check, subpixel etc.
     */
    AlgorithmControl algorithmControl;

    struct PostProcessing {
        /**
         * Set kernel size for disparity/depth median filtering, or disable
         */
        MedianFilter median = MedianFilter::KERNEL_5x5;

        /**
         * Sigma value for bilateral filter. 0 means disabled
         * A larger value of the parameter means that farther colors within the pixel neighborhood will be mixed together.
         */
        std::int16_t bilateralSigmaValue = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(PostProcessing, median, bilateralSigmaValue);
    };

    /**
     * Controls the postprocessing of disparity and/or depth map.
     */
    PostProcessing postProcessing;

    /**
     * The basic cost function used by the Stereo Accelerator for matching the left and right images is the Census
     * Transform. It works on a block of pixels and computes a bit vector which represents the structure of the
     * image in that block.
     * There are two types of Census Transform based on how the middle pixel is used:
     * Classic Approach and Modified Census. The comparisons that are made between pixels can be or not thresholded.
     * In some cases a mask can be applied to filter out only specific bits from the entire bit stream.
     * All these approaches are:
     * Classic Approach: Uses middle pixel to compare against all its neighbors over a defined window. Each
     * comparison results in a new bit, that is 0 if central pixel is smaller, or 1 if is it bigger than its neighbor.
     * Modified Census Transform: same as classic Census Transform, but instead of comparing central pixel
     * with its neighbors, the window mean will be compared with each pixel over the window.
     * Thresholding Census Transform: same as classic Census Transform, but it is not enough that a
     * neighbor pixel to be bigger than the central pixel, it must be significant bigger (based on a threshold).
     * Census Transform with Mask: same as classic Census Transform, but in this case not all of the pixel from
     * the support window are part of the binary descriptor. We use a ma sk “M” to define which pixels are part
     * of the binary descriptor (1), and which pixels should be skipped (0).
     */
    struct CensusTransform {
        /**
         * Census transform kernel size possible values.
         */
        enum class KernelSize : std::int32_t { AUTO = -1, KERNEL_5x5 = 0, KERNEL_7x7, KERNEL_7x9 };

        /**
         * Census transform kernel size.
         */
        KernelSize kernelSize = KernelSize::AUTO;

        /**
         * Census transform mask, default: auto, mask is set based on resolution and kernel size.
         * Disabled for 400p input resolution.
         * Enabled for 720p.
         * 0XA82415 for 5x5 census transform kernel.
         * 0XAA02A8154055 for 7x7 census transform kernel.
         * 0X2AA00AA805540155 for 7x9 census transform kernel.
         * Empirical values.
         */
        uint64_t kernelMask = 0;

        /**
         * If enabled, each pixel in the window is compared with the mean window value instead of the central pixel.
         */
        bool enableMeanMode = true;

        /**
         * Census transform comparation treshold value.
         */
        uint32_t threshold = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(CensusTransform, kernelSize, kernelMask, enableMeanMode, threshold);
    };

    /**
     * Census transform settings.
     */
    CensusTransform censusTransform;

    /**
     * The matching cost is way of measuring the similarity of image locations in stereo correspondence
     * algorithm. Based on the configuration parameters and based on the descriptor type, a linear equation
     * is applied to computing the cost for each candidate disparity at each pixel.
     */
    struct CostMatching {
        /**
         * Disparity search range: 64 or 96 pixels are supported by the HW.
         */
        enum class DisparityWidth : std::uint32_t { DISPARITY_64, DISPARITY_96 };

        /**
         * Disparity search range, default 96 pixels.
         */
        DisparityWidth disparityWidth = DisparityWidth::DISPARITY_96;

        /**
         * Disparity companding using sparse matching.
         * Matching pixel by pixel for N disparities.
         * Matching every 2nd pixel for M disparitites.
         * Matching every 4th pixel for T disparities.
         * In case of 96 disparities: N=48, M=32, T=16.
         * This way the search range is extended to 176 disparities, by sparse matching.
         * Note: when enabling this flag only depth map will be affected, disparity map is not.
         */
        bool enableCompanding = false;

        /**
         * Used only for debug purposes, SW postprocessing handled only invalid value of 0 properly.
         */
        uint8_t invalidDisparityValue = 0;

        /**
         * Disparities with confidence value under this threshold are accepted.
         * Higher confidence threshold means disparities with less confidence are accepted too.
         */
        uint8_t confidenceThreshold = 230;

        /**
         * The linear equation applied for computing the cost is:
         * COMB_COST = α*AD + β*(CTC<<3).
         * CLAMP(COMB_COST >> 5, threshold).
         * Where AD is the Absolute Difference between 2 pixels values.
         * CTC is the Census Transform Cost between 2 pixels, based on Hamming distance (xor).
         * The α and β parameters are subject to fine fine tuning by the user.
         */
        struct LinearEquationParameters {
            uint8_t alpha = 0;
            uint8_t beta = 2;
            uint8_t threshold = 127;

            NLOHMANN_DEFINE_TYPE_INTRUSIVE(LinearEquationParameters, alpha, beta, threshold);
        };

        /**
         * Cost calculation linear equation parameters.
         */
        LinearEquationParameters linearEquationParameters;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(CostMatching, disparityWidth, enableCompanding, invalidDisparityValue, confidenceThreshold, linearEquationParameters);
    };

    /**
     * Cost matching settings.
     */
    CostMatching costMatching;

    /**
     * Cost Aggregation is based on Semi Global Block Matching (SGBM). This algorithm uses a semi global
     * technique to aggregate the cost map. Ultimately the idea is to build inertia into the stereo algorithm. If
     * a pixel has very little texture information, then odds are the correct disparity for this pixel is close to
     * that of the previous pixel considered. This means that we get improved results in areas with low
     * texture.
     */
    struct CostAggregation {
        static constexpr const int defaultPenaltyP1 = 250;
        static constexpr const int defaultPenaltyP2 = 500;

        /**
         * Cost calculation linear equation parameters.
         */
        uint8_t divisionFactor = 1;

        /**
         * Horizontal P1 penalty cost parameter.
         */
        uint16_t horizontalPenaltyCostP1 = defaultPenaltyP1;
        /**
         * Horizontal P2 penalty cost parameter.
         */
        uint16_t horizontalPenaltyCostP2 = defaultPenaltyP2;

        /**
         * Vertical P1 penalty cost parameter.
         */
        uint16_t verticalPenaltyCostP1 = defaultPenaltyP1;
        /**
         * Vertical P2 penalty cost parameter.
         */
        uint16_t verticalPenaltyCostP2 = defaultPenaltyP2;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(
            CostAggregation, divisionFactor, horizontalPenaltyCostP1, horizontalPenaltyCostP2, verticalPenaltyCostP1, verticalPenaltyCostP2);
    };

    /**
     * Cost aggregation settings.
     */
    CostAggregation costAggregation;

    void serialize(std::vector<std::uint8_t>& metadata, DatatypeEnum& datatype) const override {
        nlohmann::json j = *this;
        metadata = nlohmann::json::to_msgpack(j);
        datatype = DatatypeEnum::StereoDepthConfig;
    };

    NLOHMANN_DEFINE_TYPE_INTRUSIVE(RawStereoDepthConfig, algorithmControl, postProcessing, censusTransform, costMatching, costAggregation);
};

}  // namespace dai
<commit_msg>Increase LR-check threshold to 10; disparity confidence threshold to 245 by default<commit_after>#pragma once
#include <cstdint>
#include <depthai-shared/common/optional.hpp>
#include <nlohmann/json.hpp>
#include <vector>

#include "DatatypeEnum.hpp"
#include "RawBuffer.hpp"

namespace dai {

/**
 * Median filter config for disparity post-processing
 */
enum class MedianFilter : int32_t { MEDIAN_OFF = 0, KERNEL_3x3 = 3, KERNEL_5x5 = 5, KERNEL_7x7 = 7 };

/// RawStereoDepthConfig configuration structure
struct RawStereoDepthConfig : public RawBuffer {
    using MedianFilter = dai::MedianFilter;

    struct AlgorithmControl {
        /**
         * Computes and combines disparities in both L-R and R-L directions, and combine them.
         * For better occlusion handling
         */
        bool enableLeftRightCheck = true;

        /**
         * Disparity range increased from 95 to 190, combined from full resolution and downscaled images.
         * Suitable for short range objects
         */
        bool enableExtended = false;

        /**
         * Computes disparity with sub-pixel interpolation (5 fractional bits), suitable for long range
         */
        bool enableSubpixel = false;

        /**
         * Left-right check threshold for left-right, right-left disparity map combine, 0..128
         * Used only when left-right check mode is enabled.
         * Defines the maximum difference between the confidence of pixels from left-right and right-left confidence maps
         */
        std::int32_t leftRightCheckThreshold = 10;

        /**
         * Number of fractional bits for subpixel mode.
         * Valid values: 3,4,5.
         * Defines the number of fractional disparities: 2^x.
         * Median filter postprocessing is supported only for 3 fractional bits.
         */
        std::int32_t subpixelFractionalBits = 3;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(AlgorithmControl, enableLeftRightCheck, enableExtended, enableSubpixel, leftRightCheckThreshold, subpixelFractionalBits);
    };

    /**
     * Controls the flow of stereo algorithm: left-right check, subpixel etc.
     */
    AlgorithmControl algorithmControl;

    struct PostProcessing {
        /**
         * Set kernel size for disparity/depth median filtering, or disable
         */
        MedianFilter median = MedianFilter::KERNEL_5x5;

        /**
         * Sigma value for bilateral filter. 0 means disabled
         * A larger value of the parameter means that farther colors within the pixel neighborhood will be mixed together.
         */
        std::int16_t bilateralSigmaValue = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(PostProcessing, median, bilateralSigmaValue);
    };

    /**
     * Controls the postprocessing of disparity and/or depth map.
     */
    PostProcessing postProcessing;

    /**
     * The basic cost function used by the Stereo Accelerator for matching the left and right images is the Census
     * Transform. It works on a block of pixels and computes a bit vector which represents the structure of the
     * image in that block.
     * There are two types of Census Transform based on how the middle pixel is used:
     * Classic Approach and Modified Census. The comparisons that are made between pixels can be or not thresholded.
     * In some cases a mask can be applied to filter out only specific bits from the entire bit stream.
     * All these approaches are:
     * Classic Approach: Uses middle pixel to compare against all its neighbors over a defined window. Each
     * comparison results in a new bit, that is 0 if central pixel is smaller, or 1 if is it bigger than its neighbor.
     * Modified Census Transform: same as classic Census Transform, but instead of comparing central pixel
     * with its neighbors, the window mean will be compared with each pixel over the window.
     * Thresholding Census Transform: same as classic Census Transform, but it is not enough that a
     * neighbor pixel to be bigger than the central pixel, it must be significant bigger (based on a threshold).
     * Census Transform with Mask: same as classic Census Transform, but in this case not all of the pixel from
     * the support window are part of the binary descriptor. We use a ma sk “M” to define which pixels are part
     * of the binary descriptor (1), and which pixels should be skipped (0).
     */
    struct CensusTransform {
        /**
         * Census transform kernel size possible values.
         */
        enum class KernelSize : std::int32_t { AUTO = -1, KERNEL_5x5 = 0, KERNEL_7x7, KERNEL_7x9 };

        /**
         * Census transform kernel size.
         */
        KernelSize kernelSize = KernelSize::AUTO;

        /**
         * Census transform mask, default: auto, mask is set based on resolution and kernel size.
         * Disabled for 400p input resolution.
         * Enabled for 720p.
         * 0XA82415 for 5x5 census transform kernel.
         * 0XAA02A8154055 for 7x7 census transform kernel.
         * 0X2AA00AA805540155 for 7x9 census transform kernel.
         * Empirical values.
         */
        uint64_t kernelMask = 0;

        /**
         * If enabled, each pixel in the window is compared with the mean window value instead of the central pixel.
         */
        bool enableMeanMode = true;

        /**
         * Census transform comparation treshold value.
         */
        uint32_t threshold = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(CensusTransform, kernelSize, kernelMask, enableMeanMode, threshold);
    };

    /**
     * Census transform settings.
     */
    CensusTransform censusTransform;

    /**
     * The matching cost is way of measuring the similarity of image locations in stereo correspondence
     * algorithm. Based on the configuration parameters and based on the descriptor type, a linear equation
     * is applied to computing the cost for each candidate disparity at each pixel.
     */
    struct CostMatching {
        /**
         * Disparity search range: 64 or 96 pixels are supported by the HW.
         */
        enum class DisparityWidth : std::uint32_t { DISPARITY_64, DISPARITY_96 };

        /**
         * Disparity search range, default 96 pixels.
         */
        DisparityWidth disparityWidth = DisparityWidth::DISPARITY_96;

        /**
         * Disparity companding using sparse matching.
         * Matching pixel by pixel for N disparities.
         * Matching every 2nd pixel for M disparitites.
         * Matching every 4th pixel for T disparities.
         * In case of 96 disparities: N=48, M=32, T=16.
         * This way the search range is extended to 176 disparities, by sparse matching.
         * Note: when enabling this flag only depth map will be affected, disparity map is not.
         */
        bool enableCompanding = false;

        /**
         * Used only for debug purposes, SW postprocessing handled only invalid value of 0 properly.
         */
        uint8_t invalidDisparityValue = 0;

        /**
         * Disparities with confidence value under this threshold are accepted.
         * Higher confidence threshold means disparities with less confidence are accepted too.
         */
        uint8_t confidenceThreshold = 245;

        /**
         * The linear equation applied for computing the cost is:
         * COMB_COST = α*AD + β*(CTC<<3).
         * CLAMP(COMB_COST >> 5, threshold).
         * Where AD is the Absolute Difference between 2 pixels values.
         * CTC is the Census Transform Cost between 2 pixels, based on Hamming distance (xor).
         * The α and β parameters are subject to fine fine tuning by the user.
         */
        struct LinearEquationParameters {
            uint8_t alpha = 0;
            uint8_t beta = 2;
            uint8_t threshold = 127;

            NLOHMANN_DEFINE_TYPE_INTRUSIVE(LinearEquationParameters, alpha, beta, threshold);
        };

        /**
         * Cost calculation linear equation parameters.
         */
        LinearEquationParameters linearEquationParameters;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(CostMatching, disparityWidth, enableCompanding, invalidDisparityValue, confidenceThreshold, linearEquationParameters);
    };

    /**
     * Cost matching settings.
     */
    CostMatching costMatching;

    /**
     * Cost Aggregation is based on Semi Global Block Matching (SGBM). This algorithm uses a semi global
     * technique to aggregate the cost map. Ultimately the idea is to build inertia into the stereo algorithm. If
     * a pixel has very little texture information, then odds are the correct disparity for this pixel is close to
     * that of the previous pixel considered. This means that we get improved results in areas with low
     * texture.
     */
    struct CostAggregation {
        static constexpr const int defaultPenaltyP1 = 250;
        static constexpr const int defaultPenaltyP2 = 500;

        /**
         * Cost calculation linear equation parameters.
         */
        uint8_t divisionFactor = 1;

        /**
         * Horizontal P1 penalty cost parameter.
         */
        uint16_t horizontalPenaltyCostP1 = defaultPenaltyP1;
        /**
         * Horizontal P2 penalty cost parameter.
         */
        uint16_t horizontalPenaltyCostP2 = defaultPenaltyP2;

        /**
         * Vertical P1 penalty cost parameter.
         */
        uint16_t verticalPenaltyCostP1 = defaultPenaltyP1;
        /**
         * Vertical P2 penalty cost parameter.
         */
        uint16_t verticalPenaltyCostP2 = defaultPenaltyP2;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(
            CostAggregation, divisionFactor, horizontalPenaltyCostP1, horizontalPenaltyCostP2, verticalPenaltyCostP1, verticalPenaltyCostP2);
    };

    /**
     * Cost aggregation settings.
     */
    CostAggregation costAggregation;

    void serialize(std::vector<std::uint8_t>& metadata, DatatypeEnum& datatype) const override {
        nlohmann::json j = *this;
        metadata = nlohmann::json::to_msgpack(j);
        datatype = DatatypeEnum::StereoDepthConfig;
    };

    NLOHMANN_DEFINE_TYPE_INTRUSIVE(RawStereoDepthConfig, algorithmControl, postProcessing, censusTransform, costMatching, costAggregation);
};

}  // namespace dai
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP
#define RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP

#include "level.hpp"
#include "packer_pack.hpp"
#include "packer_unpack.hpp"

#include <mlk/filesystem/filesystem.h>

#include <map>
#include <string>

namespace rj
{
	using level_id = std::string;

	class level_manager
	{
		mlk::fs::dir_handle m_dirh;
		mlk::fs::file_handle m_filemgr;
		const std::string& m_abs_path;

		std::map<level_id, level> m_loaded_levels;

	public:
		level_manager(const std::string& abs_level_path) :
			m_dirh{abs_level_path},
			m_abs_path{m_dirh.get_path()}
		{this->init();}

		const level& load_level(const level_id& id)
		{
			this->load_to_mgr(id, this->make_path(id));
			if(m_loaded_levels.find(id) == std::end(m_loaded_levels))
				throw std::runtime_error{"error while open level"};
			return m_loaded_levels[id];
		}

		bool save_level(const level_packer<packer_mode::pack>& lv, const level_id& id)
		{
			if(!m_filemgr.reopen(this->make_path(id), std::ios::out | std::ios::trunc))
				return false;
			m_filemgr.write(lv.packed_data());
			m_filemgr.close();
			return true;
		}

		const level& get_level(const level_id& id) const
		{return m_loaded_levels.at(this->make_id(id));}

		auto get_levels() const noexcept
		-> const decltype(m_loaded_levels)&
		{return m_loaded_levels;}

		std::size_t num_levels() const noexcept
		{return m_loaded_levels.size();}

	private:
		void init()
		{
			mlk::lout("rj::level_manager") << "loading levels recursive from directory '" << m_abs_path << "'...";
			auto content(m_dirh.get_content<true>());
			auto count(0);
			for(auto& a : content)
				if(a.type == mlk::fs::item_type::file)
				{
					this->load_to_mgr(a.name, a.path);
					++count;
				}
			mlk::lout("rj::level_manager") << "loaded " << count << " levels";
		}

		void load_to_mgr(const level_id& id, const std::string& path)
		{
			if(!m_filemgr.reopen(path, std::ios::in))
				return;

			auto data(m_filemgr.read_all());
			level_packer<packer_mode::unpack> unpacker{data};
			m_loaded_levels[id] = unpacker.get_level();
			mlk::lout("rj::level_manager") << "loaded level '" << path << "' " << (m_loaded_levels[id].is_valid() ? "(valid)" : "(invalid)");
		}

		std::string make_path(const level_id& id) const noexcept
		{return m_abs_path + id + ".rjl";}

		level_id make_id(const std::string& str) const noexcept
		{
			auto result(str);
			if(str.find(".rjl") == std::string::npos)
				result += ".rjl";
			return result;
		}
	};
}

#endif // RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP
<commit_msg>level_manager: done make_id(...) better<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP
#define RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP

#include "level.hpp"
#include "packer_pack.hpp"
#include "packer_unpack.hpp"

#include <mlk/filesystem/filesystem.h>

#include <map>
#include <string>

namespace rj
{
	using level_id = std::string;

	class level_manager
	{
		mlk::fs::dir_handle m_dirh;
		mlk::fs::file_handle m_filemgr;
		const std::string& m_abs_path;

		std::map<level_id, level> m_loaded_levels;

	public:
		level_manager(const std::string& abs_level_path) :
			m_dirh{abs_level_path},
			m_abs_path{m_dirh.get_path()}
		{this->init();}

		const level& load_level(const level_id& id)
		{
			this->load_to_mgr(id, this->make_path(id));
			if(m_loaded_levels.find(id) == std::end(m_loaded_levels))
				throw std::runtime_error{"error while open level"};
			return m_loaded_levels[id];
		}

		bool save_level(const level_packer<packer_mode::pack>& lv, const level_id& id)
		{
			if(!m_filemgr.reopen(this->make_path(id), std::ios::out | std::ios::trunc))
				return false;
			m_filemgr.write(lv.packed_data());
			m_filemgr.close();
			return true;
		}

		const level& get_level(const level_id& id) const
		{return m_loaded_levels.at(this->make_id(id));}

		auto get_levels() const noexcept
		-> const decltype(m_loaded_levels)&
		{return m_loaded_levels;}

		std::size_t num_levels() const noexcept
		{return m_loaded_levels.size();}

	private:
		void init()
		{
			mlk::lout("rj::level_manager") << "loading levels recursive from directory '" << m_abs_path << "'...";
			auto content(m_dirh.get_content<true>());
			auto count(0);
			for(auto& a : content)
				if(a.type == mlk::fs::item_type::file)
				{
					this->load_to_mgr(a.name, a.path);
					++count;
				}
			mlk::lout("rj::level_manager") << "loaded " << count << " levels";
		}

		void load_to_mgr(const level_id& id, const std::string& path)
		{
			if(!m_filemgr.reopen(path, std::ios::in))
				return;

			auto data(m_filemgr.read_all());
			level_packer<packer_mode::unpack> unpacker{data};
			m_loaded_levels[id] = unpacker.get_level();
			mlk::lout("rj::level_manager") << "loaded level '" << path << "' " << (m_loaded_levels[id].is_valid() ? "(valid)" : "(invalid)");
		}

		std::string make_path(const level_id& id) const noexcept
		{return m_abs_path + id + ".rjl";}

		level_id make_id(const std::string& str) const noexcept
		{
			auto result(str);
			if(result.substr(result.size() - 4, 4) != ".rjl")
				result += ".rjl";
			return result;
		}
	};
}

#endif // RJ_SHARED_LEVEL_MANAGER_LEVEL_MANAGER_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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 "perfetto/base/thread_checker.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#endif

namespace perfetto {
namespace base {

namespace {
constexpr ThreadID kDetached = 0;

ThreadID CurrentThreadId() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return ::GetCurrentThreadId();
#else
  return pthread_self();
#endif
}
}  // namespace

ThreadChecker::ThreadChecker() {
  thread_id_.store(CurrentThreadId());
}

ThreadChecker::~ThreadChecker() = default;

ThreadChecker::ThreadChecker(const ThreadChecker& other) {
  thread_id_ = other.thread_id_.load();
}

ThreadChecker& ThreadChecker::operator=(const ThreadChecker& other) {
  thread_id_ = other.thread_id_.load();
  return *this;
}

bool ThreadChecker::CalledOnValidThread() const {
  auto self = CurrentThreadId();

  // Will re-attach if previously detached using DetachFromThread().
  auto prev_value = kDetached;
  if (thread_id_.compare_exchange_strong(prev_value, self))
    return true;
  return prev_value == self;
}

void ThreadChecker::DetachFromThread() {
  thread_id_.store(kDetached);
}

}  // namespace base
}  // namespace perfetto
<commit_msg>fix: work-around compile issue on mac<commit_after>/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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 "perfetto/base/thread_checker.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#endif

namespace perfetto {
namespace base {

namespace {
constexpr ThreadID kDetached{};

ThreadID CurrentThreadId() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  return ::GetCurrentThreadId();
#else
  return pthread_self();
#endif
}
}  // namespace

ThreadChecker::ThreadChecker() {
  thread_id_.store(CurrentThreadId());
}

ThreadChecker::~ThreadChecker() = default;

ThreadChecker::ThreadChecker(const ThreadChecker& other) {
  thread_id_ = other.thread_id_.load();
}

ThreadChecker& ThreadChecker::operator=(const ThreadChecker& other) {
  thread_id_ = other.thread_id_.load();
  return *this;
}

bool ThreadChecker::CalledOnValidThread() const {
  auto self = CurrentThreadId();

  // Will re-attach if previously detached using DetachFromThread().
  auto prev_value = kDetached;
  if (thread_id_.compare_exchange_strong(prev_value, self))
    return true;
  return prev_value == self;
}

void ThreadChecker::DetachFromThread() {
  thread_id_.store(kDetached);
}

}  // namespace base
}  // namespace perfetto
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <roomba_clean_actions/basic_cleanAction.h>

void doneCb(const actionlib::SimpleClientGoalState& state, const roomba_clean_actions::basic_cleanResultConstPtr& result) {
    ROS_INFO("Finished clean in state %s", state.toString().c_str());
    ROS_INFO("    Duration: %d, distance travelled: %d.  %f%% charge remaining.", result->seconds, result->millimeters, result->battery_charge);
    ros::shutdown();
}

void activeCb() {
    ROS_INFO("Cleaning task active.");
}

void feedbackCb(const roomba_clean_actions::basic_cleanFeedbackConstPtr& feedback) {
    //ROS_INFO("    Duration: %d, distance travelled: %d.  %f%% charge remaining.", feedback->seconds, feedback->millimeters, feedback->battery_charge);
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "run_clean");
    actionlib::SimpleActionClient<roomba_clean_actions::basic_cleanAction> ac("basic_clean", true);
    ROS_INFO("Waiting for server...");
    ac.waitForServer();
    roomba_clean_actions::basic_cleanGoal goal;
    goal.seconds = 1800;
    ac.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);
    ros::spin();
    return 0;
}
<commit_msg>SIGINT Handling and logging changes.<commit_after>#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <roomba_clean_actions/basic_cleanAction.h>
#include <signal.h>

actionlib::SimpleActionClient<roomba_clean_actions::basic_cleanAction> ac("basic_clean", true);

void interruptSignalHandler(int sig) {
  ac.cancelGoal();
  ros::shutdown();
}

void doneCb(const actionlib::SimpleClientGoalState& state, const roomba_clean_actions::basic_cleanResultConstPtr& result) {
  ROS_INFO("Finished clean in state %s", state.toString().c_str());
  ROS_INFO("    Duration: %d, distance travelled: %d.  %f%% charge remaining.", result->seconds, result->millimeters, result->battery_charge);
  ros::shutdown();
}

void activeCb() {
  ROS_INFO("Cleaning task active.");
}

void feedbackCb(const roomba_clean_actions::basic_cleanFeedbackConstPtr& feedback) {
  ROS_DEBUG("    Duration: %d, distance travelled: %d.  %f%% charge remaining.", feedback->seconds, feedback->millimeters, feedback->battery_charge);
}

int main(int argc, char** argv) {
  ros::init(argc, argv, "run_clean", ros::init_options::NoSigintHandler);
  ROS_INFO("Waiting for server...");
  signal(SIGINT, interruptSignalHandler);
  ac.waitForServer();
  roomba_clean_actions::basic_cleanGoal goal;
  goal.seconds = 1800;
  ac.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);
  ros::spin();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012-present Facebook, Inc.
 *
 * 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 <folly/experimental/symbolizer/Elf.h>

#include <fcntl.h>
#include <folly/portability/SysMman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <cstring>
#include <string>

#include <glog/logging.h>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>

#ifndef STT_GNU_IFUNC
#define STT_GNU_IFUNC 10
#endif

namespace folly {
namespace symbolizer {

ElfFile::ElfFile() noexcept
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {}

ElfFile::ElfFile(const char* name, bool readOnly)
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {
  open(name, readOnly);
}

void ElfFile::open(const char* name, bool readOnly) {
  const char* msg = "";
  int r = openNoThrow(name, readOnly, &msg);
  if (r == kSystemError) {
    throwSystemError(msg);
  } else {
    CHECK_EQ(r, kSuccess) << msg;
  }
}

int ElfFile::openNoThrow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
  strncat(filepath_, name, kFilepathMaxLen - 1);
  fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
  if (fd_ == -1) {
    if (msg) {
      *msg = "open";
    }
    return kSystemError;
  }
  // Always close fd and unmap in case of failure along the way to avoid
  // check failure above if we leave fd != -1 and the object is recycled
  // like it is inside SignalSafeElfCache
  auto guard = makeGuard([&] { reset(); });
  struct stat st;
  int r = fstat(fd_, &st);
  if (r == -1) {
    if (msg) {
      *msg = "fstat";
    }
    return kSystemError;
  }

  length_ = st.st_size;
  int prot = PROT_READ;
  if (!readOnly) {
    prot |= PROT_WRITE;
  }
  file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
  if (file_ == MAP_FAILED) {
    if (msg) {
      *msg = "mmap";
    }
    return kSystemError;
  }
  if (!init(msg)) {
    errno = EINVAL;
    return kInvalidElfFile;
  }
  guard.dismiss();
  return kSuccess;
}

int ElfFile::openAndFollow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  auto result = openNoThrow(name, readOnly, msg);
  if (!readOnly || result != kSuccess) {
    return result;
  }

  /* NOTE .gnu_debuglink specifies only the name of the debugging info file
   * (with no directory components). GDB checks 3 different directories, but
   * ElfFile only supports the first version:
   *     - dirname(name)
   *     - dirname(name) + /.debug/
   *     - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
   */
  auto dirend = strrchr(name, '/');
  // include ending '/' if any.
  auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;

  auto debuginfo = getSectionByName(".gnu_debuglink");
  if (!debuginfo) {
    return result;
  }

  // The section starts with the filename, with any leading directory
  // components removed, followed by a zero byte.
  auto debugFileName = getSectionBody(*debuginfo);
  auto debugFileLen = strlen(debugFileName.begin());
  if (dirlen + debugFileLen >= PATH_MAX) {
    return result;
  }

  char linkname[PATH_MAX];
  memcpy(linkname, name, dirlen);
  memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
  reset();
  result = openNoThrow(linkname, readOnly, msg);
  if (result == kSuccess) {
    return result;
  }
  return openNoThrow(name, readOnly, msg);
}

ElfFile::~ElfFile() {
  reset();
}

ElfFile::ElfFile(ElfFile&& other) noexcept
    : fd_(other.fd_),
      file_(other.file_),
      length_(other.length_),
      baseAddress_(other.baseAddress_) {
  // copy other.filepath_, leaving filepath_ zero-terminated, always.
  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  other.filepath_[0] = 0;
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;
}

ElfFile& ElfFile::operator=(ElfFile&& other) {
  assert(this != &other);
  reset();

  // copy other.filepath_, leaving filepath_ zero-terminated, always.
  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  fd_ = other.fd_;
  file_ = other.file_;
  length_ = other.length_;
  baseAddress_ = other.baseAddress_;

  other.filepath_[0] = 0;
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;

  return *this;
}

void ElfFile::reset() {
  filepath_[0] = 0;

  if (file_ != MAP_FAILED) {
    munmap(file_, length_);
    file_ = static_cast<char*>(MAP_FAILED);
  }

  if (fd_ != -1) {
    close(fd_);
    fd_ = -1;
  }
}

bool ElfFile::init(const char** msg) {
  if (length_ < 4) {
    if (msg) {
      *msg = "not an ELF file (too short)";
    }
    return false;
  }

  std::array<char, 5> elfMagBuf = {{0, 0, 0, 0, 0}};
  if (::lseek(fd_, 0, SEEK_SET) != 0 || ::read(fd_, elfMagBuf.data(), 4) != 4) {
    if (msg) {
      *msg = "unable to read ELF file for magic number";
    }
    return false;
  }
  if (std::strncmp(elfMagBuf.data(), ELFMAG, sizeof(ELFMAG)) != 0) {
    if (msg) {
      *msg = "invalid ELF magic";
    }
    return false;
  }
  if (::lseek(fd_, 0, SEEK_SET) != 0) {
    if (msg) {
      *msg = "unable to reset file descriptor after reading ELF magic number";
    }
    return false;
  }

  auto& elfHeader = this->elfHeader();

#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
  // Validate ELF class (32/64 bits)
  if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
    if (msg) {
      *msg = "invalid ELF class";
    }
    return false;
  }
#undef P1
#undef P2
#undef EXPECTED_CLASS

  // Validate ELF data encoding (LSB/MSB)
  static constexpr auto kExpectedEncoding =
      kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
  if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
    if (msg) {
      *msg = "invalid ELF encoding";
    }
    return false;
  }

  // Validate ELF version (1)
  if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
      elfHeader.e_version != EV_CURRENT) {
    if (msg) {
      *msg = "invalid ELF version";
    }
    return false;
  }

  // We only support executable and shared object files
  if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
    if (msg) {
      *msg = "invalid ELF file type";
    }
    return false;
  }

  if (elfHeader.e_phnum == 0) {
    if (msg) {
      *msg = "no program header!";
    }
    return false;
  }

  if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
    if (msg) {
      *msg = "invalid program header entry size";
    }
    return false;
  }

  if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
    if (msg) {
      *msg = "invalid section header entry size";
    }
  }

  // Program headers are sorted by load address, so the first PT_LOAD
  // header gives us the base address.
  const ElfPhdr* programHeader =
      iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });

  if (!programHeader) {
    if (msg) {
      *msg = "could not find base address";
    }
    return false;
  }
  baseAddress_ = programHeader->p_vaddr;

  return true;
}

const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
  FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
  return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
}

folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
  return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
}

void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
  FOLLY_SAFE_CHECK(
      stringTable.sh_type == SHT_STRTAB, "invalid type for string table");

  const char* start = file_ + stringTable.sh_offset;
  // First and last bytes must be 0
  FOLLY_SAFE_CHECK(
      stringTable.sh_size == 0 ||
          (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
      "invalid string table");
}

const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
    const {
  validateStringTable(stringTable);
  FOLLY_SAFE_CHECK(
      offset < stringTable.sh_size, "invalid offset in string table");

  return file_ + stringTable.sh_offset + offset;
}

const char* ElfFile::getSectionName(const ElfShdr& section) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  return getString(sectionNames, section.sh_name);
}

const ElfShdr* ElfFile::getSectionByName(const char* name) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  // Find offset in the section name string table of the requested name
  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  const char* foundName = iterateStrings(
      sectionNames, [&](const char* s) { return !strcmp(name, s); });
  if (foundName == nullptr) {
    return nullptr;
  }

  size_t offset = foundName - (file_ + sectionNames.sh_offset);

  // Find section with the appropriate sh_name offset
  const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
    if (sh.sh_name == offset) {
      return true;
    }
    return false;
  });
  return foundSection;
}

ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) {
    auto findSymbols = [&](const ElfSym& sym) {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
   iterateSectionsWithType(SHT_SYMTAB, findSection));

  return foundSymbol;
}

ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) -> bool {
    // This section has no string table associated w/ its symbols; hence we
    // can't get names for them
    if (section.sh_link == SHN_UNDEF) {
      return false;
    }

    auto findSymbols = [&](const ElfSym& sym) -> bool {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (sym.st_name == 0) {
        return false; // no name for this symbol
      }
      const char* sym_name =
          getString(*getSectionByIndex(section.sh_link), sym.st_name);
      if (strcmp(sym_name, name) == 0) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  iterateSectionsWithType(SHT_DYNSYM, findSection) ||
      iterateSectionsWithType(SHT_SYMTAB, findSection);

  return foundSymbol;
}

const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
  return iterateSections([&](const ElfShdr& sh) -> bool {
    return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
  });
}

const char* ElfFile::getSymbolName(Symbol symbol) const {
  if (!symbol.first || !symbol.second) {
    return nullptr;
  }

  if (symbol.second->st_name == 0) {
    return nullptr; // symbol has no name
  }

  if (symbol.first->sh_link == SHN_UNDEF) {
    return nullptr; // symbol table has no strings
  }

  return getString(
      *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
}

} // namespace symbolizer
} // namespace folly
<commit_msg>Fix a bug in ElfFile::getSectionByName<commit_after>/*
 * Copyright 2012-present Facebook, Inc.
 *
 * 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 <folly/experimental/symbolizer/Elf.h>

#include <fcntl.h>
#include <folly/portability/SysMman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <cstring>
#include <string>

#include <glog/logging.h>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>

#ifndef STT_GNU_IFUNC
#define STT_GNU_IFUNC 10
#endif

namespace folly {
namespace symbolizer {

ElfFile::ElfFile() noexcept
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {}

ElfFile::ElfFile(const char* name, bool readOnly)
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {
  open(name, readOnly);
}

void ElfFile::open(const char* name, bool readOnly) {
  const char* msg = "";
  int r = openNoThrow(name, readOnly, &msg);
  if (r == kSystemError) {
    throwSystemError(msg);
  } else {
    CHECK_EQ(r, kSuccess) << msg;
  }
}

int ElfFile::openNoThrow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
  strncat(filepath_, name, kFilepathMaxLen - 1);
  fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
  if (fd_ == -1) {
    if (msg) {
      *msg = "open";
    }
    return kSystemError;
  }
  // Always close fd and unmap in case of failure along the way to avoid
  // check failure above if we leave fd != -1 and the object is recycled
  // like it is inside SignalSafeElfCache
  auto guard = makeGuard([&] { reset(); });
  struct stat st;
  int r = fstat(fd_, &st);
  if (r == -1) {
    if (msg) {
      *msg = "fstat";
    }
    return kSystemError;
  }

  length_ = st.st_size;
  int prot = PROT_READ;
  if (!readOnly) {
    prot |= PROT_WRITE;
  }
  file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
  if (file_ == MAP_FAILED) {
    if (msg) {
      *msg = "mmap";
    }
    return kSystemError;
  }
  if (!init(msg)) {
    errno = EINVAL;
    return kInvalidElfFile;
  }
  guard.dismiss();
  return kSuccess;
}

int ElfFile::openAndFollow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  auto result = openNoThrow(name, readOnly, msg);
  if (!readOnly || result != kSuccess) {
    return result;
  }

  /* NOTE .gnu_debuglink specifies only the name of the debugging info file
   * (with no directory components). GDB checks 3 different directories, but
   * ElfFile only supports the first version:
   *     - dirname(name)
   *     - dirname(name) + /.debug/
   *     - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
   */
  auto dirend = strrchr(name, '/');
  // include ending '/' if any.
  auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;

  auto debuginfo = getSectionByName(".gnu_debuglink");
  if (!debuginfo) {
    return result;
  }

  // The section starts with the filename, with any leading directory
  // components removed, followed by a zero byte.
  auto debugFileName = getSectionBody(*debuginfo);
  auto debugFileLen = strlen(debugFileName.begin());
  if (dirlen + debugFileLen >= PATH_MAX) {
    return result;
  }

  char linkname[PATH_MAX];
  memcpy(linkname, name, dirlen);
  memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
  reset();
  result = openNoThrow(linkname, readOnly, msg);
  if (result == kSuccess) {
    return result;
  }
  return openNoThrow(name, readOnly, msg);
}

ElfFile::~ElfFile() {
  reset();
}

ElfFile::ElfFile(ElfFile&& other) noexcept
    : fd_(other.fd_),
      file_(other.file_),
      length_(other.length_),
      baseAddress_(other.baseAddress_) {
  // copy other.filepath_, leaving filepath_ zero-terminated, always.
  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  other.filepath_[0] = 0;
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;
}

ElfFile& ElfFile::operator=(ElfFile&& other) {
  assert(this != &other);
  reset();

  // copy other.filepath_, leaving filepath_ zero-terminated, always.
  strncat(filepath_, other.filepath_, kFilepathMaxLen - 1);
  fd_ = other.fd_;
  file_ = other.file_;
  length_ = other.length_;
  baseAddress_ = other.baseAddress_;

  other.filepath_[0] = 0;
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;

  return *this;
}

void ElfFile::reset() {
  filepath_[0] = 0;

  if (file_ != MAP_FAILED) {
    munmap(file_, length_);
    file_ = static_cast<char*>(MAP_FAILED);
  }

  if (fd_ != -1) {
    close(fd_);
    fd_ = -1;
  }
}

bool ElfFile::init(const char** msg) {
  if (length_ < 4) {
    if (msg) {
      *msg = "not an ELF file (too short)";
    }
    return false;
  }

  std::array<char, 5> elfMagBuf = {{0, 0, 0, 0, 0}};
  if (::lseek(fd_, 0, SEEK_SET) != 0 || ::read(fd_, elfMagBuf.data(), 4) != 4) {
    if (msg) {
      *msg = "unable to read ELF file for magic number";
    }
    return false;
  }
  if (std::strncmp(elfMagBuf.data(), ELFMAG, sizeof(ELFMAG)) != 0) {
    if (msg) {
      *msg = "invalid ELF magic";
    }
    return false;
  }
  if (::lseek(fd_, 0, SEEK_SET) != 0) {
    if (msg) {
      *msg = "unable to reset file descriptor after reading ELF magic number";
    }
    return false;
  }

  auto& elfHeader = this->elfHeader();

#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
  // Validate ELF class (32/64 bits)
  if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
    if (msg) {
      *msg = "invalid ELF class";
    }
    return false;
  }
#undef P1
#undef P2
#undef EXPECTED_CLASS

  // Validate ELF data encoding (LSB/MSB)
  static constexpr auto kExpectedEncoding =
      kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
  if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
    if (msg) {
      *msg = "invalid ELF encoding";
    }
    return false;
  }

  // Validate ELF version (1)
  if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
      elfHeader.e_version != EV_CURRENT) {
    if (msg) {
      *msg = "invalid ELF version";
    }
    return false;
  }

  // We only support executable and shared object files
  if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
    if (msg) {
      *msg = "invalid ELF file type";
    }
    return false;
  }

  if (elfHeader.e_phnum == 0) {
    if (msg) {
      *msg = "no program header!";
    }
    return false;
  }

  if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
    if (msg) {
      *msg = "invalid program header entry size";
    }
    return false;
  }

  if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
    if (msg) {
      *msg = "invalid section header entry size";
    }
  }

  // Program headers are sorted by load address, so the first PT_LOAD
  // header gives us the base address.
  const ElfPhdr* programHeader =
      iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });

  if (!programHeader) {
    if (msg) {
      *msg = "could not find base address";
    }
    return false;
  }
  baseAddress_ = programHeader->p_vaddr;

  return true;
}

const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
  FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
  return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
}

folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
  return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
}

void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
  FOLLY_SAFE_CHECK(
      stringTable.sh_type == SHT_STRTAB, "invalid type for string table");

  const char* start = file_ + stringTable.sh_offset;
  // First and last bytes must be 0
  FOLLY_SAFE_CHECK(
      stringTable.sh_size == 0 ||
          (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
      "invalid string table");
}

const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
    const {
  validateStringTable(stringTable);
  FOLLY_SAFE_CHECK(
      offset < stringTable.sh_size, "invalid offset in string table");

  return file_ + stringTable.sh_offset + offset;
}

const char* ElfFile::getSectionName(const ElfShdr& section) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  return getString(sectionNames, section.sh_name);
}

const ElfShdr* ElfFile::getSectionByName(const char* name) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  const char* start = file_ + sectionNames.sh_offset;

  // Find section with the appropriate sh_name offset
  const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
    if (sh.sh_name >= sectionNames.sh_size) {
      return false;
    }
    return !strcmp(start + sh.sh_name, name);
  });
  return foundSection;
}

ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) {
    auto findSymbols = [&](const ElfSym& sym) {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
   iterateSectionsWithType(SHT_SYMTAB, findSection));

  return foundSymbol;
}

ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) -> bool {
    // This section has no string table associated w/ its symbols; hence we
    // can't get names for them
    if (section.sh_link == SHN_UNDEF) {
      return false;
    }

    auto findSymbols = [&](const ElfSym& sym) -> bool {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (sym.st_name == 0) {
        return false; // no name for this symbol
      }
      const char* sym_name =
          getString(*getSectionByIndex(section.sh_link), sym.st_name);
      if (strcmp(sym_name, name) == 0) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  iterateSectionsWithType(SHT_DYNSYM, findSection) ||
      iterateSectionsWithType(SHT_SYMTAB, findSection);

  return foundSymbol;
}

const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
  return iterateSections([&](const ElfShdr& sh) -> bool {
    return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
  });
}

const char* ElfFile::getSymbolName(Symbol symbol) const {
  if (!symbol.first || !symbol.second) {
    return nullptr;
  }

  if (symbol.second->st_name == 0) {
    return nullptr; // symbol has no name
  }

  if (symbol.first->sh_link == SHN_UNDEF) {
    return nullptr; // symbol table has no strings
  }

  return getString(
      *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
}

} // namespace symbolizer
} // namespace folly
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
#include <vector>
#include "global.h"
#include "WorldPlayer.h"

WorldPlayer::WorldPlayer() :
   Player(ServerPlayer, RogueTeam, "world weapon", "", ComputerPlayer)
{
}

WorldPlayer::~WorldPlayer()
{
  for (std::vector<RemoteShotPath*>::iterator it = shots.begin(); it != shots.end(); ++it) {
    RemoteShotPath *shot = *it;
    delete shot;
  }

  shots.clear();
}

void			WorldPlayer::addShot(const FiringInfo& info)
{
  RemoteShotPath* newShot = new RemoteShotPath(info);
  int shotNum = int(newShot->getShotId() & 255);
  if (shotNum >= (int)shots.size()) {
    shots.resize(shotNum+1);
  }
  else {
    if (shots[shotNum] != NULL)
      delete shots[shotNum];
  }
  shots[shotNum] = newShot;
}

ShotPath*		WorldPlayer::getShot(int index) const
{
  return shots[index & 255];
}

bool			WorldPlayer::doEndShot(
				int id, bool isHit, float* pos)
{
  const int index = id & 255;
  const int salt = (id >> 8) & 127;

  // special id used in some messages (and really shouldn't be sent here)
  if (id == -1)
    return false;

  // ignore bogus shots (those with a bad index or for shots that don't exist)
  if (index < 0 || index >= (int)shots.size() || !shots[index])
    return false;

  // ignore shots that already ending
  if (shots[index]->isExpired() || shots[index]->isExpiring())
    return false;

  // ignore shots that have the wrong salt.  since we reuse shot indices
  // it's possible for an old MsgShotEnd to arrive after we've started a
  // new shot.  that's where the salt comes in.  it changes for each shot
  // so we can identify an old shot from a new one.
  if (salt != ((shots[index]->getShotId() >> 8) & 127))
    return false;

  // don't stop if it's because were hitting something and we don't stop
  // when we hit something.
  if (isHit && !shots[index]->isStoppedByHit())
    return false;

  // end it
  const float* shotPos = shots[index]->getPosition();
  pos[0] = shotPos[0];
  pos[1] = shotPos[1];
  pos[2] = shotPos[2];
  shots[index]->setExpired();
  return true;
}

void			WorldPlayer::updateShots(float dt)
{
  for (int i = 0; i < (int)shots.size(); i++)
    if (shots[i])
      shots[i]->update(dt);
}

void			WorldPlayer::addShots(SceneDatabase* scene,
					bool colorblind) const
{
  const int count = shots.size();
  for (int i = 0; i < count; i++) {
    ShotPath* shot = getShot(i);
    if (shot && !shot->isExpiring() && !shot->isExpired())
      shot->addShot(scene, colorblind);
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>try to prevent a lil crashage<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
#include <vector>
#include "global.h"
#include "WorldPlayer.h"

WorldPlayer::WorldPlayer() :
   Player(ServerPlayer, RogueTeam, "world weapon", "", ComputerPlayer)
{
}

WorldPlayer::~WorldPlayer()
{
  for (std::vector<RemoteShotPath*>::iterator it = shots.begin(); it != shots.end(); ++it) {
    RemoteShotPath *shot = *it;
    delete shot;
  }

  shots.clear();
}

void			WorldPlayer::addShot(const FiringInfo& info)
{
  RemoteShotPath* newShot = new RemoteShotPath(info);
  int shotNum = int(newShot->getShotId() & 255);
  if (shotNum >= (int)shots.size()) {
    shots.resize(shotNum+1);
  }
  else {
    if (shots[shotNum] != NULL)
      delete shots[shotNum];
  }
  shots[shotNum] = newShot;
}

ShotPath*		WorldPlayer::getShot(int index) const
{
  if (index & 255 >= (int)shots.size()) return NULL;
  return shots[index & 255];
}

bool			WorldPlayer::doEndShot(
				int id, bool isHit, float* pos)
{
  const int index = id & 255;
  const int salt = (id >> 8) & 127;

  // special id used in some messages (and really shouldn't be sent here)
  if (id == -1)
    return false;

  // ignore bogus shots (those with a bad index or for shots that don't exist)
  if (index < 0 || index >= (int)shots.size() || !shots[index])
    return false;

  // ignore shots that already ending
  if (shots[index]->isExpired() || shots[index]->isExpiring())
    return false;

  // ignore shots that have the wrong salt.  since we reuse shot indices
  // it's possible for an old MsgShotEnd to arrive after we've started a
  // new shot.  that's where the salt comes in.  it changes for each shot
  // so we can identify an old shot from a new one.
  if (salt != ((shots[index]->getShotId() >> 8) & 127))
    return false;

  // don't stop if it's because were hitting something and we don't stop
  // when we hit something.
  if (isHit && !shots[index]->isStoppedByHit())
    return false;

  // end it
  const float* shotPos = shots[index]->getPosition();
  pos[0] = shotPos[0];
  pos[1] = shotPos[1];
  pos[2] = shotPos[2];
  shots[index]->setExpired();
  return true;
}

void			WorldPlayer::updateShots(float dt)
{
  for (int i = 0; i < (int)shots.size(); i++)
    if (shots[i])
      shots[i]->update(dt);
}

void			WorldPlayer::addShots(SceneDatabase* scene,
					bool colorblind) const
{
  const int count = shots.size();
  for (int i = 0; i < count; i++) {
    ShotPath* shot = getShot(i);
    if (shot && !shot->isExpiring() && !shot->isExpired())
      shot->addShot(scene, colorblind);
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
// File:        thresholder.cpp
// Description: Base API for thresholding images in tesseract.
// Author:      Ray Smith
//
// (C) Copyright 2008, Google Inc.
// 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 "otsuthr.h"
#include "thresholder.h"
#include "tprintf.h" // for tprintf

#if defined(USE_OPENCL)
#  include "openclwrapper.h" // for OpenclDevice
#endif

#include <allheaders.h>

#include <cstdint> // for uint32_t
#include <cstring>
#include <tuple>

namespace tesseract {

ImageThresholder::ImageThresholder()
    : pix_(nullptr)
    , image_width_(0)
    , image_height_(0)
    , pix_channels_(0)
    , pix_wpl_(0)
    , scale_(1)
    , yres_(300)
    , estimated_res_(300) {
  SetRectangle(0, 0, 0, 0);
}

ImageThresholder::~ImageThresholder() {
  Clear();
}

// Destroy the Pix if there is one, freeing memory.
void ImageThresholder::Clear() {
  pix_.destroy();
}

// Return true if no image has been set.
bool ImageThresholder::IsEmpty() const {
  return pix_ == nullptr;
}

// SetImage makes a copy of all the image data, so it may be deleted
// immediately after this call.
// Greyscale of 8 and color of 24 or 32 bits per pixel may be given.
// Palette color images will not work properly and must be converted to
// 24 bit.
// Binary images of 1 bit per pixel may also be given but they must be
// byte packed with the MSB of the first byte being the first pixel, and a
// one pixel is WHITE. For binary images set bytes_per_pixel=0.
void ImageThresholder::SetImage(const unsigned char *imagedata, int width, int height,
                                int bytes_per_pixel, int bytes_per_line) {
  int bpp = bytes_per_pixel * 8;
  if (bpp == 0) {
    bpp = 1;
  }
  Image pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
  l_uint32 *data = pixGetData(pix);
  int wpl = pixGetWpl(pix);
  switch (bpp) {
    case 1:
      for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x) {
          if (imagedata[x / 8] & (0x80 >> (x % 8))) {
            CLEAR_DATA_BIT(data, x);
          } else {
            SET_DATA_BIT(data, x);
          }
        }
      }
      break;

    case 8:
      // Greyscale just copies the bytes in the right order.
      for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x) {
          SET_DATA_BYTE(data, x, imagedata[x]);
        }
      }
      break;

    case 24:
      // Put the colors in the correct places in the line buffer.
      for (int y = 0; y < height; ++y, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x, ++data) {
          SET_DATA_BYTE(data, COLOR_RED, imagedata[3 * x]);
          SET_DATA_BYTE(data, COLOR_GREEN, imagedata[3 * x + 1]);
          SET_DATA_BYTE(data, COLOR_BLUE, imagedata[3 * x + 2]);
        }
      }
      break;

    case 32:
      // Maintain byte order consistency across different endianness.
      for (int y = 0; y < height; ++y, imagedata += bytes_per_line, data += wpl) {
        for (int x = 0; x < width; ++x) {
          data[x] = (imagedata[x * 4] << 24) | (imagedata[x * 4 + 1] << 16) |
                    (imagedata[x * 4 + 2] << 8) | imagedata[x * 4 + 3];
        }
      }
      break;

    default:
      tprintf("Cannot convert RAW image to Pix with bpp = %d\n", bpp);
  }
  SetImage(pix);
  pix.destroy();
}

// Store the coordinates of the rectangle to process for later use.
// Doesn't actually do any thresholding.
void ImageThresholder::SetRectangle(int left, int top, int width, int height) {
  rect_left_ = left;
  rect_top_ = top;
  rect_width_ = width;
  rect_height_ = height;
}

// Get enough parameters to be able to rebuild bounding boxes in the
// original image (not just within the rectangle).
// Left and top are enough with top-down coordinates, but
// the height of the rectangle and the image are needed for bottom-up.
void ImageThresholder::GetImageSizes(int *left, int *top, int *width, int *height, int *imagewidth,
                                     int *imageheight) {
  *left = rect_left_;
  *top = rect_top_;
  *width = rect_width_;
  *height = rect_height_;
  *imagewidth = image_width_;
  *imageheight = image_height_;
}

// Pix vs raw, which to use? Pix is the preferred input for efficiency,
// since raw buffers are copied.
// SetImage for Pix clones its input, so the source pix may be pixDestroyed
// immediately after, but may not go away until after the Thresholder has
// finished with it.
void ImageThresholder::SetImage(const Image pix) {
  if (pix_ != nullptr) {
    pix_.destroy();
  }
  Image src = pix;
  int depth;
  pixGetDimensions(src, &image_width_, &image_height_, &depth);
  // Convert the image as necessary so it is one of binary, plain RGB, or
  // 8 bit with no colormap. Guarantee that we always end up with our own copy,
  // not just a clone of the input.
  if (pixGetColormap(src)) {
    Image tmp = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC);
    depth = pixGetDepth(tmp);
    if (depth > 1 && depth < 8) {
      pix_ = pixConvertTo8(tmp, false);
      tmp.destroy();
    } else {
      pix_ = tmp;
    }
  } else if (depth > 1 && depth < 8) {
    pix_ = pixConvertTo8(src, false);
  } else {
    pix_ = src.copy();
  }
  depth = pixGetDepth(pix_);
  pix_channels_ = depth / 8;
  pix_wpl_ = pixGetWpl(pix_);
  scale_ = 1;
  estimated_res_ = yres_ = pixGetYRes(pix_);
  Init();
}

std::tuple<bool, Image, Image, Image> ImageThresholder::Threshold(
                                                         ThresholdMethod method) {
  Image pix_binary = nullptr;
  Image pix_thresholds = nullptr;

  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Image original = GetPixRect();
    pix_binary = original.copy();
    original.destroy();
    return std::make_tuple(false, nullptr, pix_binary, nullptr);
  }

  auto pix_grey = GetPixRectGrey();

  int r;
  if (method == ThresholdMethod::Sauvola) {
    r = pixSauvolaBinarizeTiled(pix_grey, 25, 0.40, 300, 300, (PIX**)pix_thresholds,
                                (PIX**)pix_binary);
  } else {
    // AdaptiveOtsu.
    r = pixOtsuAdaptiveThreshold(pix_grey, 300, 300, 0, 0, 0.1,
                                 (PIX**)pix_thresholds, (PIX**)pix_binary);
  }

  bool ok = (r == 0);
  return std::make_tuple(ok, pix_grey, pix_binary, pix_thresholds);
}

// Threshold the source image as efficiently as possible to the output Pix.
// Creates a Pix and sets pix to point to the resulting pointer.
// Caller must use pixDestroy to free the created Pix.
/// Returns false on error.
bool ImageThresholder::ThresholdToPix(Image *pix) {
  if (image_width_ > INT16_MAX || image_height_ > INT16_MAX) {
    tprintf("Image too large: (%d, %d)\n", image_width_, image_height_);
    return false;
  }
  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Image original = GetPixRect();
    *pix = original.copy();
    original.destroy();
  } else {
    OtsuThresholdRectToPix(pix_, pix);
  }
  return true;
}

// Gets a pix that contains an 8 bit threshold value at each pixel. The
// returned pix may be an integer reduction of the binary image such that
// the scale factor may be inferred from the ratio of the sizes, even down
// to the extreme of a 1x1 pixel thresholds image.
// Ideally the 8 bit threshold should be the exact threshold used to generate
// the binary image in ThresholdToPix, but this is not a hard constraint.
// Returns nullptr if the input is binary. PixDestroy after use.
Image ImageThresholder::GetPixRectThresholds() {
  if (IsBinary()) {
    return nullptr;
  }
  Image pix_grey = GetPixRectGrey();
  int width = pixGetWidth(pix_grey);
  int height = pixGetHeight(pix_grey);
  std::vector<int> thresholds;
  std::vector<int> hi_values;
  OtsuThreshold(pix_grey, 0, 0, width, height, thresholds, hi_values);
  pix_grey.destroy();
  Image pix_thresholds = pixCreate(width, height, 8);
  int threshold = thresholds[0] > 0 ? thresholds[0] : 128;
  pixSetAllArbitrary(pix_thresholds, threshold);
  return pix_thresholds;
}

// Common initialization shared between SetImage methods.
void ImageThresholder::Init() {
  SetRectangle(0, 0, image_width_, image_height_);
}

// Get a clone/copy of the source image rectangle.
// The returned Pix must be pixDestroyed.
// This function will be used in the future by the page layout analysis, and
// the layout analysis that uses it will only be available with Leptonica,
// so there is no raw equivalent.
Image ImageThresholder::GetPixRect() {
  if (IsFullImage()) {
    // Just clone the whole thing.
    return pix_.clone();
  } else {
    // Crop to the given rectangle.
    Box *box = boxCreate(rect_left_, rect_top_, rect_width_, rect_height_);
    Image cropped = pixClipRectangle(pix_, box, nullptr);
    boxDestroy(&box);
    return cropped;
  }
}

// Get a clone/copy of the source image rectangle, reduced to greyscale,
// and at the same resolution as the output binary.
// The returned Pix must be pixDestroyed.
// Provided to the classifier to extract features from the greyscale image.
Image ImageThresholder::GetPixRectGrey() {
  auto pix = GetPixRect(); // May have to be reduced to grey.
  int depth = pixGetDepth(pix);
  if (depth != 8) {
    if (depth == 24) {
      auto tmp = pixConvert24To32(pix);
      pix.destroy();
      pix = tmp;
    }
    auto result = pixConvertTo8(pix, false);
    pix.destroy();
    return result;
  }
  return pix;
}

// Otsu thresholds the rectangle, taking the rectangle from *this.
void ImageThresholder::OtsuThresholdRectToPix(Image src_pix, Image *out_pix) const {
  std::vector<int> thresholds;
  std::vector<int> hi_values;

  int num_channels = OtsuThreshold(src_pix, rect_left_, rect_top_, rect_width_, rect_height_,
                                   thresholds, hi_values);
  // only use opencl if compiled w/ OpenCL and selected device is opencl
#ifdef USE_OPENCL
  OpenclDevice od;
  if (num_channels == 4 && od.selectedDeviceIsOpenCL() && rect_top_ == 0 && rect_left_ == 0) {
    od.ThresholdRectToPixOCL((unsigned char *)pixGetData(src_pix), num_channels,
                             pixGetWpl(src_pix) * 4, &thresholds[0], &hi_values[0], out_pix /*pix_OCL*/,
                             rect_height_, rect_width_, rect_top_, rect_left_);
  } else {
#endif
    ThresholdRectToPix(src_pix, num_channels, thresholds, hi_values, out_pix);
#ifdef USE_OPENCL
  }
#endif
}

/// Threshold the rectangle, taking everything except the src_pix
/// from the class, using thresholds/hi_values to the output pix.
/// NOTE that num_channels is the size of the thresholds and hi_values
// arrays and also the bytes per pixel in src_pix.
void ImageThresholder::ThresholdRectToPix(Image src_pix, int num_channels, const std::vector<int> &thresholds,
                                          const std::vector<int> &hi_values, Image *pix) const {
  *pix = pixCreate(rect_width_, rect_height_, 1);
  uint32_t *pixdata = pixGetData(*pix);
  int wpl = pixGetWpl(*pix);
  int src_wpl = pixGetWpl(src_pix);
  uint32_t *srcdata = pixGetData(src_pix);
  pixSetXRes(*pix, pixGetXRes(src_pix));
  pixSetYRes(*pix, pixGetYRes(src_pix));
  for (int y = 0; y < rect_height_; ++y) {
    const uint32_t *linedata = srcdata + (y + rect_top_) * src_wpl;
    uint32_t *pixline = pixdata + y * wpl;
    for (int x = 0; x < rect_width_; ++x) {
      bool white_result = true;
      for (int ch = 0; ch < num_channels; ++ch) {
        int pixel = GET_DATA_BYTE(linedata, (x + rect_left_) * num_channels + ch);
        if (hi_values[ch] >= 0 && (pixel > thresholds[ch]) == (hi_values[ch] == 0)) {
          white_result = false;
          break;
        }
      }
      if (white_result) {
        CLEAR_DATA_BIT(pixline, x);
      } else {
        SET_DATA_BIT(pixline, x);
      }
    }
  }
}

} // namespace tesseract.
<commit_msg>Fix wrong tiles parameters in Sauvola (#3570)<commit_after>///////////////////////////////////////////////////////////////////////
// File:        thresholder.cpp
// Description: Base API for thresholding images in tesseract.
// Author:      Ray Smith
//
// (C) Copyright 2008, Google Inc.
// 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 "otsuthr.h"
#include "thresholder.h"
#include "tprintf.h" // for tprintf

#if defined(USE_OPENCL)
#  include "openclwrapper.h" // for OpenclDevice
#endif

#include <allheaders.h>

#include <cstdint> // for uint32_t
#include <cstring>
#include <tuple>

namespace tesseract {

ImageThresholder::ImageThresholder()
    : pix_(nullptr)
    , image_width_(0)
    , image_height_(0)
    , pix_channels_(0)
    , pix_wpl_(0)
    , scale_(1)
    , yres_(300)
    , estimated_res_(300) {
  SetRectangle(0, 0, 0, 0);
}

ImageThresholder::~ImageThresholder() {
  Clear();
}

// Destroy the Pix if there is one, freeing memory.
void ImageThresholder::Clear() {
  pix_.destroy();
}

// Return true if no image has been set.
bool ImageThresholder::IsEmpty() const {
  return pix_ == nullptr;
}

// SetImage makes a copy of all the image data, so it may be deleted
// immediately after this call.
// Greyscale of 8 and color of 24 or 32 bits per pixel may be given.
// Palette color images will not work properly and must be converted to
// 24 bit.
// Binary images of 1 bit per pixel may also be given but they must be
// byte packed with the MSB of the first byte being the first pixel, and a
// one pixel is WHITE. For binary images set bytes_per_pixel=0.
void ImageThresholder::SetImage(const unsigned char *imagedata, int width, int height,
                                int bytes_per_pixel, int bytes_per_line) {
  int bpp = bytes_per_pixel * 8;
  if (bpp == 0) {
    bpp = 1;
  }
  Image pix = pixCreate(width, height, bpp == 24 ? 32 : bpp);
  l_uint32 *data = pixGetData(pix);
  int wpl = pixGetWpl(pix);
  switch (bpp) {
    case 1:
      for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x) {
          if (imagedata[x / 8] & (0x80 >> (x % 8))) {
            CLEAR_DATA_BIT(data, x);
          } else {
            SET_DATA_BIT(data, x);
          }
        }
      }
      break;

    case 8:
      // Greyscale just copies the bytes in the right order.
      for (int y = 0; y < height; ++y, data += wpl, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x) {
          SET_DATA_BYTE(data, x, imagedata[x]);
        }
      }
      break;

    case 24:
      // Put the colors in the correct places in the line buffer.
      for (int y = 0; y < height; ++y, imagedata += bytes_per_line) {
        for (int x = 0; x < width; ++x, ++data) {
          SET_DATA_BYTE(data, COLOR_RED, imagedata[3 * x]);
          SET_DATA_BYTE(data, COLOR_GREEN, imagedata[3 * x + 1]);
          SET_DATA_BYTE(data, COLOR_BLUE, imagedata[3 * x + 2]);
        }
      }
      break;

    case 32:
      // Maintain byte order consistency across different endianness.
      for (int y = 0; y < height; ++y, imagedata += bytes_per_line, data += wpl) {
        for (int x = 0; x < width; ++x) {
          data[x] = (imagedata[x * 4] << 24) | (imagedata[x * 4 + 1] << 16) |
                    (imagedata[x * 4 + 2] << 8) | imagedata[x * 4 + 3];
        }
      }
      break;

    default:
      tprintf("Cannot convert RAW image to Pix with bpp = %d\n", bpp);
  }
  SetImage(pix);
  pix.destroy();
}

// Store the coordinates of the rectangle to process for later use.
// Doesn't actually do any thresholding.
void ImageThresholder::SetRectangle(int left, int top, int width, int height) {
  rect_left_ = left;
  rect_top_ = top;
  rect_width_ = width;
  rect_height_ = height;
}

// Get enough parameters to be able to rebuild bounding boxes in the
// original image (not just within the rectangle).
// Left and top are enough with top-down coordinates, but
// the height of the rectangle and the image are needed for bottom-up.
void ImageThresholder::GetImageSizes(int *left, int *top, int *width, int *height, int *imagewidth,
                                     int *imageheight) {
  *left = rect_left_;
  *top = rect_top_;
  *width = rect_width_;
  *height = rect_height_;
  *imagewidth = image_width_;
  *imageheight = image_height_;
}

// Pix vs raw, which to use? Pix is the preferred input for efficiency,
// since raw buffers are copied.
// SetImage for Pix clones its input, so the source pix may be pixDestroyed
// immediately after, but may not go away until after the Thresholder has
// finished with it.
void ImageThresholder::SetImage(const Image pix) {
  if (pix_ != nullptr) {
    pix_.destroy();
  }
  Image src = pix;
  int depth;
  pixGetDimensions(src, &image_width_, &image_height_, &depth);
  // Convert the image as necessary so it is one of binary, plain RGB, or
  // 8 bit with no colormap. Guarantee that we always end up with our own copy,
  // not just a clone of the input.
  if (pixGetColormap(src)) {
    Image tmp = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC);
    depth = pixGetDepth(tmp);
    if (depth > 1 && depth < 8) {
      pix_ = pixConvertTo8(tmp, false);
      tmp.destroy();
    } else {
      pix_ = tmp;
    }
  } else if (depth > 1 && depth < 8) {
    pix_ = pixConvertTo8(src, false);
  } else {
    pix_ = src.copy();
  }
  depth = pixGetDepth(pix_);
  pix_channels_ = depth / 8;
  pix_wpl_ = pixGetWpl(pix_);
  scale_ = 1;
  estimated_res_ = yres_ = pixGetYRes(pix_);
  Init();
}

std::tuple<bool, Image, Image, Image> ImageThresholder::Threshold(
                                                         ThresholdMethod method) {
  Image pix_binary = nullptr;
  Image pix_thresholds = nullptr;

  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Image original = GetPixRect();
    pix_binary = original.copy();
    original.destroy();
    return std::make_tuple(false, nullptr, pix_binary, nullptr);
  }

  auto pix_grey = GetPixRectGrey();

  int r;
  if (method == ThresholdMethod::Sauvola) {
    // TODO: Convert this constant to config var
    // window half-width for measuring local statistics
    constexpr l_int32 whsize = 25;
    // factor for image division into tiles; >= 1
    l_int32 nx, ny;
//  // tiles size will be approx. 250 x 250 pixels
    l_int32 pix_w, pix_h;
    pixGetDimensions(pix_grey, &pix_w, &pix_h, nullptr);
    nx = std::max(1, (pix_w + 125) / 250);
    ny = std::max(1, (pix_h + 125) / 250);
    auto xrat = pix_w / nx;
    auto yrat = pix_h / ny;
    if (xrat < whsize + 2) {
      nx = pix_w / (whsize + 2);
    }
    if (yrat < whsize + 2) {
      ny = pix_h / (whsize + 2);
    }

    r = pixSauvolaBinarizeTiled(pix_grey, whsize, 0.40, nx, ny,
                               (PIX**)pix_thresholds,
                                (PIX**)pix_binary);
  } else { // if (method == ThresholdMethod::AdaptiveOtsu)
    r = pixOtsuAdaptiveThreshold(pix_grey, 300, 300, 0, 0, 0.1,
                                 (PIX**)pix_thresholds, (PIX**)pix_binary);
  }

  bool ok = (r == 0);
  return std::make_tuple(ok, pix_grey, pix_binary, pix_thresholds);
}

// Threshold the source image as efficiently as possible to the output Pix.
// Creates a Pix and sets pix to point to the resulting pointer.
// Caller must use pixDestroy to free the created Pix.
/// Returns false on error.
bool ImageThresholder::ThresholdToPix(Image *pix) {
  if (image_width_ > INT16_MAX || image_height_ > INT16_MAX) {
    tprintf("Image too large: (%d, %d)\n", image_width_, image_height_);
    return false;
  }
  if (pix_channels_ == 0) {
    // We have a binary image, but it still has to be copied, as this API
    // allows the caller to modify the output.
    Image original = GetPixRect();
    *pix = original.copy();
    original.destroy();
  } else {
    OtsuThresholdRectToPix(pix_, pix);
  }
  return true;
}

// Gets a pix that contains an 8 bit threshold value at each pixel. The
// returned pix may be an integer reduction of the binary image such that
// the scale factor may be inferred from the ratio of the sizes, even down
// to the extreme of a 1x1 pixel thresholds image.
// Ideally the 8 bit threshold should be the exact threshold used to generate
// the binary image in ThresholdToPix, but this is not a hard constraint.
// Returns nullptr if the input is binary. PixDestroy after use.
Image ImageThresholder::GetPixRectThresholds() {
  if (IsBinary()) {
    return nullptr;
  }
  Image pix_grey = GetPixRectGrey();
  int width = pixGetWidth(pix_grey);
  int height = pixGetHeight(pix_grey);
  std::vector<int> thresholds;
  std::vector<int> hi_values;
  OtsuThreshold(pix_grey, 0, 0, width, height, thresholds, hi_values);
  pix_grey.destroy();
  Image pix_thresholds = pixCreate(width, height, 8);
  int threshold = thresholds[0] > 0 ? thresholds[0] : 128;
  pixSetAllArbitrary(pix_thresholds, threshold);
  return pix_thresholds;
}

// Common initialization shared between SetImage methods.
void ImageThresholder::Init() {
  SetRectangle(0, 0, image_width_, image_height_);
}

// Get a clone/copy of the source image rectangle.
// The returned Pix must be pixDestroyed.
// This function will be used in the future by the page layout analysis, and
// the layout analysis that uses it will only be available with Leptonica,
// so there is no raw equivalent.
Image ImageThresholder::GetPixRect() {
  if (IsFullImage()) {
    // Just clone the whole thing.
    return pix_.clone();
  } else {
    // Crop to the given rectangle.
    Box *box = boxCreate(rect_left_, rect_top_, rect_width_, rect_height_);
    Image cropped = pixClipRectangle(pix_, box, nullptr);
    boxDestroy(&box);
    return cropped;
  }
}

// Get a clone/copy of the source image rectangle, reduced to greyscale,
// and at the same resolution as the output binary.
// The returned Pix must be pixDestroyed.
// Provided to the classifier to extract features from the greyscale image.
Image ImageThresholder::GetPixRectGrey() {
  auto pix = GetPixRect(); // May have to be reduced to grey.
  int depth = pixGetDepth(pix);
  if (depth != 8) {
    if (depth == 24) {
      auto tmp = pixConvert24To32(pix);
      pix.destroy();
      pix = tmp;
    }
    auto result = pixConvertTo8(pix, false);
    pix.destroy();
    return result;
  }
  return pix;
}

// Otsu thresholds the rectangle, taking the rectangle from *this.
void ImageThresholder::OtsuThresholdRectToPix(Image src_pix, Image *out_pix) const {
  std::vector<int> thresholds;
  std::vector<int> hi_values;

  int num_channels = OtsuThreshold(src_pix, rect_left_, rect_top_, rect_width_, rect_height_,
                                   thresholds, hi_values);
  // only use opencl if compiled w/ OpenCL and selected device is opencl
#ifdef USE_OPENCL
  OpenclDevice od;
  if (num_channels == 4 && od.selectedDeviceIsOpenCL() && rect_top_ == 0 && rect_left_ == 0) {
    od.ThresholdRectToPixOCL((unsigned char *)pixGetData(src_pix), num_channels,
                             pixGetWpl(src_pix) * 4, &thresholds[0], &hi_values[0], out_pix /*pix_OCL*/,
                             rect_height_, rect_width_, rect_top_, rect_left_);
  } else {
#endif
    ThresholdRectToPix(src_pix, num_channels, thresholds, hi_values, out_pix);
#ifdef USE_OPENCL
  }
#endif
}

/// Threshold the rectangle, taking everything except the src_pix
/// from the class, using thresholds/hi_values to the output pix.
/// NOTE that num_channels is the size of the thresholds and hi_values
// arrays and also the bytes per pixel in src_pix.
void ImageThresholder::ThresholdRectToPix(Image src_pix, int num_channels, const std::vector<int> &thresholds,
                                          const std::vector<int> &hi_values, Image *pix) const {
  *pix = pixCreate(rect_width_, rect_height_, 1);
  uint32_t *pixdata = pixGetData(*pix);
  int wpl = pixGetWpl(*pix);
  int src_wpl = pixGetWpl(src_pix);
  uint32_t *srcdata = pixGetData(src_pix);
  pixSetXRes(*pix, pixGetXRes(src_pix));
  pixSetYRes(*pix, pixGetYRes(src_pix));
  for (int y = 0; y < rect_height_; ++y) {
    const uint32_t *linedata = srcdata + (y + rect_top_) * src_wpl;
    uint32_t *pixline = pixdata + y * wpl;
    for (int x = 0; x < rect_width_; ++x) {
      bool white_result = true;
      for (int ch = 0; ch < num_channels; ++ch) {
        int pixel = GET_DATA_BYTE(linedata, (x + rect_left_) * num_channels + ch);
        if (hi_values[ch] >= 0 && (pixel > thresholds[ch]) == (hi_values[ch] == 0)) {
          white_result = false;
          break;
        }
      }
      if (white_result) {
        CLEAR_DATA_BIT(pixline, x);
      } else {
        SET_DATA_BIT(pixline, x);
      }
    }
  }
}

} // namespace tesseract.
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2016 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * libbitcoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <bitcoin/bitcoin/c/chain/output_point.h>
#include <bitcoin/bitcoin/c/internal/chain/output_point.hpp>

#include <bitcoin/bitcoin/c/internal/chain/output.hpp>
#include <bitcoin/bitcoin/c/internal/chain/point.hpp>
#include <bitcoin/bitcoin/c/internal/math/hash.hpp>
#include <bitcoin/bitcoin/c/internal/utility/vector.hpp>

BC_IMPLEMENT_VECTOR(output_info_list, bc_output_info_t,
    bc_destroy_output_info, libbitcoin::chain::output_info::list);

extern "C" {

uint64_t bc_output_point__not_coinbase()
{
    return libbitcoin::chain::output_point::not_coinbase;
}

bc_output_point_t* bc_create_output_point()
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point };
}
bc_output_point_t* bc_create_output_point_copy(const bc_output_point_t* other)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *other->obj) };
}
bc_output_point_t* bc_create_output_point_Point(const bc_point_t* value)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *value->obj) };
}
bc_output_point_t* bc_create_output_point_Tuple(
    const bc_hash_digest_t* hash, uint32_t index)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *hash->obj, index) };
}

void bc_destroy_output_point(bc_output_point_t* self)
{
    delete self->obj;
    delete self;
}

bool bc_output_point__equals(const bc_output_point_t* self,
    const bc_output_point_t* other)
{
    return *self->obj == *other->obj;
}
bool bc_output_point__not_equals(const bc_output_point_t* self,
    const bc_output_point_t* other)
{
    return *self->obj != *other->obj;
}

bc_point_t* bc_output_point__to_point(bc_output_point_t* self)
{
    return new bc_point_t{ new libbitcoin::chain::point(
        *static_cast<libbitcoin::chain::point*>(self->obj)) };
}

void bc_output_point__reset(bc_output_point_t* self)
{
    self->obj->reset();
}

bool bc_output_point__is_cached(const bc_output_point_t* self)
{
    return self->obj->is_cached();
}

bool bc_output_point__is_mature(const bc_output_point_t* self,
    size_t target_height)
{
    return self->obj->is_mature(target_height);
}

bool bc_output_point__spent(const bc_output_point_t* self)
{
    return self->obj->spent;
}
void bc_output_point__set_spent(bc_output_point_t* self, bool spent)
{
    self->obj->spent = spent;
}

bool bc_output_point__confirmed(const bc_output_point_t* self)
{
    return self->obj->confirmed;
}
void bc_output_point__set_confirmed(bc_output_point_t* self, bool confirmed)
{
    self->obj->confirmed = confirmed;
}

size_t bc_output_point__height(const bc_output_point_t* self)
{
    return self->obj->height;
}
void bc_output_point__set_height(bc_output_point_t* self, size_t height)
{
    self->obj->height = height;
}

bc_output_t* bc_output_point__cache(const bc_output_point_t* self)
{
    return new bc_output_t{ new libbitcoin::chain::output(
        self->obj->cache) };
}
void bc_output_point__set_cache(bc_output_point_t* self,
    const bc_output_t* cache)
{
    self->obj->cache = *cache->obj;
}

bc_points_info_t* bc_create_points_info()
{
    return new bc_points_info_t{ new libbitcoin::chain::points_info };
}
void bc_destroy_points_info(bc_points_info_t* self)
{
    delete self->obj;
    delete self;
}
bc_chain_point_list_t* bc_points_info__points(const bc_points_info_t* self)
{
    return bc_chain_point_list_to_ctype(self->obj->points);
}
void bc_points_info__set_points(bc_points_info_t* self,
    const bc_chain_point_list_t* points)
{
    self->obj->points = bc_chain_point_list_from_ctype(points);
}
uint64_t bc_points_info__change(const bc_points_info_t* self)
{
    return self->obj->change;
}
void bc_points_info__set_change(bc_points_info_t* self, uint64_t change)
{
    self->obj->change = change;
}

bc_output_info_t* bc_create_output_info()
{
    return new bc_output_info_t{ new libbitcoin::chain::output_info };
}
void bc_destroy_output_info(bc_output_info_t* self)
{
    delete self->obj;
    delete self;
}
bc_output_point_t* bc_output_info__point(const bc_output_info_t* self)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        self->obj->point) };
}
void bc_output_info__set_point(bc_output_info_t* self,
    const bc_output_point_t* point)
{
    self->obj->point = *point->obj;
}
uint64_t bc_output_info__value(const bc_output_info_t* self)
{
    return self->obj->value;
}
void bc_output_info__set_value(bc_output_info_t* self, uint64_t value)
{
    self->obj->value = value;
}

} // extern C

<commit_msg>cast shouldnt make a new object.<commit_after>/**
 * Copyright (c) 2011-2016 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * libbitcoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <bitcoin/bitcoin/c/chain/output_point.h>
#include <bitcoin/bitcoin/c/internal/chain/output_point.hpp>

#include <bitcoin/bitcoin/c/internal/chain/output.hpp>
#include <bitcoin/bitcoin/c/internal/chain/point.hpp>
#include <bitcoin/bitcoin/c/internal/math/hash.hpp>
#include <bitcoin/bitcoin/c/internal/utility/vector.hpp>

BC_IMPLEMENT_VECTOR(output_info_list, bc_output_info_t,
    bc_destroy_output_info, libbitcoin::chain::output_info::list);

extern "C" {

uint64_t bc_output_point__not_coinbase()
{
    return libbitcoin::chain::output_point::not_coinbase;
}

bc_output_point_t* bc_create_output_point()
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point };
}
bc_output_point_t* bc_create_output_point_copy(const bc_output_point_t* other)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *other->obj) };
}
bc_output_point_t* bc_create_output_point_Point(const bc_point_t* value)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *value->obj) };
}
bc_output_point_t* bc_create_output_point_Tuple(
    const bc_hash_digest_t* hash, uint32_t index)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        *hash->obj, index) };
}

void bc_destroy_output_point(bc_output_point_t* self)
{
    delete self->obj;
    delete self;
}

bool bc_output_point__equals(const bc_output_point_t* self,
    const bc_output_point_t* other)
{
    return *self->obj == *other->obj;
}
bool bc_output_point__not_equals(const bc_output_point_t* self,
    const bc_output_point_t* other)
{
    return *self->obj != *other->obj;
}

bc_point_t* bc_output_point__to_point(bc_output_point_t* self)
{
    return new bc_point_t{ static_cast<libbitcoin::chain::point*>(self->obj) };
}

void bc_output_point__reset(bc_output_point_t* self)
{
    self->obj->reset();
}

bool bc_output_point__is_cached(const bc_output_point_t* self)
{
    return self->obj->is_cached();
}

bool bc_output_point__is_mature(const bc_output_point_t* self,
    size_t target_height)
{
    return self->obj->is_mature(target_height);
}

bool bc_output_point__spent(const bc_output_point_t* self)
{
    return self->obj->spent;
}
void bc_output_point__set_spent(bc_output_point_t* self, bool spent)
{
    self->obj->spent = spent;
}

bool bc_output_point__confirmed(const bc_output_point_t* self)
{
    return self->obj->confirmed;
}
void bc_output_point__set_confirmed(bc_output_point_t* self, bool confirmed)
{
    self->obj->confirmed = confirmed;
}

size_t bc_output_point__height(const bc_output_point_t* self)
{
    return self->obj->height;
}
void bc_output_point__set_height(bc_output_point_t* self, size_t height)
{
    self->obj->height = height;
}

bc_output_t* bc_output_point__cache(const bc_output_point_t* self)
{
    return new bc_output_t{ new libbitcoin::chain::output(
        self->obj->cache) };
}
void bc_output_point__set_cache(bc_output_point_t* self,
    const bc_output_t* cache)
{
    self->obj->cache = *cache->obj;
}

bc_points_info_t* bc_create_points_info()
{
    return new bc_points_info_t{ new libbitcoin::chain::points_info };
}
void bc_destroy_points_info(bc_points_info_t* self)
{
    delete self->obj;
    delete self;
}
bc_chain_point_list_t* bc_points_info__points(const bc_points_info_t* self)
{
    return bc_chain_point_list_to_ctype(self->obj->points);
}
void bc_points_info__set_points(bc_points_info_t* self,
    const bc_chain_point_list_t* points)
{
    self->obj->points = bc_chain_point_list_from_ctype(points);
}
uint64_t bc_points_info__change(const bc_points_info_t* self)
{
    return self->obj->change;
}
void bc_points_info__set_change(bc_points_info_t* self, uint64_t change)
{
    self->obj->change = change;
}

bc_output_info_t* bc_create_output_info()
{
    return new bc_output_info_t{ new libbitcoin::chain::output_info };
}
void bc_destroy_output_info(bc_output_info_t* self)
{
    delete self->obj;
    delete self;
}
bc_output_point_t* bc_output_info__point(const bc_output_info_t* self)
{
    return new bc_output_point_t{ new libbitcoin::chain::output_point(
        self->obj->point) };
}
void bc_output_info__set_point(bc_output_info_t* self,
    const bc_output_point_t* point)
{
    self->obj->point = *point->obj;
}
uint64_t bc_output_info__value(const bc_output_info_t* self)
{
    return self->obj->value;
}
void bc_output_info__set_value(bc_output_info_t* self, uint64_t value)
{
    self->obj->value = value;
}

} // extern C

<|endoftext|>