<commit_before>/**
 * \file
 * \brief Header for RCC-related functions for STM32F4
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-09-17
 */

#ifndef SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_
#define SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_

#include <cstdint>

namespace distortos
{

namespace chip
{

/*---------------------------------------------------------------------------------------------------------------------+
| global types
+---------------------------------------------------------------------------------------------------------------------*/

/// system clock source
enum class SystemClockSource : uint8_t
{
	/// HSI oscillator selected as system clock
	hsi,
	/// HSE oscillator selected as system clock
	hse,
	/// main PLL selected as system clock
	pll,
};

/*---------------------------------------------------------------------------------------------------------------------+
| global constants
+---------------------------------------------------------------------------------------------------------------------*/

/// minimum allowed value for PLLM
constexpr uint8_t minPllm {2};

/// maximum allowed value for PLLM
constexpr uint8_t maxPllm {63};

/// minimum allowed value for PLLN
constexpr uint16_t minPlln {192};

/// maximum allowed value for PLLN
constexpr uint16_t maxPlln {432};

/// minimum allowed value for PLLQ
constexpr uint8_t minPllq {2};

/// maximum allowed value for PLLQ
constexpr uint8_t maxPllq {15};

/// first allowed value for PLLP - 2
constexpr uint8_t pllpDiv2 {2};

/// second allowed value for PLLP - 4
constexpr uint8_t pllpDiv4 {4};

/// third allowed value for PLLP - 6
constexpr uint8_t pllpDiv6 {6};

/// fourth allowed value for PLLP - 8
constexpr uint8_t pllpDiv8 {8};

/// HSI clock frequency, Hz
constexpr uint32_t hsiHz {16000000};

/// minimum allowed value for VCO input frequency, Hz
constexpr uint32_t minVcoInHz {1000000};

/// maximum allowed value for VCO input frequency, Hz
constexpr uint32_t maxVcoInHz {2000000};

/// minimum allowed value for VCO output frequency, Hz
constexpr uint32_t minVcoOutHz {192000000};

/// maximum allowed value for VCO output frequency, Hz
constexpr uint32_t maxVcoOutHz {432000000};

/// maximum allowed value for PLL output frequency, Hz
constexpr uint32_t maxPllOutHz {168000000};

/// maximum allowed value for PLL "Q" output frequency, Hz
constexpr uint32_t maxPllqOutHz {48000000};

/// first allowed value for AHB divider - 1
constexpr uint16_t hpreDiv1 {1};

/// second allowed value for AHB divider - 2
constexpr uint16_t hpreDiv2 {2};

/// third allowed value for AHB divider - 4
constexpr uint16_t hpreDiv4 {4};

/// fourth allowed value for AHB divider - 8
constexpr uint16_t hpreDiv8 {8};

/// fifth allowed value for AHB divider - 16
constexpr uint16_t hpreDiv16 {16};

/// sixth allowed value for AHB divider - 64
constexpr uint16_t hpreDiv64 {64};

/// seventh allowed value for AHB divider - 128
constexpr uint16_t hpreDiv128 {128};

/// eighth allowed value for AHB divider - 256
constexpr uint16_t hpreDiv256 {256};

/// ninth allowed value for AHB divider - 512
constexpr uint16_t hpreDiv512 {512};

/// first allowed value for APB1 and APB2 dividers - 1
constexpr uint8_t ppreDiv1 {1};

/// second allowed value for APB1 and APB2 dividers - 2
constexpr uint8_t ppreDiv2 {2};

/// third allowed value for APB1 and APB2 dividers - 4
constexpr uint8_t ppreDiv4 {4};

/// fourth allowed value for APB1 and APB2 dividers - 8
constexpr uint8_t ppreDiv8 {8};

/// fifth allowed value for APB1 and APB2 dividers - 16
constexpr uint8_t ppreDiv16 {16};

/*---------------------------------------------------------------------------------------------------------------------+
| global functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Configures divider of AHB clock (HPRE value).
 *
 * \param [in] hpre is the HPRE value, {1, 2, 4, 8, 16, 64, 128, 256, 512} or {hpreDiv1, hpreDiv2, hpreDiv4, hpreDiv8,
 * hpreDiv16, hpreDiv64, hpreDiv128, hpreDiv256, hpreDiv512}
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a hpre value is invalid;
 */

int configureAhbClockDivider(uint16_t hpre);

/**
 * \brief Configures divider of APB1 or APB2 clock (PPRE1 or PPRE2 value).
 *
 * \param [in] ppre2 selects whether PPRE1 (false) or PPRE2 (true) is configured
 * \param [in] ppre is the PPRE value, {1, 2, 4, 8, 16} or {ppreDiv1, ppreDiv2, ppreDiv4, ppreDiv8, ppreDiv16}
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a ppre value is invalid;
 */

int configureApbClockDivider(bool ppre2, uint8_t ppre);

/**
 * \brief Configures clock source of main PLL and audio PLLI2S.
 *
 * \warning Before changing configuration of main PLL and/or audio PLLI2S make sure that they are not used in any way
 * (as core clock or as source of peripheral clocks) and that they are disabled.
 *
 * \param [in] hse selects whether HSI (false) or HSE (true) is used as clock source of main PLL and audio PLLI2S
 */

void configurePllClockSource(bool hse);

/**
 * \brief Configures divider of PLL input clock (PLLM value) for main PLL and audio PLLI2S.
 *
 * \warning Before changing configuration of main PLL and/or audio PLLI2S make sure that they are not used in any way
 * (as core clock or as source of peripheral clocks) and that they are disabled.
 *
 * \param [in] pllm is the PLLM value for main PLL and audio PLLI2S, [2; 63] or [minPllm; maxPllm]
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a pllm value is invalid;
 */

int configurePllInputClockDivider(uint8_t pllm);

/**
 * \brief Enables HSE clock.
 *
 * Enables HSE clock using crystal/ceramic resonator (bypass disabled) or external user clock (bypass enabled). This
 * function waits until the HSE oscillator is stable after enabling the clock.
 *
 * \warning Before changing configuration of HSE clock make sure that it is not used in any way (as core clock, as
 * source for any PLL or as source of RTC clock).
 *
 * \param [in] bypass selects whether crystal/ceramic resonator (false) or external user clock (true) is used
 */

void enableHse(bool bypass);

/**
 * \brief Enables main PLL.
 *
 * Enables main PLL using selected parameters and waits until it is stable.
 *
 * \warning Before changing configuration of main PLL make sure that it is not used in any way (as core clock or as
 * source of peripheral clocks) and that it is disabled.
 *
 * \param [in] plln is the PLLN value for main PLL, [192; 432] or [minPlln; maxPlln]
 * \param [in] pllp is the PLLP value for main PLL, {2, 4, 6, 8} or {pllpDiv2, pllpDiv4, pllpDiv6, pllpDiv8}
 * \param [in] pllq is the PLLQ value for main PLL, [2; 15] or [minPllq; maxPllq]
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a plln or \a pllp or \a pllq value is invalid;
 */

int enablePll(uint16_t plln, uint8_t pllp, uint8_t pllq);

/**
 * \brief Disables HSE clock.
 *
 * \warning Before changing configuration of HSE clock make sure that it is not used in any way (as core clock, as
 * source for any PLL or as source of RTC clock).
 */

void disableHse();

/**
 * \brief Disables main PLL.
 *
 * \warning Before changing configuration of main PLL make sure that it is not used in any way (as core clock or as
 * source of peripheral clocks).
 */

void disablePll();

/**
 * \brief Switches system clock.
 *
 * \param [in] source is the new source of system clock, SystemClockSource::{hsi, hse, pll}
 */

void switchSystemClock(SystemClockSource source);

}	// namespace chip

}	// namespace distortos

#endif	// SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_
<commit_msg>chip: add constants with maximum APB frequencies to STM32F4-RCC.hpp<commit_after>/**
 * \file
 * \brief Header for RCC-related functions for STM32F4
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-09-17
 */

#ifndef SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_
#define SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_

#include <cstdint>

namespace distortos
{

namespace chip
{

/*---------------------------------------------------------------------------------------------------------------------+
| global types
+---------------------------------------------------------------------------------------------------------------------*/

/// system clock source
enum class SystemClockSource : uint8_t
{
	/// HSI oscillator selected as system clock
	hsi,
	/// HSE oscillator selected as system clock
	hse,
	/// main PLL selected as system clock
	pll,
};

/*---------------------------------------------------------------------------------------------------------------------+
| global constants
+---------------------------------------------------------------------------------------------------------------------*/

/// minimum allowed value for PLLM
constexpr uint8_t minPllm {2};

/// maximum allowed value for PLLM
constexpr uint8_t maxPllm {63};

/// minimum allowed value for PLLN
constexpr uint16_t minPlln {192};

/// maximum allowed value for PLLN
constexpr uint16_t maxPlln {432};

/// minimum allowed value for PLLQ
constexpr uint8_t minPllq {2};

/// maximum allowed value for PLLQ
constexpr uint8_t maxPllq {15};

/// first allowed value for PLLP - 2
constexpr uint8_t pllpDiv2 {2};

/// second allowed value for PLLP - 4
constexpr uint8_t pllpDiv4 {4};

/// third allowed value for PLLP - 6
constexpr uint8_t pllpDiv6 {6};

/// fourth allowed value for PLLP - 8
constexpr uint8_t pllpDiv8 {8};

/// HSI clock frequency, Hz
constexpr uint32_t hsiHz {16000000};

/// minimum allowed value for VCO input frequency, Hz
constexpr uint32_t minVcoInHz {1000000};

/// maximum allowed value for VCO input frequency, Hz
constexpr uint32_t maxVcoInHz {2000000};

/// minimum allowed value for VCO output frequency, Hz
constexpr uint32_t minVcoOutHz {192000000};

/// maximum allowed value for VCO output frequency, Hz
constexpr uint32_t maxVcoOutHz {432000000};

/// maximum allowed value for PLL output frequency, Hz
constexpr uint32_t maxPllOutHz {168000000};

/// maximum allowed value for PLL "Q" output frequency, Hz
constexpr uint32_t maxPllqOutHz {48000000};

/// maximum allowed APB1 (low speed) frequency, Hz
constexpr uint32_t maxApb1Hz {maxPllOutHz / 4};

/// maximum allowed APB2 (high speed) frequency, Hz
constexpr uint32_t maxApb2Hz {maxPllOutHz / 2};

/// first allowed value for AHB divider - 1
constexpr uint16_t hpreDiv1 {1};

/// second allowed value for AHB divider - 2
constexpr uint16_t hpreDiv2 {2};

/// third allowed value for AHB divider - 4
constexpr uint16_t hpreDiv4 {4};

/// fourth allowed value for AHB divider - 8
constexpr uint16_t hpreDiv8 {8};

/// fifth allowed value for AHB divider - 16
constexpr uint16_t hpreDiv16 {16};

/// sixth allowed value for AHB divider - 64
constexpr uint16_t hpreDiv64 {64};

/// seventh allowed value for AHB divider - 128
constexpr uint16_t hpreDiv128 {128};

/// eighth allowed value for AHB divider - 256
constexpr uint16_t hpreDiv256 {256};

/// ninth allowed value for AHB divider - 512
constexpr uint16_t hpreDiv512 {512};

/// first allowed value for APB1 and APB2 dividers - 1
constexpr uint8_t ppreDiv1 {1};

/// second allowed value for APB1 and APB2 dividers - 2
constexpr uint8_t ppreDiv2 {2};

/// third allowed value for APB1 and APB2 dividers - 4
constexpr uint8_t ppreDiv4 {4};

/// fourth allowed value for APB1 and APB2 dividers - 8
constexpr uint8_t ppreDiv8 {8};

/// fifth allowed value for APB1 and APB2 dividers - 16
constexpr uint8_t ppreDiv16 {16};

/*---------------------------------------------------------------------------------------------------------------------+
| global functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Configures divider of AHB clock (HPRE value).
 *
 * \param [in] hpre is the HPRE value, {1, 2, 4, 8, 16, 64, 128, 256, 512} or {hpreDiv1, hpreDiv2, hpreDiv4, hpreDiv8,
 * hpreDiv16, hpreDiv64, hpreDiv128, hpreDiv256, hpreDiv512}
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a hpre value is invalid;
 */

int configureAhbClockDivider(uint16_t hpre);

/**
 * \brief Configures divider of APB1 or APB2 clock (PPRE1 or PPRE2 value).
 *
 * \param [in] ppre2 selects whether PPRE1 (false) or PPRE2 (true) is configured
 * \param [in] ppre is the PPRE value, {1, 2, 4, 8, 16} or {ppreDiv1, ppreDiv2, ppreDiv4, ppreDiv8, ppreDiv16}
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a ppre value is invalid;
 */

int configureApbClockDivider(bool ppre2, uint8_t ppre);

/**
 * \brief Configures clock source of main PLL and audio PLLI2S.
 *
 * \warning Before changing configuration of main PLL and/or audio PLLI2S make sure that they are not used in any way
 * (as core clock or as source of peripheral clocks) and that they are disabled.
 *
 * \param [in] hse selects whether HSI (false) or HSE (true) is used as clock source of main PLL and audio PLLI2S
 */

void configurePllClockSource(bool hse);

/**
 * \brief Configures divider of PLL input clock (PLLM value) for main PLL and audio PLLI2S.
 *
 * \warning Before changing configuration of main PLL and/or audio PLLI2S make sure that they are not used in any way
 * (as core clock or as source of peripheral clocks) and that they are disabled.
 *
 * \param [in] pllm is the PLLM value for main PLL and audio PLLI2S, [2; 63] or [minPllm; maxPllm]
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a pllm value is invalid;
 */

int configurePllInputClockDivider(uint8_t pllm);

/**
 * \brief Enables HSE clock.
 *
 * Enables HSE clock using crystal/ceramic resonator (bypass disabled) or external user clock (bypass enabled). This
 * function waits until the HSE oscillator is stable after enabling the clock.
 *
 * \warning Before changing configuration of HSE clock make sure that it is not used in any way (as core clock, as
 * source for any PLL or as source of RTC clock).
 *
 * \param [in] bypass selects whether crystal/ceramic resonator (false) or external user clock (true) is used
 */

void enableHse(bool bypass);

/**
 * \brief Enables main PLL.
 *
 * Enables main PLL using selected parameters and waits until it is stable.
 *
 * \warning Before changing configuration of main PLL make sure that it is not used in any way (as core clock or as
 * source of peripheral clocks) and that it is disabled.
 *
 * \param [in] plln is the PLLN value for main PLL, [192; 432] or [minPlln; maxPlln]
 * \param [in] pllp is the PLLP value for main PLL, {2, 4, 6, 8} or {pllpDiv2, pllpDiv4, pllpDiv6, pllpDiv8}
 * \param [in] pllq is the PLLQ value for main PLL, [2; 15] or [minPllq; maxPllq]
 *
 * \return 0 on success, error code otherwise:
 * - EINVAL - \a plln or \a pllp or \a pllq value is invalid;
 */

int enablePll(uint16_t plln, uint8_t pllp, uint8_t pllq);

/**
 * \brief Disables HSE clock.
 *
 * \warning Before changing configuration of HSE clock make sure that it is not used in any way (as core clock, as
 * source for any PLL or as source of RTC clock).
 */

void disableHse();

/**
 * \brief Disables main PLL.
 *
 * \warning Before changing configuration of main PLL make sure that it is not used in any way (as core clock or as
 * source of peripheral clocks).
 */

void disablePll();

/**
 * \brief Switches system clock.
 *
 * \param [in] source is the new source of system clock, SystemClockSource::{hsi, hse, pll}
 */

void switchSystemClock(SystemClockSource source);

}	// namespace chip

}	// namespace distortos

#endif	// SOURCE_CHIP_STMICROELECTRONICS_STM32F4_INCLUDE_DISTORTOS_CHIP_STM32F4_RCC_HPP_
<|endoftext|>


<commit_before>/*****************************************************************************
*   Number Plate Recognition using SVM and Neural Networks
******************************************************************************
*   by David Milln Escriv, 5th Dec 2012
*   http://blog.damiles.com
******************************************************************************
*   Ch5 of the book "Mastering OpenCV with Practical Computer Vision Projects"
*   Copyright Packt Publishing 2012.
*   http://www.packtpub.com/cool-projects-with-opencv/book
*****************************************************************************/

// Main entry code OpenCV

#include <cv.h>
#include <highgui.h>
#include <cvaux.h>

#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main ( int argc, char** argv )
{
    cout << "OpenCV Training SVM Automatic Number Plate Recognition\n";
    cout << "\n";

    char* path_Plates;
    char* path_NoPlates;
    int numPlates;
    int numNoPlates;
    int imageWidth=144;
    int imageHeight=33;

    //Check if user specify image to process
    if(argc >= 5 )
    {
        numPlates= atoi(argv[1]);
        numNoPlates= atoi(argv[2]);
        path_Plates= argv[3];
        path_NoPlates= argv[4];

    }else{
        cout << "Usage:\n" << argv[0] << " <num Plate Files> <num Non Plate Files> <path to plate folder files> <path to non plate files> \n";
        return 0;
    }

    Mat classes;//(numPlates+numNoPlates, 1, CV_32FC1);
    Mat trainingData;//(numPlates+numNoPlates, imageWidth*imageHeight, CV_32FC1 );

    Mat trainingImages;
    vector<int> trainingLabels;

    for(int i=0; i< numPlates; i++)
    {

        stringstream ss(stringstream::in | stringstream::out);
        ss << path_Plates << i << ".jpg";
        Mat img=imread(ss.str(), 0);
        img= img.reshape(1, 1);
        trainingImages.push_back(img);
        trainingLabels.push_back(1);
    }

    for(int i=0; i< numNoPlates; i++)
    {
        stringstream ss(stringstream::in | stringstream::out);
        ss << path_NoPlates << i << ".jpg";
        Mat img=imread(ss.str(), 0);
        img= img.reshape(1, 1);
        trainingImages.push_back(img);
        trainingLabels.push_back(0);

    }

    Mat(trainingImages).copyTo(trainingData);
    //trainingData = trainingData.reshape(1,trainingData.rows);
    trainingData.convertTo(trainingData, CV_32FC1);
    Mat(trainingLabels).copyTo(classes);

    FileStorage fs("SVM.xml", FileStorage::WRITE);
    fs << "TrainingData" << trainingData;
    fs << "classes" << classes;
    fs.release();

    return 0;
}
<commit_msg>SVM train<commit_after>/*****************************************************************************
*   Number Plate Recognition using SVM and Neural Networks
******************************************************************************
*/

// Main entry code OpenCV

#include <cv.h>
#include <highgui.h>
#include <cvaux.h>

#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main ( int argc, char** argv )
{
    cout << "OpenCV Training SVM Automatic Number Plate Recognition\n";
    cout << "\n";

    char* path_Plates;
    char* path_NoPlates;
    int numPlates;
    int numNoPlates;
    int imageWidth=144;
    int imageHeight=33;

    //Check if user specify image to process
    if(argc >= 5 )
    {
        numPlates= atoi(argv[1]);
        numNoPlates= atoi(argv[2]);
        path_Plates= argv[3];
        path_NoPlates= argv[4];

    }else{
        cout << "Usage:\n" << argv[0] << " <num Plate Files> <num Non Plate Files> <path to plate folder files> <path to non plate files> \n";
        return 0;
    }

    Mat classes;//(numPlates+numNoPlates, 1, CV_32FC1);
    Mat trainingData;//(numPlates+numNoPlates, imageWidth*imageHeight, CV_32FC1 );

    Mat trainingImages;
    vector<int> trainingLabels;

    for(int i=0; i< numPlates; i++)
    {

        stringstream ss(stringstream::in | stringstream::out);
        ss << path_Plates << i << ".jpg";
        Mat img=imread(ss.str(), 0);
        img= img.reshape(1, 1);
        trainingImages.push_back(img);
        trainingLabels.push_back(1);
    }

    for(int i=0; i< numNoPlates; i++)
    {
        stringstream ss(stringstream::in | stringstream::out);
        ss << path_NoPlates << i << ".jpg";
        Mat img=imread(ss.str(), 0);
        img= img.reshape(1, 1);
        trainingImages.push_back(img);
        trainingLabels.push_back(0);

    }

    Mat(trainingImages).copyTo(trainingData);
    //trainingData = trainingData.reshape(1,trainingData.rows);
    trainingData.convertTo(trainingData, CV_32FC1);
    Mat(trainingLabels).copyTo(classes);

    FileStorage fs("SVM.xml", FileStorage::WRITE);
    fs << "TrainingData" << trainingData;
    fs << "classes" << classes;
    fs.release();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<string>)
#include <string>
#endif

#if __has_include(<QString>)
#include <QString>
#endif

#include "assert.hpp"
#include "bstring.hpp"
#include "string.hpp"
#include "strops.hpp"
#include "types.hpp"
#include "typetraits.hpp"

namespace ox {
namespace detail {

constexpr const char *toCString(const char *s) noexcept {
	return s;
}

template<std::size_t size>
constexpr const char *toCString(const BString<size> &s) noexcept {
    return s.c_str();
}

template<std::size_t size>
constexpr const char *toCString(const BasicString<size> &s) noexcept {
    return s.c_str();
}

#if __has_include(<string>)
#if __cplusplus >= 202002L
constexpr
#else
inline
#endif
const char *toCString(const std::string &s) noexcept {
	return s.c_str();
}
#endif

#if __has_include(<QString>)
inline const char *toCString(const QString &s) noexcept {
	return s.toUtf8();
}
#endif

class FmtArg {

	private:
		char dataStr[10] = {};

	public:
		const char *out = nullptr;

		template<typename T>
		constexpr FmtArg(const T &v) noexcept {
			if constexpr(is_bool_v<T>) {
				out = v ? "true" : "false";
			} else if constexpr(is_integral_v<T>) {
				out = ox_itoa(v, dataStr);
			} else {
				out = toCString(v);
			}
		}

};

[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
	uint64_t cnt = 0;
	const auto prev = [str](std::size_t i) -> char {
		if (i > 0) {
			return str[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [str](std::size_t i) -> char {
		if (i < ox_strlen(str) - 1) {
			return str[i + 1];
		} else {
			return '\0';
		}
	};
	for (std::size_t i = 0; i < ox_strlen(str); ++i) {
		if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++cnt;
		}
	}
	return cnt;
}

struct FmtSegment {
	const char *str = nullptr;
	unsigned length = 0;

	constexpr bool operator==(const FmtSegment &o) const noexcept {
		return length == o.length && ox_strncmp(str, o.str, length) == 0;
	}

	constexpr bool operator!=(const FmtSegment &o) const noexcept {
		return length != o.length || ox_strncmp(str, o.str, length) != 0;
	}
};

template<std::size_t sz>
struct Fmt {
	static constexpr std::size_t size = sz;
	FmtSegment segments[sz];

	constexpr bool operator==(const Fmt<sz> &o) const noexcept {
		for (std::size_t i = 0; i < sz; ++i) {
			if (segments[i] != o.segments[i]) {
				return false;
			}
		}
		return true;
	}
};

template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
	Fmt<segementCnt> out;
	const auto prev = [fmt](std::size_t i) -> char {
		if (i > 0) {
			return fmt[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [fmt](std::size_t i) -> char {
		if (i < ox_strlen(fmt) - 1) {
			return fmt[i + 1];
		} else {
			return '\0';
		}
	};
	auto current = &out.segments[0];
	current->str = fmt;
	for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
		if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++current;
			current->str = fmt + i + 2;
			current->length = 0;
			i += 1;
		} else {
			++current->length;
		}
	}
	return out;
}

}

template<typename StringType = String, typename ...Args>
[[nodiscard]]
StringType sfmt(const char *fmt, Args... args) noexcept {
	oxAssert(ox::detail::argCount(fmt) == sizeof...(args), "Argument count mismatch.");
	StringType out;
	const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);
	const auto &firstSegment = fmtSegments.segments[0];
	oxIgnoreError(out.append(firstSegment.str, firstSegment.length));
	const detail::FmtArg elements[sizeof...(args)] = {args...};
	for (auto i = 0u; i < fmtSegments.size - 1; ++i) {
		out += elements[i].out;
		const auto &s = fmtSegments.segments[i + 1];
		oxIgnoreError(out.append(s.str, s.length));
	}
	return move(out);
}

}
<commit_msg>[ox/std] Fix formatting error<commit_after>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<string>)
#include <string>
#endif

#if __has_include(<QString>)
#include <QString>
#endif

#include "assert.hpp"
#include "bstring.hpp"
#include "string.hpp"
#include "strops.hpp"
#include "types.hpp"
#include "typetraits.hpp"

namespace ox {
namespace detail {

constexpr const char *toCString(const char *s) noexcept {
	return s;
}

template<std::size_t size>
constexpr const char *toCString(const BString<size> &s) noexcept {
	return s.c_str();
}

template<std::size_t size>
constexpr const char *toCString(const BasicString<size> &s) noexcept {
	return s.c_str();
}

#if __has_include(<string>)
#if __cplusplus >= 202002L
constexpr
#else
inline
#endif
const char *toCString(const std::string &s) noexcept {
	return s.c_str();
}
#endif

#if __has_include(<QString>)
inline const char *toCString(const QString &s) noexcept {
	return s.toUtf8();
}
#endif

class FmtArg {

	private:
		char dataStr[10] = {};

	public:
		const char *out = nullptr;

		template<typename T>
		constexpr FmtArg(const T &v) noexcept {
			if constexpr(is_bool_v<T>) {
				out = v ? "true" : "false";
			} else if constexpr(is_integral_v<T>) {
				out = ox_itoa(v, dataStr);
			} else {
				out = toCString(v);
			}
		}

};

[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
	uint64_t cnt = 0;
	const auto prev = [str](std::size_t i) -> char {
		if (i > 0) {
			return str[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [str](std::size_t i) -> char {
		if (i < ox_strlen(str) - 1) {
			return str[i + 1];
		} else {
			return '\0';
		}
	};
	for (std::size_t i = 0; i < ox_strlen(str); ++i) {
		if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++cnt;
		}
	}
	return cnt;
}

struct FmtSegment {
	const char *str = nullptr;
	unsigned length = 0;

	constexpr bool operator==(const FmtSegment &o) const noexcept {
		return length == o.length && ox_strncmp(str, o.str, length) == 0;
	}

	constexpr bool operator!=(const FmtSegment &o) const noexcept {
		return length != o.length || ox_strncmp(str, o.str, length) != 0;
	}
};

template<std::size_t sz>
struct Fmt {
	static constexpr std::size_t size = sz;
	FmtSegment segments[sz];

	constexpr bool operator==(const Fmt<sz> &o) const noexcept {
		for (std::size_t i = 0; i < sz; ++i) {
			if (segments[i] != o.segments[i]) {
				return false;
			}
		}
		return true;
	}
};

template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
	Fmt<segementCnt> out;
	const auto prev = [fmt](std::size_t i) -> char {
		if (i > 0) {
			return fmt[i - 1];
		} else {
			return '\0';
		}
	};
	const auto next = [fmt](std::size_t i) -> char {
		if (i < ox_strlen(fmt) - 1) {
			return fmt[i + 1];
		} else {
			return '\0';
		}
	};
	auto current = &out.segments[0];
	current->str = fmt;
	for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
		if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
			++current;
			current->str = fmt + i + 2;
			current->length = 0;
			i += 1;
		} else {
			++current->length;
		}
	}
	return out;
}

}

template<typename StringType = String, typename ...Args>
[[nodiscard]]
StringType sfmt(const char *fmt, Args... args) noexcept {
	oxAssert(ox::detail::argCount(fmt) == sizeof...(args), "Argument count mismatch.");
	StringType out;
	const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);
	const auto &firstSegment = fmtSegments.segments[0];
	oxIgnoreError(out.append(firstSegment.str, firstSegment.length));
	const detail::FmtArg elements[sizeof...(args)] = {args...};
	for (auto i = 0u; i < fmtSegments.size - 1; ++i) {
		out += elements[i].out;
		const auto &s = fmtSegments.segments[i + 1];
		oxIgnoreError(out.append(s.str, s.length));
	}
	return move(out);
}

}
<|endoftext|>


<commit_before>//===-- Function.cpp - Implement the Global object classes ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Function & GlobalVariable classes for the VMCore
// library.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

BasicBlock *ilist_traits<BasicBlock>::createSentinel() {
  BasicBlock *Ret = new BasicBlock();
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<BasicBlock> &ilist_traits<BasicBlock>::getList(Function *F) {
  return F->getBasicBlockList();
}

Argument *ilist_traits<Argument>::createSentinel() {
  Argument *Ret = new Argument(Type::IntTy);
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<Argument> &ilist_traits<Argument>::getList(Function *F) {
  return F->getArgumentList();
}

// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Argument, Function, Function>;
template class SymbolTableListTraits<BasicBlock, Function, Function>;

//===----------------------------------------------------------------------===//
// Argument Implementation
//===----------------------------------------------------------------------===//

Argument::Argument(const Type *Ty, const std::string &Name, Function *Par)
  : Value(Ty, Value::ArgumentVal, Name) {
  Parent = 0;

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (Par)
    Par->getArgumentList().push_back(this);
}

void Argument::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

//===----------------------------------------------------------------------===//
// Function Implementation
//===----------------------------------------------------------------------===//

Function::Function(const FunctionType *Ty, LinkageTypes Linkage,
                   const std::string &name, Module *ParentModule)
  : GlobalValue(PointerType::get(Ty), Value::FunctionVal, 0, 0, Linkage, name) {
  CallingConvention = 0;
  BasicBlocks.setItemParent(this);
  BasicBlocks.setParent(this);
  ArgumentList.setItemParent(this);
  ArgumentList.setParent(this);
  SymTab = new SymbolTable();

  assert((getReturnType()->isFirstClassType() ||getReturnType() == Type::VoidTy)
         && "LLVM functions cannot return aggregate values!");

  // Create the arguments vector, all arguments start out unnamed.
  for (unsigned i = 0, e = Ty->getNumParams(); i != e; ++i) {
    assert(Ty->getParamType(i) != Type::VoidTy &&
           "Cannot have void typed arguments!");
    ArgumentList.push_back(new Argument(Ty->getParamType(i)));
  }

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (ParentModule)
    ParentModule->getFunctionList().push_back(this);
}

Function::~Function() {
  dropAllReferences();    // After this it is safe to delete instructions.

  // Delete all of the method arguments and unlink from symbol table...
  ArgumentList.clear();
  ArgumentList.setParent(0);
  delete SymTab;
}

void Function::setParent(Module *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

const FunctionType *Function::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

bool Function::isVarArg() const {
  return getFunctionType()->isVarArg();
}

const Type *Function::getReturnType() const {
  return getFunctionType()->getReturnType();
}

void Function::removeFromParent() {
  getParent()->getFunctionList().remove(this);
}

void Function::eraseFromParent() {
  getParent()->getFunctionList().erase(this);
}

/// renameLocalSymbols - This method goes through the Function's symbol table
/// and renames any symbols that conflict with symbols at global scope.  This is
/// required before printing out to a textual form, to ensure that there is no
/// ambiguity when parsing.
void Function::renameLocalSymbols() {
  SymbolTable &LST = getSymbolTable();                 // Local Symtab
  SymbolTable &GST = getParent()->getSymbolTable();    // Global Symtab

  for (SymbolTable::plane_iterator LPI = LST.plane_begin(), E = LST.plane_end();
       LPI != E; ++LPI)
    // All global symbols are of pointer type, ignore any non-pointer planes.
    if (const PointerType *CurTy = dyn_cast<PointerType>(LPI->first)) {
      // Only check if the global plane has any symbols of this type.
      SymbolTable::plane_iterator GPI = GST.find(LPI->first);
      if (GPI != GST.plane_end()) {
        SymbolTable::ValueMap &LVM       = LPI->second;
        const SymbolTable::ValueMap &GVM = GPI->second;

        // Loop over all local symbols, renaming those that are in the global
        // symbol table already.
        for (SymbolTable::value_iterator VI = LVM.begin(), E = LVM.end();
             VI != E;) {
          Value *V                = VI->second;
          const std::string &Name = VI->first;
          ++VI;
          if (GVM.count(Name)) {
            static unsigned UniqueNum = 0;
            // Find a name that does not conflict!
            while (GVM.count(Name + "_" + utostr(++UniqueNum)) ||
                   LVM.count(Name + "_" + utostr(UniqueNum)))
              /* scan for UniqueNum that works */;
            V->setName(Name + "_" + utostr(UniqueNum));
          }
        }
      }
    }
}

// dropAllReferences() - This function causes all the subinstructions to "let
// go" of all references that they are maintaining.  This allows one to
// 'delete' a whole class at a time, even though there may be circular
// references... first all references are dropped, and all use counts go to
// zero.  Then everything is deleted for real.  Note that no operations are
// valid on an object that has "dropped all references", except operator
// delete.
//
void Function::dropAllReferences() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
  BasicBlocks.clear();    // Delete all basic blocks...
}

/// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an
/// intrinsic, or if the pointer is null.  This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not.  The
/// particular intrinsic functions which correspond to this value are defined in
/// llvm/Intrinsics.h.
///
unsigned Function::getIntrinsicID() const {
  if (getName().size() < 5 || getName()[4] != '.' || getName()[0] != 'l' ||
      getName()[1] != 'l' || getName()[2] != 'v' || getName()[3] != 'm')
    return 0;  // All intrinsics start with 'llvm.'

  assert(getName().size() != 5 && "'llvm.' is an invalid intrinsic name!");

  switch (getName()[5]) {
  case 'b':
    if (getName() == "llvm.bswap.i16") return Intrinsic::bswap_i16;
    if (getName() == "llvm.bswap.i32") return Intrinsic::bswap_i32;
    if (getName() == "llvm.bswap.i64") return Intrinsic::bswap_i64;
    break;
  case 'c':
    if (getName() == "llvm.ctpop") return Intrinsic::ctpop;
    if (getName() == "llvm.cttz") return Intrinsic::cttz;
    if (getName() == "llvm.ctlz") return Intrinsic::ctlz;
    break;
  case 'd':
    if (getName() == "llvm.dbg.stoppoint")   return Intrinsic::dbg_stoppoint;
    if (getName() == "llvm.dbg.region.start")return Intrinsic::dbg_region_start;
    if (getName() == "llvm.dbg.region.end")  return Intrinsic::dbg_region_end;
    if (getName() == "llvm.dbg.func.start")  return Intrinsic::dbg_func_start;
    if (getName() == "llvm.dbg.declare")     return Intrinsic::dbg_declare;
    break;
  case 'f':
    if (getName() == "llvm.frameaddress")  return Intrinsic::frameaddress;
    break;
  case 'g':
    if (getName() == "llvm.gcwrite") return Intrinsic::gcwrite;
    if (getName() == "llvm.gcread")  return Intrinsic::gcread;
    if (getName() == "llvm.gcroot")  return Intrinsic::gcroot;
    break;
  case 'i':
    if (getName() == "llvm.isunordered") return Intrinsic::isunordered;
    break;
  case 'l':
    if (getName() == "llvm.longjmp")  return Intrinsic::longjmp;
    break;
  case 'm':
    if (getName() == "llvm.memcpy")  return Intrinsic::memcpy;
    if (getName() == "llvm.memmove")  return Intrinsic::memmove;
    if (getName() == "llvm.memset")  return Intrinsic::memset;
    break;
  case 'p':
    if (getName() == "llvm.prefetch")  return Intrinsic::prefetch;
    if (getName() == "llvm.pcmarker")  return Intrinsic::pcmarker;
    break;
  case 'r':
    if (getName() == "llvm.returnaddress")    return Intrinsic::returnaddress;
    if (getName() == "llvm.readport")         return Intrinsic::readport;
    if (getName() == "llvm.readio")           return Intrinsic::readio;
    if (getName() == "llvm.readcyclecounter") return Intrinsic::readcyclecounter;
    break;
  case 's':
    if (getName() == "llvm.setjmp")       return Intrinsic::setjmp;
    if (getName() == "llvm.sigsetjmp")    return Intrinsic::sigsetjmp;
    if (getName() == "llvm.siglongjmp")   return Intrinsic::siglongjmp;
    if (getName() == "llvm.stackrestore") return Intrinsic::stackrestore;
    if (getName() == "llvm.stacksave")    return Intrinsic::stacksave;
    if (getName() == "llvm.sqrt")         return Intrinsic::sqrt;
    break;
  case 'v':
    if (getName() == "llvm.va_copy")  return Intrinsic::vacopy;
    if (getName() == "llvm.va_end")   return Intrinsic::vaend;
    if (getName() == "llvm.va_start") return Intrinsic::vastart;
  case 'w':
    if (getName() == "llvm.writeport") return Intrinsic::writeport;
    if (getName() == "llvm.writeio")   return Intrinsic::writeio;
    break;
  }
  // The "llvm." namespace is reserved!
  assert(0 && "Unknown LLVM intrinsic function!");
  return 0;
}

Value *IntrinsicInst::StripPointerCasts(Value *Ptr) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
    if (CE->getOpcode() == Instruction::Cast) {
      if (isa<PointerType>(CE->getOperand(0)->getType()))
        return StripPointerCasts(CE->getOperand(0));
    } else if (CE->getOpcode() == Instruction::GetElementPtr) {
      for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
        if (!CE->getOperand(i)->isNullValue())
          return Ptr;
      return StripPointerCasts(CE->getOperand(0));
    }
    return Ptr;
  }

  if (CastInst *CI = dyn_cast<CastInst>(Ptr)) {
    if (isa<PointerType>(CI->getOperand(0)->getType()))
      return StripPointerCasts(CI->getOperand(0));
  } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
    for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
      if (!isa<Constant>(GEP->getOperand(i)) ||
          !cast<Constant>(GEP->getOperand(i))->isNullValue())
        return Ptr;
    return StripPointerCasts(GEP->getOperand(0));
  }
  return Ptr;
}

// vim: sw=2 ai
<commit_msg>add a missing break that Reid noticed.<commit_after>//===-- Function.cpp - Implement the Global object classes ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Function & GlobalVariable classes for the VMCore
// library.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/DerivedTypes.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/LeakDetector.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;

BasicBlock *ilist_traits<BasicBlock>::createSentinel() {
  BasicBlock *Ret = new BasicBlock();
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<BasicBlock> &ilist_traits<BasicBlock>::getList(Function *F) {
  return F->getBasicBlockList();
}

Argument *ilist_traits<Argument>::createSentinel() {
  Argument *Ret = new Argument(Type::IntTy);
  // This should not be garbage monitored.
  LeakDetector::removeGarbageObject(Ret);
  return Ret;
}

iplist<Argument> &ilist_traits<Argument>::getList(Function *F) {
  return F->getArgumentList();
}

// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class SymbolTableListTraits<Argument, Function, Function>;
template class SymbolTableListTraits<BasicBlock, Function, Function>;

//===----------------------------------------------------------------------===//
// Argument Implementation
//===----------------------------------------------------------------------===//

Argument::Argument(const Type *Ty, const std::string &Name, Function *Par)
  : Value(Ty, Value::ArgumentVal, Name) {
  Parent = 0;

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (Par)
    Par->getArgumentList().push_back(this);
}

void Argument::setParent(Function *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

//===----------------------------------------------------------------------===//
// Function Implementation
//===----------------------------------------------------------------------===//

Function::Function(const FunctionType *Ty, LinkageTypes Linkage,
                   const std::string &name, Module *ParentModule)
  : GlobalValue(PointerType::get(Ty), Value::FunctionVal, 0, 0, Linkage, name) {
  CallingConvention = 0;
  BasicBlocks.setItemParent(this);
  BasicBlocks.setParent(this);
  ArgumentList.setItemParent(this);
  ArgumentList.setParent(this);
  SymTab = new SymbolTable();

  assert((getReturnType()->isFirstClassType() ||getReturnType() == Type::VoidTy)
         && "LLVM functions cannot return aggregate values!");

  // Create the arguments vector, all arguments start out unnamed.
  for (unsigned i = 0, e = Ty->getNumParams(); i != e; ++i) {
    assert(Ty->getParamType(i) != Type::VoidTy &&
           "Cannot have void typed arguments!");
    ArgumentList.push_back(new Argument(Ty->getParamType(i)));
  }

  // Make sure that we get added to a function
  LeakDetector::addGarbageObject(this);

  if (ParentModule)
    ParentModule->getFunctionList().push_back(this);
}

Function::~Function() {
  dropAllReferences();    // After this it is safe to delete instructions.

  // Delete all of the method arguments and unlink from symbol table...
  ArgumentList.clear();
  ArgumentList.setParent(0);
  delete SymTab;
}

void Function::setParent(Module *parent) {
  if (getParent())
    LeakDetector::addGarbageObject(this);
  Parent = parent;
  if (getParent())
    LeakDetector::removeGarbageObject(this);
}

const FunctionType *Function::getFunctionType() const {
  return cast<FunctionType>(getType()->getElementType());
}

bool Function::isVarArg() const {
  return getFunctionType()->isVarArg();
}

const Type *Function::getReturnType() const {
  return getFunctionType()->getReturnType();
}

void Function::removeFromParent() {
  getParent()->getFunctionList().remove(this);
}

void Function::eraseFromParent() {
  getParent()->getFunctionList().erase(this);
}

/// renameLocalSymbols - This method goes through the Function's symbol table
/// and renames any symbols that conflict with symbols at global scope.  This is
/// required before printing out to a textual form, to ensure that there is no
/// ambiguity when parsing.
void Function::renameLocalSymbols() {
  SymbolTable &LST = getSymbolTable();                 // Local Symtab
  SymbolTable &GST = getParent()->getSymbolTable();    // Global Symtab

  for (SymbolTable::plane_iterator LPI = LST.plane_begin(), E = LST.plane_end();
       LPI != E; ++LPI)
    // All global symbols are of pointer type, ignore any non-pointer planes.
    if (const PointerType *CurTy = dyn_cast<PointerType>(LPI->first)) {
      // Only check if the global plane has any symbols of this type.
      SymbolTable::plane_iterator GPI = GST.find(LPI->first);
      if (GPI != GST.plane_end()) {
        SymbolTable::ValueMap &LVM       = LPI->second;
        const SymbolTable::ValueMap &GVM = GPI->second;

        // Loop over all local symbols, renaming those that are in the global
        // symbol table already.
        for (SymbolTable::value_iterator VI = LVM.begin(), E = LVM.end();
             VI != E;) {
          Value *V                = VI->second;
          const std::string &Name = VI->first;
          ++VI;
          if (GVM.count(Name)) {
            static unsigned UniqueNum = 0;
            // Find a name that does not conflict!
            while (GVM.count(Name + "_" + utostr(++UniqueNum)) ||
                   LVM.count(Name + "_" + utostr(UniqueNum)))
              /* scan for UniqueNum that works */;
            V->setName(Name + "_" + utostr(UniqueNum));
          }
        }
      }
    }
}

// dropAllReferences() - This function causes all the subinstructions to "let
// go" of all references that they are maintaining.  This allows one to
// 'delete' a whole class at a time, even though there may be circular
// references... first all references are dropped, and all use counts go to
// zero.  Then everything is deleted for real.  Note that no operations are
// valid on an object that has "dropped all references", except operator
// delete.
//
void Function::dropAllReferences() {
  for (iterator I = begin(), E = end(); I != E; ++I)
    I->dropAllReferences();
  BasicBlocks.clear();    // Delete all basic blocks...
}

/// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an
/// intrinsic, or if the pointer is null.  This value is always defined to be
/// zero to allow easy checking for whether a function is intrinsic or not.  The
/// particular intrinsic functions which correspond to this value are defined in
/// llvm/Intrinsics.h.
///
unsigned Function::getIntrinsicID() const {
  if (getName().size() < 5 || getName()[4] != '.' || getName()[0] != 'l' ||
      getName()[1] != 'l' || getName()[2] != 'v' || getName()[3] != 'm')
    return 0;  // All intrinsics start with 'llvm.'

  assert(getName().size() != 5 && "'llvm.' is an invalid intrinsic name!");

  switch (getName()[5]) {
  case 'b':
    if (getName() == "llvm.bswap.i16") return Intrinsic::bswap_i16;
    if (getName() == "llvm.bswap.i32") return Intrinsic::bswap_i32;
    if (getName() == "llvm.bswap.i64") return Intrinsic::bswap_i64;
    break;
  case 'c':
    if (getName() == "llvm.ctpop") return Intrinsic::ctpop;
    if (getName() == "llvm.cttz") return Intrinsic::cttz;
    if (getName() == "llvm.ctlz") return Intrinsic::ctlz;
    break;
  case 'd':
    if (getName() == "llvm.dbg.stoppoint")   return Intrinsic::dbg_stoppoint;
    if (getName() == "llvm.dbg.region.start")return Intrinsic::dbg_region_start;
    if (getName() == "llvm.dbg.region.end")  return Intrinsic::dbg_region_end;
    if (getName() == "llvm.dbg.func.start")  return Intrinsic::dbg_func_start;
    if (getName() == "llvm.dbg.declare")     return Intrinsic::dbg_declare;
    break;
  case 'f':
    if (getName() == "llvm.frameaddress")  return Intrinsic::frameaddress;
    break;
  case 'g':
    if (getName() == "llvm.gcwrite") return Intrinsic::gcwrite;
    if (getName() == "llvm.gcread")  return Intrinsic::gcread;
    if (getName() == "llvm.gcroot")  return Intrinsic::gcroot;
    break;
  case 'i':
    if (getName() == "llvm.isunordered") return Intrinsic::isunordered;
    break;
  case 'l':
    if (getName() == "llvm.longjmp")  return Intrinsic::longjmp;
    break;
  case 'm':
    if (getName() == "llvm.memcpy")  return Intrinsic::memcpy;
    if (getName() == "llvm.memmove")  return Intrinsic::memmove;
    if (getName() == "llvm.memset")  return Intrinsic::memset;
    break;
  case 'p':
    if (getName() == "llvm.prefetch")  return Intrinsic::prefetch;
    if (getName() == "llvm.pcmarker")  return Intrinsic::pcmarker;
    break;
  case 'r':
    if (getName() == "llvm.returnaddress")    return Intrinsic::returnaddress;
    if (getName() == "llvm.readport")         return Intrinsic::readport;
    if (getName() == "llvm.readio")           return Intrinsic::readio;
    if (getName() == "llvm.readcyclecounter") return Intrinsic::readcyclecounter;
    break;
  case 's':
    if (getName() == "llvm.setjmp")       return Intrinsic::setjmp;
    if (getName() == "llvm.sigsetjmp")    return Intrinsic::sigsetjmp;
    if (getName() == "llvm.siglongjmp")   return Intrinsic::siglongjmp;
    if (getName() == "llvm.stackrestore") return Intrinsic::stackrestore;
    if (getName() == "llvm.stacksave")    return Intrinsic::stacksave;
    if (getName() == "llvm.sqrt")         return Intrinsic::sqrt;
    break;
  case 'v':
    if (getName() == "llvm.va_copy")  return Intrinsic::vacopy;
    if (getName() == "llvm.va_end")   return Intrinsic::vaend;
    if (getName() == "llvm.va_start") return Intrinsic::vastart;
    break;
  case 'w':
    if (getName() == "llvm.writeport") return Intrinsic::writeport;
    if (getName() == "llvm.writeio")   return Intrinsic::writeio;
    break;
  }
  // The "llvm." namespace is reserved!
  assert(0 && "Unknown LLVM intrinsic function!");
  return 0;
}

Value *IntrinsicInst::StripPointerCasts(Value *Ptr) {
  if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr)) {
    if (CE->getOpcode() == Instruction::Cast) {
      if (isa<PointerType>(CE->getOperand(0)->getType()))
        return StripPointerCasts(CE->getOperand(0));
    } else if (CE->getOpcode() == Instruction::GetElementPtr) {
      for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
        if (!CE->getOperand(i)->isNullValue())
          return Ptr;
      return StripPointerCasts(CE->getOperand(0));
    }
    return Ptr;
  }

  if (CastInst *CI = dyn_cast<CastInst>(Ptr)) {
    if (isa<PointerType>(CI->getOperand(0)->getType()))
      return StripPointerCasts(CI->getOperand(0));
  } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr)) {
    for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
      if (!isa<Constant>(GEP->getOperand(i)) ||
          !cast<Constant>(GEP->getOperand(i))->isNullValue())
        return Ptr;
    return StripPointerCasts(GEP->getOperand(0));
  }
  return Ptr;
}

// vim: sw=2 ai
<|endoftext|>


<commit_before>//===-------- LoopDataPrefetch.cpp - Loop Data Prefetching Pass -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Loop Data Prefetching Pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"

#define DEBUG_TYPE "loop-data-prefetch"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
using namespace llvm;

// By default, we limit this to creating 16 PHIs (which is a little over half
// of the allocatable register set).
static cl::opt<bool>
PrefetchWrites("loop-prefetch-writes", cl::Hidden, cl::init(false),
               cl::desc("Prefetch write addresses"));

static cl::opt<unsigned>
    PrefetchDistance("prefetch-distance",
                     cl::desc("Number of instructions to prefetch ahead"),
                     cl::Hidden);

static cl::opt<unsigned>
    MinPrefetchStride("min-prefetch-stride",
                      cl::desc("Min stride to add prefetches"), cl::Hidden);

static cl::opt<unsigned> MaxPrefetchIterationsAhead(
    "max-prefetch-iters-ahead",
    cl::desc("Max number of iterations to prefetch ahead"), cl::Hidden);

STATISTIC(NumPrefetches, "Number of prefetches inserted");

namespace {

/// Loop prefetch implementation class.
class LoopDataPrefetch {
public:
  LoopDataPrefetch(AssumptionCache *AC, LoopInfo *LI, ScalarEvolution *SE,
                   const TargetTransformInfo *TTI,
                   OptimizationRemarkEmitter *ORE)
      : AC(AC), LI(LI), SE(SE), TTI(TTI), ORE(ORE) {}

  bool run();

private:
  bool runOnLoop(Loop *L);

  /// \brief Check if the the stride of the accesses is large enough to
  /// warrant a prefetch.
  bool isStrideLargeEnough(const SCEVAddRecExpr *AR);

  unsigned getMinPrefetchStride() {
    if (MinPrefetchStride.getNumOccurrences() > 0)
      return MinPrefetchStride;
    return TTI->getMinPrefetchStride();
  }

  unsigned getPrefetchDistance() {
    if (PrefetchDistance.getNumOccurrences() > 0)
      return PrefetchDistance;
    return TTI->getPrefetchDistance();
  }

  unsigned getMaxPrefetchIterationsAhead() {
    if (MaxPrefetchIterationsAhead.getNumOccurrences() > 0)
      return MaxPrefetchIterationsAhead;
    return TTI->getMaxPrefetchIterationsAhead();
  }

  AssumptionCache *AC;
  LoopInfo *LI;
  ScalarEvolution *SE;
  const TargetTransformInfo *TTI;
  OptimizationRemarkEmitter *ORE;
};

/// Legacy class for inserting loop data prefetches.
class LoopDataPrefetchLegacyPass : public FunctionPass {
public:
  static char ID; // Pass ID, replacement for typeid
  LoopDataPrefetchLegacyPass() : FunctionPass(ID) {
    initializeLoopDataPrefetchLegacyPassPass(*PassRegistry::getPassRegistry());
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequired<AssumptionCacheTracker>();
    AU.addPreserved<DominatorTreeWrapperPass>();
    AU.addRequired<LoopInfoWrapperPass>();
    AU.addPreserved<LoopInfoWrapperPass>();
    AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
    AU.addRequired<ScalarEvolutionWrapperPass>();
    // FIXME: For some reason, preserving SE here breaks LSR (even if
    // this pass changes nothing).
    // AU.addPreserved<ScalarEvolutionWrapperPass>();
    AU.addRequired<TargetTransformInfoWrapperPass>();
  }

  bool runOnFunction(Function &F) override;
  };
}

char LoopDataPrefetchLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(LoopDataPrefetchLegacyPass, "loop-data-prefetch",
                      "Loop Data Prefetch", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(LoopDataPrefetchLegacyPass, "loop-data-prefetch",
                    "Loop Data Prefetch", false, false)

FunctionPass *llvm::createLoopDataPrefetchPass() {
  return new LoopDataPrefetchLegacyPass();
}

bool LoopDataPrefetch::isStrideLargeEnough(const SCEVAddRecExpr *AR) {
  unsigned TargetMinStride = getMinPrefetchStride();
  // No need to check if any stride goes.
  if (TargetMinStride <= 1)
    return true;

  const auto *ConstStride = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*SE));
  // If MinStride is set, don't prefetch unless we can ensure that stride is
  // larger.
  if (!ConstStride)
    return false;

  unsigned AbsStride = std::abs(ConstStride->getAPInt().getSExtValue());
  return TargetMinStride <= AbsStride;
}

PreservedAnalyses LoopDataPrefetchPass::run(Function &F,
                                            FunctionAnalysisManager &AM) {
  LoopInfo *LI = &AM.getResult<LoopAnalysis>(F);
  ScalarEvolution *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
  AssumptionCache *AC = &AM.getResult<AssumptionAnalysis>(F);
  OptimizationRemarkEmitter *ORE =
      &AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
  const TargetTransformInfo *TTI = &AM.getResult<TargetIRAnalysis>(F);

  LoopDataPrefetch LDP(AC, LI, SE, TTI, ORE);
  bool Changed = LDP.run();

  if (Changed) {
    PreservedAnalyses PA;
    PA.preserve<DominatorTreeAnalysis>();
    PA.preserve<LoopAnalysis>();
    return PA;
  }

  return PreservedAnalyses::all();
}

bool LoopDataPrefetchLegacyPass::runOnFunction(Function &F) {
  if (skipFunction(F))
    return false;

  LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
  ScalarEvolution *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
  AssumptionCache *AC =
      &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  OptimizationRemarkEmitter *ORE =
      &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
  const TargetTransformInfo *TTI =
      &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);

  LoopDataPrefetch LDP(AC, LI, SE, TTI, ORE);
  return LDP.run();
}

bool LoopDataPrefetch::run() {
  // If PrefetchDistance is not set, don't run the pass.  This gives an
  // opportunity for targets to run this pass for selected subtargets only
  // (whose TTI sets PrefetchDistance).
  if (getPrefetchDistance() == 0)
    return false;
  assert(TTI->getCacheLineSize() && "Cache line size is not set for target");

  bool MadeChange = false;

  for (Loop *I : *LI)
    for (auto L = df_begin(I), LE = df_end(I); L != LE; ++L)
      MadeChange |= runOnLoop(*L);

  return MadeChange;
}

bool LoopDataPrefetch::runOnLoop(Loop *L) {
  bool MadeChange = false;

  // Only prefetch in the inner-most loop
  if (!L->empty())
    return MadeChange;

  SmallPtrSet<const Value *, 32> EphValues;
  CodeMetrics::collectEphemeralValues(L, AC, EphValues);

  // Calculate the number of iterations ahead to prefetch
  CodeMetrics Metrics;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {

    // If the loop already has prefetches, then assume that the user knows
    // what they are doing and don't add any more.
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
         J != JE; ++J)
      if (CallInst *CI = dyn_cast<CallInst>(J))
        if (Function *F = CI->getCalledFunction())
          if (F->getIntrinsicID() == Intrinsic::prefetch)
            return MadeChange;

    Metrics.analyzeBasicBlock(*I, *TTI, EphValues);
  }
  unsigned LoopSize = Metrics.NumInsts;
  if (!LoopSize)
    LoopSize = 1;

  unsigned ItersAhead = getPrefetchDistance() / LoopSize;
  if (!ItersAhead)
    ItersAhead = 1;

  if (ItersAhead > getMaxPrefetchIterationsAhead())
    return MadeChange;

  DEBUG(dbgs() << "Prefetching " << ItersAhead
               << " iterations ahead (loop size: " << LoopSize << ") in "
               << L->getHeader()->getParent()->getName() << ": " << *L);

  SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>, 16> PrefLoads;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
        J != JE; ++J) {
      Value *PtrValue;
      Instruction *MemI;

      if (LoadInst *LMemI = dyn_cast<LoadInst>(J)) {
        MemI = LMemI;
        PtrValue = LMemI->getPointerOperand();
      } else if (StoreInst *SMemI = dyn_cast<StoreInst>(J)) {
        if (!PrefetchWrites) continue;
        MemI = SMemI;
        PtrValue = SMemI->getPointerOperand();
      } else continue;

      unsigned PtrAddrSpace = PtrValue->getType()->getPointerAddressSpace();
      if (PtrAddrSpace)
        continue;

      if (L->isLoopInvariant(PtrValue))
        continue;

      const SCEV *LSCEV = SE->getSCEV(PtrValue);
      const SCEVAddRecExpr *LSCEVAddRec = dyn_cast<SCEVAddRecExpr>(LSCEV);
      if (!LSCEVAddRec)
        continue;

      // Check if the the stride of the accesses is large enough to warrant a
      // prefetch.
      if (!isStrideLargeEnough(LSCEVAddRec))
        continue;

      // We don't want to double prefetch individual cache lines. If this load
      // is known to be within one cache line of some other load that has
      // already been prefetched, then don't prefetch this one as well.
      bool DupPref = false;
      for (const auto &PrefLoad : PrefLoads) {
        const SCEV *PtrDiff = SE->getMinusSCEV(LSCEVAddRec, PrefLoad.second);
        if (const SCEVConstant *ConstPtrDiff =
            dyn_cast<SCEVConstant>(PtrDiff)) {
          int64_t PD = std::abs(ConstPtrDiff->getValue()->getSExtValue());
          if (PD < (int64_t) TTI->getCacheLineSize()) {
            DupPref = true;
            break;
          }
        }
      }
      if (DupPref)
        continue;

      const SCEV *NextLSCEV = SE->getAddExpr(LSCEVAddRec, SE->getMulExpr(
        SE->getConstant(LSCEVAddRec->getType(), ItersAhead),
        LSCEVAddRec->getStepRecurrence(*SE)));
      if (!isSafeToExpand(NextLSCEV, *SE))
        continue;

      PrefLoads.push_back(std::make_pair(MemI, LSCEVAddRec));

      Type *I8Ptr = Type::getInt8PtrTy((*I)->getContext(), PtrAddrSpace);
      SCEVExpander SCEVE(*SE, J->getModule()->getDataLayout(), "prefaddr");
      Value *PrefPtrValue = SCEVE.expandCodeFor(NextLSCEV, I8Ptr, MemI);

      IRBuilder<> Builder(MemI);
      Module *M = (*I)->getParent()->getParent();
      Type *I32 = Type::getInt32Ty((*I)->getContext());
      Value *PrefetchFunc = Intrinsic::getDeclaration(M, Intrinsic::prefetch);
      Builder.CreateCall(
          PrefetchFunc,
          {PrefPtrValue,
           ConstantInt::get(I32, MemI->mayReadFromMemory() ? 0 : 1),
           ConstantInt::get(I32, 3), ConstantInt::get(I32, 1)});
      ++NumPrefetches;
      DEBUG(dbgs() << "  Access: " << *PtrValue << ", SCEV: " << *LSCEV
                   << "\n");
      ORE->emitOptimizationRemark(DEBUG_TYPE, MemI, "prefetched memory access");

      MadeChange = true;
    }
  }

  return MadeChange;
}

<commit_msg>[LoopDataPrefetch] Use range based for loop; NFCI<commit_after>//===-------- LoopDataPrefetch.cpp - Loop Data Prefetching Pass -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Loop Data Prefetching Pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"

#define DEBUG_TYPE "loop-data-prefetch"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationDiagnosticInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
using namespace llvm;

// By default, we limit this to creating 16 PHIs (which is a little over half
// of the allocatable register set).
static cl::opt<bool>
PrefetchWrites("loop-prefetch-writes", cl::Hidden, cl::init(false),
               cl::desc("Prefetch write addresses"));

static cl::opt<unsigned>
    PrefetchDistance("prefetch-distance",
                     cl::desc("Number of instructions to prefetch ahead"),
                     cl::Hidden);

static cl::opt<unsigned>
    MinPrefetchStride("min-prefetch-stride",
                      cl::desc("Min stride to add prefetches"), cl::Hidden);

static cl::opt<unsigned> MaxPrefetchIterationsAhead(
    "max-prefetch-iters-ahead",
    cl::desc("Max number of iterations to prefetch ahead"), cl::Hidden);

STATISTIC(NumPrefetches, "Number of prefetches inserted");

namespace {

/// Loop prefetch implementation class.
class LoopDataPrefetch {
public:
  LoopDataPrefetch(AssumptionCache *AC, LoopInfo *LI, ScalarEvolution *SE,
                   const TargetTransformInfo *TTI,
                   OptimizationRemarkEmitter *ORE)
      : AC(AC), LI(LI), SE(SE), TTI(TTI), ORE(ORE) {}

  bool run();

private:
  bool runOnLoop(Loop *L);

  /// \brief Check if the the stride of the accesses is large enough to
  /// warrant a prefetch.
  bool isStrideLargeEnough(const SCEVAddRecExpr *AR);

  unsigned getMinPrefetchStride() {
    if (MinPrefetchStride.getNumOccurrences() > 0)
      return MinPrefetchStride;
    return TTI->getMinPrefetchStride();
  }

  unsigned getPrefetchDistance() {
    if (PrefetchDistance.getNumOccurrences() > 0)
      return PrefetchDistance;
    return TTI->getPrefetchDistance();
  }

  unsigned getMaxPrefetchIterationsAhead() {
    if (MaxPrefetchIterationsAhead.getNumOccurrences() > 0)
      return MaxPrefetchIterationsAhead;
    return TTI->getMaxPrefetchIterationsAhead();
  }

  AssumptionCache *AC;
  LoopInfo *LI;
  ScalarEvolution *SE;
  const TargetTransformInfo *TTI;
  OptimizationRemarkEmitter *ORE;
};

/// Legacy class for inserting loop data prefetches.
class LoopDataPrefetchLegacyPass : public FunctionPass {
public:
  static char ID; // Pass ID, replacement for typeid
  LoopDataPrefetchLegacyPass() : FunctionPass(ID) {
    initializeLoopDataPrefetchLegacyPassPass(*PassRegistry::getPassRegistry());
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequired<AssumptionCacheTracker>();
    AU.addPreserved<DominatorTreeWrapperPass>();
    AU.addRequired<LoopInfoWrapperPass>();
    AU.addPreserved<LoopInfoWrapperPass>();
    AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
    AU.addRequired<ScalarEvolutionWrapperPass>();
    // FIXME: For some reason, preserving SE here breaks LSR (even if
    // this pass changes nothing).
    // AU.addPreserved<ScalarEvolutionWrapperPass>();
    AU.addRequired<TargetTransformInfoWrapperPass>();
  }

  bool runOnFunction(Function &F) override;
  };
}

char LoopDataPrefetchLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(LoopDataPrefetchLegacyPass, "loop-data-prefetch",
                      "Loop Data Prefetch", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(LoopDataPrefetchLegacyPass, "loop-data-prefetch",
                    "Loop Data Prefetch", false, false)

FunctionPass *llvm::createLoopDataPrefetchPass() {
  return new LoopDataPrefetchLegacyPass();
}

bool LoopDataPrefetch::isStrideLargeEnough(const SCEVAddRecExpr *AR) {
  unsigned TargetMinStride = getMinPrefetchStride();
  // No need to check if any stride goes.
  if (TargetMinStride <= 1)
    return true;

  const auto *ConstStride = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*SE));
  // If MinStride is set, don't prefetch unless we can ensure that stride is
  // larger.
  if (!ConstStride)
    return false;

  unsigned AbsStride = std::abs(ConstStride->getAPInt().getSExtValue());
  return TargetMinStride <= AbsStride;
}

PreservedAnalyses LoopDataPrefetchPass::run(Function &F,
                                            FunctionAnalysisManager &AM) {
  LoopInfo *LI = &AM.getResult<LoopAnalysis>(F);
  ScalarEvolution *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
  AssumptionCache *AC = &AM.getResult<AssumptionAnalysis>(F);
  OptimizationRemarkEmitter *ORE =
      &AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
  const TargetTransformInfo *TTI = &AM.getResult<TargetIRAnalysis>(F);

  LoopDataPrefetch LDP(AC, LI, SE, TTI, ORE);
  bool Changed = LDP.run();

  if (Changed) {
    PreservedAnalyses PA;
    PA.preserve<DominatorTreeAnalysis>();
    PA.preserve<LoopAnalysis>();
    return PA;
  }

  return PreservedAnalyses::all();
}

bool LoopDataPrefetchLegacyPass::runOnFunction(Function &F) {
  if (skipFunction(F))
    return false;

  LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
  ScalarEvolution *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
  AssumptionCache *AC =
      &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  OptimizationRemarkEmitter *ORE =
      &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
  const TargetTransformInfo *TTI =
      &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);

  LoopDataPrefetch LDP(AC, LI, SE, TTI, ORE);
  return LDP.run();
}

bool LoopDataPrefetch::run() {
  // If PrefetchDistance is not set, don't run the pass.  This gives an
  // opportunity for targets to run this pass for selected subtargets only
  // (whose TTI sets PrefetchDistance).
  if (getPrefetchDistance() == 0)
    return false;
  assert(TTI->getCacheLineSize() && "Cache line size is not set for target");

  bool MadeChange = false;

  for (Loop *I : *LI)
    for (auto L = df_begin(I), LE = df_end(I); L != LE; ++L)
      MadeChange |= runOnLoop(*L);

  return MadeChange;
}

bool LoopDataPrefetch::runOnLoop(Loop *L) {
  bool MadeChange = false;

  // Only prefetch in the inner-most loop
  if (!L->empty())
    return MadeChange;

  SmallPtrSet<const Value *, 32> EphValues;
  CodeMetrics::collectEphemeralValues(L, AC, EphValues);

  // Calculate the number of iterations ahead to prefetch
  CodeMetrics Metrics;
  for (const auto BB : L->blocks()) {
    // If the loop already has prefetches, then assume that the user knows
    // what they are doing and don't add any more.
    for (auto &I : *BB)
      if (CallInst *CI = dyn_cast<CallInst>(&I))
        if (Function *F = CI->getCalledFunction())
          if (F->getIntrinsicID() == Intrinsic::prefetch)
            return MadeChange;

    Metrics.analyzeBasicBlock(BB, *TTI, EphValues);
  }
  unsigned LoopSize = Metrics.NumInsts;
  if (!LoopSize)
    LoopSize = 1;

  unsigned ItersAhead = getPrefetchDistance() / LoopSize;
  if (!ItersAhead)
    ItersAhead = 1;

  if (ItersAhead > getMaxPrefetchIterationsAhead())
    return MadeChange;

  DEBUG(dbgs() << "Prefetching " << ItersAhead
               << " iterations ahead (loop size: " << LoopSize << ") in "
               << L->getHeader()->getParent()->getName() << ": " << *L);

  SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>, 16> PrefLoads;
  for (const auto BB : L->blocks()) {
    for (auto &I : *BB) {
      Value *PtrValue;
      Instruction *MemI;

      if (LoadInst *LMemI = dyn_cast<LoadInst>(&I)) {
        MemI = LMemI;
        PtrValue = LMemI->getPointerOperand();
      } else if (StoreInst *SMemI = dyn_cast<StoreInst>(&I)) {
        if (!PrefetchWrites) continue;
        MemI = SMemI;
        PtrValue = SMemI->getPointerOperand();
      } else continue;

      unsigned PtrAddrSpace = PtrValue->getType()->getPointerAddressSpace();
      if (PtrAddrSpace)
        continue;

      if (L->isLoopInvariant(PtrValue))
        continue;

      const SCEV *LSCEV = SE->getSCEV(PtrValue);
      const SCEVAddRecExpr *LSCEVAddRec = dyn_cast<SCEVAddRecExpr>(LSCEV);
      if (!LSCEVAddRec)
        continue;

      // Check if the the stride of the accesses is large enough to warrant a
      // prefetch.
      if (!isStrideLargeEnough(LSCEVAddRec))
        continue;

      // We don't want to double prefetch individual cache lines. If this load
      // is known to be within one cache line of some other load that has
      // already been prefetched, then don't prefetch this one as well.
      bool DupPref = false;
      for (const auto &PrefLoad : PrefLoads) {
        const SCEV *PtrDiff = SE->getMinusSCEV(LSCEVAddRec, PrefLoad.second);
        if (const SCEVConstant *ConstPtrDiff =
            dyn_cast<SCEVConstant>(PtrDiff)) {
          int64_t PD = std::abs(ConstPtrDiff->getValue()->getSExtValue());
          if (PD < (int64_t) TTI->getCacheLineSize()) {
            DupPref = true;
            break;
          }
        }
      }
      if (DupPref)
        continue;

      const SCEV *NextLSCEV = SE->getAddExpr(LSCEVAddRec, SE->getMulExpr(
        SE->getConstant(LSCEVAddRec->getType(), ItersAhead),
        LSCEVAddRec->getStepRecurrence(*SE)));
      if (!isSafeToExpand(NextLSCEV, *SE))
        continue;

      PrefLoads.push_back(std::make_pair(MemI, LSCEVAddRec));

      Type *I8Ptr = Type::getInt8PtrTy(BB->getContext(), PtrAddrSpace);
      SCEVExpander SCEVE(*SE, I.getModule()->getDataLayout(), "prefaddr");
      Value *PrefPtrValue = SCEVE.expandCodeFor(NextLSCEV, I8Ptr, MemI);

      IRBuilder<> Builder(MemI);
      Module *M = BB->getParent()->getParent();
      Type *I32 = Type::getInt32Ty(BB->getContext());
      Value *PrefetchFunc = Intrinsic::getDeclaration(M, Intrinsic::prefetch);
      Builder.CreateCall(
          PrefetchFunc,
          {PrefPtrValue,
           ConstantInt::get(I32, MemI->mayReadFromMemory() ? 0 : 1),
           ConstantInt::get(I32, 3), ConstantInt::get(I32, 1)});
      ++NumPrefetches;
      DEBUG(dbgs() << "  Access: " << *PtrValue << ", SCEV: " << *LSCEV
                   << "\n");
      ORE->emitOptimizationRemark(DEBUG_TYPE, MemI, "prefetched memory access");

      MadeChange = true;
    }
  }

  return MadeChange;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, Willow Garage, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "rp.h"
#include <boost/program_options.hpp>
#include <iostream>
#include <stdlib.h>

namespace po = boost::program_options;

const char* usage()
{
  return "USAGE: rospack <command> [options] [package]\n"
          "  Allowed commands:\n"
          "    help\n"
          "    find [package]\n"
          "    list\n"
          "    list-names\n"
          "    list-duplicates\n"
          "    langs\n"
          "    depends [package] (alias: deps)\n"
          "    depends-manifests [package] (alias: deps-manifests)\n"
          "    depends-msgsrv [package] (alias: deps-msgsrv)\n"
          "    depends1 [package] (alias: deps1)\n"
          "    depends-indent [package] (alias: deps-indent)\n"
          "    depends-why --target=<target> [package] (alias: deps-why)\n"
          "    rosdep [package] (alias: rosdeps)\n"
          "    rosdep0 [package] (alias: rosdeps0)\n"
          "    vcs [package]\n"
          "    vcs0 [package]\n"
          "    depends-on [package]\n"
          "    depends-on1 [package]\n"
          "    export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
          "    plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
          "    cflags-only-I [--deps-only] [package]\n"
          "    cflags-only-other [--deps-only] [package]\n"
          "    libs-only-L [--deps-only] [package]\n"
          "    libs-only-l [--deps-only] [package]\n"
          "    libs-only-other [--deps-only] [package]\n"
          "    profile [--length=<length>] [--zombie-only]\n"
          "  Extra options:\n"
          "    -q     Quiets error reports.\n\n"
          " If [package] is omitted, the current working directory\n"
          " is used (if it contains a manifest.xml).\n\n";
}

int
parse_args(int argc, char** argv, po::variables_map& vm)
{
  po::options_description desc("Allowed options");
  desc.add_options()
          ("command", po::value<std::string>(), "command")
          ("package", po::value<std::string>(), "package")
          ("target", po::value<std::string>(), "target")
          ("deps-only", "deps-only")
          ("lang", po::value<std::string>(), "lang")
          ("attrib", po::value<std::string>(), "attrib")
          ("top", po::value<std::string>(), "top")
          ("length", po::value<std::string>(), "length")
          ("zombie-only", "zombie-only");

  po::positional_options_description pd;
  pd.add("command", 1).add("package", 1);
  try
  {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm);
  }
  catch(boost::program_options::error e)
  {
    rospack::log_error("rospack", std::string("failed to parse command-line options: ") + e.what());
    // TODO: print USAGE
    return 1;
  }
  po::notify(vm);

  return 0;
}

int
main(int argc, char** argv)
{
  po::variables_map vm;
  int ret;

  ret = parse_args(argc, argv, vm);
  if(ret)
    return ret;

  rospack::Rospack rp;
  std::vector<std::string> search_path;
  rospack::get_search_path_from_env(search_path);
  rp.crawl(search_path, false);

  std::string command;
  std::string package;
  if(vm.count("command"))
    command = vm["command"].as<std::string>();
  if(vm.count("package"))
    package = vm["package"].as<std::string>();
  else
  {
    // TODO: try to determine package from directory context
  }

  if(!command.size())
  {
    rospack::log_error("rospack", "no command given");
    return 1;
  }

  if(command == "find")
  {
    if(!package.size())
    {
      rospack::log_error("rospack", "no package given for find command");
      return 1;
    }
    std::string path;
    if(!rp.find(package, path))
      return 1;
    else
    {
      printf("%s\n", path.c_str());
      return 0;
    }
  }
  else if(command == "list")
  {
    std::vector<std::pair<std::string, std::string> > list;
    rp.list(list);
    for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
        it != list.end();
        ++it)
    {
      printf("%s %s\n", it->first.c_str(), it->second.c_str());
    }
  }
  else if(command == "list-names")
  {
    std::vector<std::pair<std::string, std::string> > list;
    rp.list(list);
    for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
        it != list.end();
        ++it)
    {
      printf("%s\n", it->first.c_str());
    }
  }
  else if(command == "list-duplicates")
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }
  else if(command == "langs")
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }
  else if(command == "depends" || command == "deps" ||
          command == "depends1" || command == "deps1")
  {
    std::vector<std::string> deps;
    if(!rp.deps(package, (command == "depends1" || command == "deps1"), deps))
      return 1;
    else
    {
      for(std::vector<std::string>::const_iterator it = deps.begin();
          it != deps.end();
          ++it)
        printf("%s\n", it->c_str());
      return 0;
    }
  }
  else if(command == "help")
  {
    printf("%s", usage());
    return 0;
  }
  else
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }

  return 0;
}
<commit_msg>added missing header<commit_after>/*
 * Copyright (C) 2008, Willow Garage, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "rp.h"
#include <boost/program_options.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>

namespace po = boost::program_options;

const char* usage()
{
  return "USAGE: rospack <command> [options] [package]\n"
          "  Allowed commands:\n"
          "    help\n"
          "    find [package]\n"
          "    list\n"
          "    list-names\n"
          "    list-duplicates\n"
          "    langs\n"
          "    depends [package] (alias: deps)\n"
          "    depends-manifests [package] (alias: deps-manifests)\n"
          "    depends-msgsrv [package] (alias: deps-msgsrv)\n"
          "    depends1 [package] (alias: deps1)\n"
          "    depends-indent [package] (alias: deps-indent)\n"
          "    depends-why --target=<target> [package] (alias: deps-why)\n"
          "    rosdep [package] (alias: rosdeps)\n"
          "    rosdep0 [package] (alias: rosdeps0)\n"
          "    vcs [package]\n"
          "    vcs0 [package]\n"
          "    depends-on [package]\n"
          "    depends-on1 [package]\n"
          "    export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
          "    plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
          "    cflags-only-I [--deps-only] [package]\n"
          "    cflags-only-other [--deps-only] [package]\n"
          "    libs-only-L [--deps-only] [package]\n"
          "    libs-only-l [--deps-only] [package]\n"
          "    libs-only-other [--deps-only] [package]\n"
          "    profile [--length=<length>] [--zombie-only]\n"
          "  Extra options:\n"
          "    -q     Quiets error reports.\n\n"
          " If [package] is omitted, the current working directory\n"
          " is used (if it contains a manifest.xml).\n\n";
}

int
parse_args(int argc, char** argv, po::variables_map& vm)
{
  po::options_description desc("Allowed options");
  desc.add_options()
          ("command", po::value<std::string>(), "command")
          ("package", po::value<std::string>(), "package")
          ("target", po::value<std::string>(), "target")
          ("deps-only", "deps-only")
          ("lang", po::value<std::string>(), "lang")
          ("attrib", po::value<std::string>(), "attrib")
          ("top", po::value<std::string>(), "top")
          ("length", po::value<std::string>(), "length")
          ("zombie-only", "zombie-only");

  po::positional_options_description pd;
  pd.add("command", 1).add("package", 1);
  try
  {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pd).run(), vm);
  }
  catch(boost::program_options::error e)
  {
    rospack::log_error("rospack", std::string("failed to parse command-line options: ") + e.what());
    // TODO: print USAGE
    return 1;
  }
  po::notify(vm);

  return 0;
}

int
main(int argc, char** argv)
{
  po::variables_map vm;
  int ret;

  ret = parse_args(argc, argv, vm);
  if(ret)
    return ret;

  rospack::Rospack rp;
  std::vector<std::string> search_path;
  rospack::get_search_path_from_env(search_path);
  rp.crawl(search_path, false);

  std::string command;
  std::string package;
  if(vm.count("command"))
    command = vm["command"].as<std::string>();
  if(vm.count("package"))
    package = vm["package"].as<std::string>();
  else
  {
    // TODO: try to determine package from directory context
  }

  if(!command.size())
  {
    rospack::log_error("rospack", "no command given");
    return 1;
  }

  if(command == "find")
  {
    if(!package.size())
    {
      rospack::log_error("rospack", "no package given for find command");
      return 1;
    }
    std::string path;
    if(!rp.find(package, path))
      return 1;
    else
    {
      printf("%s\n", path.c_str());
      return 0;
    }
  }
  else if(command == "list")
  {
    std::vector<std::pair<std::string, std::string> > list;
    rp.list(list);
    for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
        it != list.end();
        ++it)
    {
      printf("%s %s\n", it->first.c_str(), it->second.c_str());
    }
  }
  else if(command == "list-names")
  {
    std::vector<std::pair<std::string, std::string> > list;
    rp.list(list);
    for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
        it != list.end();
        ++it)
    {
      printf("%s\n", it->first.c_str());
    }
  }
  else if(command == "list-duplicates")
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }
  else if(command == "langs")
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }
  else if(command == "depends" || command == "deps" ||
          command == "depends1" || command == "deps1")
  {
    std::vector<std::string> deps;
    if(!rp.deps(package, (command == "depends1" || command == "deps1"), deps))
      return 1;
    else
    {
      for(std::vector<std::string>::const_iterator it = deps.begin();
          it != deps.end();
          ++it)
        printf("%s\n", it->c_str());
      return 0;
    }
  }
  else if(command == "help")
  {
    printf("%s", usage());
    return 0;
  }
  else
  {
    rospack::log_error("rospack",
                       std::string("command ") + command + " not implemented");
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "comparatorlib.hpp"
int const channels = 3;//only for convinience
double const prealocate = 0.01;

	template <class TYPE>
	IterateProcess<TYPE>::IterateProcess(cv::Mat_<TYPE> img)//should get type from img?
	{
		this.img = img;
		this.classifier = Classifier<TYPE*>::color_light_classifier;
	}

	template <class TYPE>
	std::vector<IndexTransition> IterateProcess<TYPE*>::iterate_H()
	{
		auto& img = this.img;
		auto& classifier = this.classifier;
		auto lightThreshold = this.lightThreshold;
		auto colorThreshold = this.colorThreshold;
		auto colorBalance = this.colorBalance;

		std::vector<IndexTransition> result;
		result.reserve(sizeof(IndexTransition) * img.total() * prealocate);

		for(int i = 0; i < img.rows; i++)
		{
			int rowIndex = i * img.step;
			for(int j = 0; j < img.cols - channels; j += channels)
			{
				switch (classifier(img.data + rowIndex + j, img.data + rowIndex + j + channels, lightThreshold, colorThreshold, colorBalance))
				{
					case no: continue;
					case forward: result.push_back(IndexTransition{rowIndex + j + channels, leftToRight});
					case backward: result.push_back(IndexTransition{rowIndex + j, rightToLeft});
				}
			}
		}
		return result;
	}

	template <class TYPE>
	std::vector<IndexTransition> IterateProcess<TYPE*>::iterate_V()
	{
		auto& img = this.img;
		auto& classifier = this.classifier;
		auto lightThreshold = this.lightThreshold;
		auto colorThreshold = this.colorThreshold;
		auto colorBalance = this.colorBalance;

		std::vector<IndexTransition> result;
		result.reserve(sizeof(IndexTransition) * img.total() * prealocate)

		for(int col = 0; col < img.cols - channels; col += channels)
		{
			for(int row = 0; row < img.rows - 1; row++)
			{
				switch (classifier(img.data + row * img.step + col, img.data + ((row + 1) * img.step) + col], lightThreshold, colorThreshold, colorBalance))
				{
					case no: continue;
					case forward: result.push_back(IndexTransition{((row + 1) * img.step) + col, upToDown});
					case backward: result.push_back(IndexTransition{row * img.step + col, downToUp});
				}
			}
		}
		return result;
	}

	template <class TYPE>
	std::vector<IndexTransition> IterateProcess<TYPE*>::iterate_HV()
	{
		auto& img = this.img;
		auto& classifier = this.classifier;
		auto lightThreshold = this.lightThreshold;
		auto colorThreshold = this.colorThreshold;
		auto colorBalance = this.colorBalance;

		auto detectedH = iterate_H(img, classifier, lightThreshold, colorThreshold, colorBalance);
		auto detectedV = iterate_V(img, classifier, lightThreshold, colorThreshold, colorBalance);
		detectedH.insert(detectedH.end(), detectedV.begin(), detectedV.end());
		auto detectedHV = std::move(detectedH);
		return detectedHV;
	}

	template <class TYPE>
	Transition Classifier<TYPE*>::color_light_classifier(TYPE* pix0, TYPE* pix1, double lightThreshold, double colorThreshold, cv::Point3_<double> colorBalance = cv::Point3_(1, 1, 1))
	{
		Transition result = forward;
		if(brighter(pix0, pix1))
		{
			std::swap(pix0, pix1);//pix0 is now the dimmer
			result = backward;
		}

		if(balanced_light_distance(colorBalance, pix0, pix1) > lightThreshold)//ballance applied
			if(color_distance(colorBalance, pix0, pix1) < colorThreshold)
				return result;

		return (result = no);
	}

	template <class TYPE>
	int Classifier<TYPE*>::balanced_light_distance(cv::Point3_<double> colorBalance, TYPE* pix0, TYPE* pix1)//pix0 have to < pix1
	{
		return ((pix1[0] + pix1[1] + pix1[2]) - (pix0[0] * colorBalance[0] + pix0[1] * colorBalance[1] + pix0[2] * colorBalance[2]));
	}

	template <class TYPE*>
	int Classifier<TYPE*>::balanced_color_distance(cv::Point3_<double> colorBalance, TYPE* pix0, TYPE* pix1)
	{
		return pow(pix0[0] * colorBalance[0] - pix1[0], 2) + pow(pix0[1] * colorBalance[1] - pix1[1], 2) + pow(pix0[2] * colorBalance[2] - pix1[2], 2);
	}

	template<class TYPE>
	bool Classifier<TYPE*>::brighter(TYPE* pix0, TYPE* pix1)
	{
		return ((pix0[0] + pix0[1] + pix0[2]) > (pix1[0] + pix1[1] + pix1[2]) ? (true) : (false));
	}

	template<class TYPE>
	void Classifier<TYPE*>::correct_balance(cv::Point3_<double> colorBalance, TYPE* pix)//unused
	{
		pix[0] *= colorBalance[0]; pix[1] *= colorBalance[1]; pix[2] *= colorBalance[2];
	}
<commit_msg>this pointer 	modified:   comparatorlib/lib/src/comparatorlib.cpp<commit_after>#include "comparatorlib.hpp"
int const channels = 3;//only for convinience
double const prealocate = 0.01;

	template <class TYPE>
	IterateProcess<TYPE>::IterateProcess(cv::Mat_<TYPE> img)//should get type from img?
	{
		this.img = img;
		this.classifier = Classifier<TYPE*>::color_light_classifier;
	}

	template <class TYPE> std::vector<IndexTransition> IterateProcess<TYPE>::iterate_H()
	{
		std::vector<IndexTransition> result;
		result.reserve(sizeof(IndexTransition) * img.total() * prealocate);

		for(int i = 0; i < img.rows; i++)
		{
			int rowIndex = i * this->img.step;
			for(int j = 0; j < this->img.cols - channels; j += channels)
			{
				switch (this->classifier(this->img.data + rowIndex + j, this->img.data + rowIndex + j + channels, this->lightThreshold, this->colorThreshold, this->colorBalance))
				{
					case no: continue;
					case forward: result.push_back(IndexTransition{rowIndex + j + channels, leftToRight});
					case backward: result.push_back(IndexTransition{rowIndex + j, rightToLeft});
				}
			}
		}
		return result;
	}

	template <class TYPE>
	std::vector<IndexTransition> IterateProcess<TYPE*>::iterate_V()
	{
		auto& img = this.img;
		auto& classifier = this.classifier;
		auto lightThreshold = this.lightThreshold;
		auto colorThreshold = this.colorThreshold;
		auto colorBalance = this.colorBalance;

		std::vector<IndexTransition> result;
		result.reserve(sizeof(IndexTransition) * img.total() * prealocate)

		for(int col = 0; col < img.cols - channels; col += channels)
		{
			for(int row = 0; row < img.rows - 1; row++)
			{
				switch (classifier(img.data + row * img.step + col, img.data + ((row + 1) * img.step) + col], lightThreshold, colorThreshold, colorBalance))
				{
					case no: continue;
					case forward: result.push_back(IndexTransition{((row + 1) * img.step) + col, upToDown});
					case backward: result.push_back(IndexTransition{row * img.step + col, downToUp});
				}
			}
		}
		return result;
	}

	template <class TYPE>
	std::vector<IndexTransition> IterateProcess<TYPE*>::iterate_HV()
	{
		auto& img = this.img;
		auto& classifier = this.classifier;
		auto lightThreshold = this.lightThreshold;
		auto colorThreshold = this.colorThreshold;
		auto colorBalance = this.colorBalance;

		auto detectedH = iterate_H(img, classifier, lightThreshold, colorThreshold, colorBalance);
		auto detectedV = iterate_V(img, classifier, lightThreshold, colorThreshold, colorBalance);
		detectedH.insert(detectedH.end(), detectedV.begin(), detectedV.end());
		auto detectedHV = std::move(detectedH);
		return detectedHV;
	}

	template <class TYPE>
	Transition Classifier<TYPE*>::color_light_classifier(TYPE* pix0, TYPE* pix1, double lightThreshold, double colorThreshold, cv::Point3_<double> colorBalance = cv::Point3_(1, 1, 1))
	{
		Transition result = forward;
		if(brighter(pix0, pix1))
		{
			std::swap(pix0, pix1);//pix0 is now the dimmer
			result = backward;
		}

		if(balanced_light_distance(colorBalance, pix0, pix1) > lightThreshold)//ballance applied
			if(color_distance(colorBalance, pix0, pix1) < colorThreshold)
				return result;

		return (result = no);
	}

	template <class TYPE>
	int Classifier<TYPE*>::balanced_light_distance(cv::Point3_<double> colorBalance, TYPE* pix0, TYPE* pix1)//pix0 have to < pix1
	{
		return ((pix1[0] + pix1[1] + pix1[2]) - (pix0[0] * colorBalance[0] + pix0[1] * colorBalance[1] + pix0[2] * colorBalance[2]));
	}

	template <class TYPE*>
	int Classifier<TYPE*>::balanced_color_distance(cv::Point3_<double> colorBalance, TYPE* pix0, TYPE* pix1)
	{
		return pow(pix0[0] * colorBalance[0] - pix1[0], 2) + pow(pix0[1] * colorBalance[1] - pix1[1], 2) + pow(pix0[2] * colorBalance[2] - pix1[2], 2);
	}

	template<class TYPE>
	bool Classifier<TYPE*>::brighter(TYPE* pix0, TYPE* pix1)
	{
		return ((pix0[0] + pix0[1] + pix0[2]) > (pix1[0] + pix1[1] + pix1[2]) ? (true) : (false));
	}

	template<class TYPE>
	void Classifier<TYPE*>::correct_balance(cv::Point3_<double> colorBalance, TYPE* pix)//unused
	{
		pix[0] *= colorBalance[0]; pix[1] *= colorBalance[1]; pix[2] *= colorBalance[2];
	}
<|endoftext|>