<commit_before>#include "match.hpp"
#include "utilities.hpp"
#include <stdio.h>

//using namespace cv;

Point match(const Mat &outerFrameMatrix,const Mat &innerFrameMatrix, Mat &result)
{
    int match_method = CV_TM_CCOEFF_NORMED;

    int resultCols =  outerFrameMatrix.cols - innerFrameMatrix.cols + 1;
    int resultRows = outerFrameMatrix.rows - innerFrameMatrix.rows + 1;

    result = Mat(resultCols,resultRows,CV_32FC1);

    /// Do the Matching and Normalize
    matchTemplate( outerFrameMatrix, innerFrameMatrix, result, match_method );
    normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat());

    double minVal, maxVal;
    Point minLoc, maxLoc, matchLoc;

    minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc);

    /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
    if(  match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    {
        matchLoc = minLoc;
        rectangle( result, Point( matchLoc.x - result.cols/10 , matchLoc.y - result.rows/10 ), Point( matchLoc.x + result.cols/10 , matchLoc.y + result.rows/10 ), Scalar::all(255), 1, 1, 0 );
    }
    else
    {
        matchLoc = maxLoc;
        rectangle( result, Point( matchLoc.x - result.cols/10 , matchLoc.y - result.rows/10 ), Point( matchLoc.x + result.cols/10 , matchLoc.y + result.rows/10 ), Scalar::all(0), 1, 1, 0 );
    }
    //printf("matchLoc: = (%d,%d)",matchLoc.x,matchLoc.y);

    //printf("matchLoc: = (%f,%f)",double(SearchFrameMatrix.cols - result.cols)/2.0,double(SearchFrameMatrix.rows-result.rows)/2.0);
    Point diff((outerFrameMatrix.cols - result.cols)/2 + 1 ,(outerFrameMatrix.rows-result.rows)/2 + 1);
    Point retVal(matchLoc + diff);
    return retVal;
}

float Mor(const Mat& sm, const Mat& rm, int x,int y, float rMean_new, float sMean_old, int umax_width, int vmax_height)
{

    float sum_r_uv = 0;
    float sum_s_uv = 0;
    float sum_r_uv_sq = 0;
    float sum_s_uv_sq = 0;

    for(int u = -umax_width/2; u < umax_width/2; u++)
    {
        for(int v = -vmax_height/2; v < vmax_height/2; v++)
        {
            float r_val = float(rm.at<uchar>(u,v)) - rMean_new;
            float s_val = float(sm.at<uchar>(x+u,y+v)) - sMean_old;
            sum_r_uv += r_val;
            sum_s_uv += s_val;
            sum_r_uv_sq += r_val*r_val;
            sum_s_uv_sq += s_val*s_val;
        }
    }
    return (2*sum_r_uv*sum_s_uv)/(sum_r_uv_sq+sum_s_uv_sq);
}

void drawBestMatchlocationInResult(const Point &maxLoc, Mat &outResult)
{
    cvtColor(outResult,outResult,CV_GRAY2BGR);
    DrawPoint(outResult,maxLoc,Scalar(0,0,255));
}

Point matchMOR(const Mat &outerFrameMatrix,const Mat &innerFrameMatrix, Mat &outResult)
{
    if(outerFrameMatrix.type() != CV_8UC1 || innerFrameMatrix.type() != CV_8UC1)
        {printf("input Matrices dont have the correct type");}
    Scalar_<uchar> meanOfOuterFrameMatrixScalar = mean(outerFrameMatrix);
    uchar meanOfOuterFrameMatrix = meanOfOuterFrameMatrixScalar[0];
    Scalar_<uchar> meanOfInnerFrameMatrixScalar = mean(innerFrameMatrix);
    uchar meanOfInnerFrameMatrix = meanOfInnerFrameMatrixScalar[0];

    int resultCols =  outerFrameMatrix.cols - innerFrameMatrix.cols + 1;
    int resultRows = outerFrameMatrix.rows - innerFrameMatrix.rows + 1;

    outResult = Mat(resultCols,resultRows,CV_32FC1);
    Point offset((outerFrameMatrix.cols - outResult.cols)/2 + 1 ,(outerFrameMatrix.rows-outResult.rows)/2 + 1);

    for(int y = offset.y, totalRowsToTraverse = outerFrameMatrix.rows - offset.y +1; y < totalRowsToTraverse; ++y)
    {
        for(int x = offset.x, totalColumnsToTraverse = outerFrameMatrix.cols - offset.x + 1; x < totalColumnsToTraverse; ++x)
        {
            outResult.at<float>(x-offset.x,y-offset.y) = Mor(outerFrameMatrix,innerFrameMatrix,x,y,float(meanOfOuterFrameMatrix),float(meanOfInnerFrameMatrix),innerFrameMatrix.cols,innerFrameMatrix.rows);
        }
    }
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1);

    double maxVal;
    Point maxLoc;
    minMaxLoc( outResult, NULL, &maxVal, NULL, &maxLoc);

    drawBestMatchlocationInResult(maxLoc, outResult);

    return maxLoc + offset;
}

Point matchSAD(const Mat &OuterFrameMatrix,const Mat &InnerFrameMatrix, Mat &outResult)
{
    int outerX = OuterFrameMatrix.cols;
    int outerY = OuterFrameMatrix.rows;

    int innerX = InnerFrameMatrix.cols;
    int innerY = InnerFrameMatrix.rows;

    int resultCols =  OuterFrameMatrix.cols - InnerFrameMatrix.cols + 1;
    int resultRows = OuterFrameMatrix.rows - InnerFrameMatrix.rows + 1;
    float result[resultCols * resultRows];

    float minDifference = FLT_MAX;
    Point posMinDifferenceInOuterFrame;

    outResult = Mat(resultCols, resultRows, CV_32FC1);

    for(int leftUpperY = 0; leftUpperY < outerY - innerY; leftUpperY++)
    {
        for(int leftUpperX = 0; leftUpperX < outerX - innerX; leftUpperX++)
        {

            float difference = 0;
            for(int offsetX = 0; offsetX <= innerX; offsetX++)
            {
                for(int offsetY = 0; offsetY <= innerY; offsetY++)
                {
                    Point posInOuterFrame = Point(leftUpperX + offsetX, leftUpperY + offsetY);
                    Point posInInnerFrame = Point(offsetX, offsetY);
                    difference += OuterFrameMatrix.at<uchar>(posInOuterFrame) - InnerFrameMatrix.at<uchar>(posInInnerFrame);
                }
            }
            if(difference < minDifference)
            {
                minDifference = difference;
                // get the mid-Point of the innerFrame in outerFrame-Coordinates
                posMinDifferenceInOuterFrame = Point(leftUpperX + innerX/2, leftUpperY + innerY/2);
            }
            result[leftUpperX + leftUpperY * resultCols] = difference;
            //outResult.at<float>(leftUpperX,leftUpperY) = difference;
        }
    }

    //minDifference, result hold additional information
    outResult = Mat(resultCols, resultRows, CV_32FC1, result);
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1, Mat());
    return posMinDifferenceInOuterFrame;
}

void determineValues(const Mat &Matrix, float &minValue, float &maxValue, float &meanValue)
{
    meanValue = 0;
    minValue = FLT_MAX;
    maxValue = FLT_MIN;
    for(int y = 0; y < Matrix.rows; y++)
    {
        for(int x = 0; x < Matrix.cols; x++)
        {
            Point pos = Point(x, y);
            int value = Matrix.at<uchar>(pos);
            meanValue += value;
            if( value < minValue )
                minValue = value;
            if( value > maxValue)
                maxValue = value;
        }
    }
    meanValue /= Matrix.rows * Matrix.cols;
}

Point matchKKFMF(const Mat &OuterFrameMatrix,const Mat &InnerFrameMatrix, Mat &outResult)
{
    int outerX = OuterFrameMatrix.cols;
    int outerY = OuterFrameMatrix.rows;
    float outerMinValue;
    float outerMaxValue;
    float outerMeanValue;
    determineValues(OuterFrameMatrix, outerMinValue, outerMaxValue, outerMeanValue);

    int innerX = InnerFrameMatrix.cols;
    int innerY = InnerFrameMatrix.rows;
    float innerMinValue;
    float innerMaxValue;
    float innerMeanValue;
    determineValues(InnerFrameMatrix, innerMinValue, innerMaxValue, innerMeanValue);

    int resultCols =  OuterFrameMatrix.cols - InnerFrameMatrix.cols + 1;
    int resultRows = OuterFrameMatrix.rows - InnerFrameMatrix.rows + 1;
    float result[resultCols * resultRows];

    float maxSimilarity = FLT_MIN;
    Point posMaxSimilarityInOuterFrame;

    outResult = Mat(resultCols, resultRows, CV_32FC1);

    for(int leftUpperY = 0; leftUpperY < outerY - innerY; leftUpperY++)
    {
        for(int leftUpperX = 0; leftUpperX < outerX - innerX; leftUpperX++)
        {

            float similarity = 0;
            for(int offsetX = 0; offsetX <= innerX; offsetX++)
            {
                for(int offsetY = 0; offsetY <= innerY; offsetY++)
                {
                    Point posInOuterFrame = Point(leftUpperX + offsetX, leftUpperY + offsetY);
                    Point posInInnerFrame = Point(offsetX, offsetY);
                    float outerValue = (OuterFrameMatrix.at<uchar>(posInOuterFrame) - outerMeanValue) / outerMeanValue;
                    float innerValue = (InnerFrameMatrix.at<uchar>(posInInnerFrame) - innerMeanValue) / outerMeanValue;
                    similarity += outerValue * innerValue;
                }
            }
            if(similarity > maxSimilarity)
            {
                maxSimilarity = similarity;
                // get the mid-Point of the innerFrame in outerFrame-Coordinates
                posMaxSimilarityInOuterFrame = Point(leftUpperX + innerX/2, leftUpperY + innerY/2);
            }
            result[leftUpperX + leftUpperY * resultCols] = similarity;
            //outResult.at<float>(leftUpperX,leftUpperY) = difference;
        }
    }

    //minDifference, result hold additional information
    outResult = Mat(resultCols, resultRows, CV_32FC1, result);
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1, Mat());
    return posMaxSimilarityInOuterFrame;
}
<commit_msg>added more debug printing to matchMOR() and tried to catch case where inner Frame is greater than outer Frame<commit_after>#include "match.hpp"
#include "utilities.hpp"
#include <stdio.h>

//using namespace cv;

Point match(const Mat &outerFrameMatrix,const Mat &innerFrameMatrix, Mat &result)
{
    int match_method = CV_TM_CCOEFF_NORMED;

    int resultCols =  outerFrameMatrix.cols - innerFrameMatrix.cols + 1;
    int resultRows = outerFrameMatrix.rows - innerFrameMatrix.rows + 1;

    result = Mat(resultCols,resultRows,CV_32FC1);

    /// Do the Matching and Normalize
    matchTemplate( outerFrameMatrix, innerFrameMatrix, result, match_method );
    normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat());

    double minVal, maxVal;
    Point minLoc, maxLoc, matchLoc;

    minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc);

    /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
    if(  match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
    {
        matchLoc = minLoc;
        rectangle( result, Point( matchLoc.x - result.cols/10 , matchLoc.y - result.rows/10 ), Point( matchLoc.x + result.cols/10 , matchLoc.y + result.rows/10 ), Scalar::all(255), 1, 1, 0 );
    }
    else
    {
        matchLoc = maxLoc;
        rectangle( result, Point( matchLoc.x - result.cols/10 , matchLoc.y - result.rows/10 ), Point( matchLoc.x + result.cols/10 , matchLoc.y + result.rows/10 ), Scalar::all(0), 1, 1, 0 );
    }
    //printf("matchLoc: = (%d,%d)",matchLoc.x,matchLoc.y);

    //printf("matchLoc: = (%f,%f)",double(SearchFrameMatrix.cols - result.cols)/2.0,double(SearchFrameMatrix.rows-result.rows)/2.0);
    Point diff((outerFrameMatrix.cols - result.cols)/2 + 1 ,(outerFrameMatrix.rows-result.rows)/2 + 1);
    Point retVal(matchLoc + diff);
    return retVal;
}

float Mor(const Mat& sm, const Mat& rm, int x,int y, float rMean_new, float sMean_old, int umax_width, int vmax_height)
{

    float sum_r_uv = 0;
    float sum_s_uv = 0;
    float sum_r_uv_sq = 0;
    float sum_s_uv_sq = 0;

    for(int u = -umax_width/2; u < umax_width/2; u++)
    {
        for(int v = -vmax_height/2; v < vmax_height/2; v++)
        {
            float r_val = float(rm.at<uchar>(u,v)) - rMean_new;
            float s_val = float(sm.at<uchar>(x+u,y+v)) - sMean_old;
            sum_r_uv += r_val;
            sum_s_uv += s_val;
            sum_r_uv_sq += r_val*r_val;
            sum_s_uv_sq += s_val*s_val;
        }
    }
    return (2*sum_r_uv*sum_s_uv)/(sum_r_uv_sq+sum_s_uv_sq);
}

void drawBestMatchlocationInResult(const Point &maxLoc, Mat &outResult)
{
    cvtColor(outResult,outResult,CV_GRAY2BGR);
    DrawPoint(outResult,maxLoc,Scalar(0,0,255));
}

Point matchMOR(const Mat &outerFrameMatrix,const Mat &innerFrameMatrix, Mat &outResult)
{
    if(outerFrameMatrix.type() != CV_8UC1 || innerFrameMatrix.type() != CV_8UC1)
        {printf("input Matrices dont have the correct type\n");}
    if(innerFrameMatrix.cols%2 != 0 || innerFrameMatrix.rows%2 != 0 || outerFrameMatrix.cols%2 != 0 || outerFrameMatrix.rows%2 != 0)
        {printf("cols/rows are odd ic: %d, ir: %d, oc: %d or:%d\n",innerFrameMatrix.cols,innerFrameMatrix.rows,outerFrameMatrix.cols,outerFrameMatrix.rows); }
    Scalar_<uchar> meanOfOuterFrameMatrixScalar = mean(outerFrameMatrix);
    uchar meanOfOuterFrameMatrix = meanOfOuterFrameMatrixScalar[0];
    Scalar_<uchar> meanOfInnerFrameMatrixScalar = mean(innerFrameMatrix);
    uchar meanOfInnerFrameMatrix = meanOfInnerFrameMatrixScalar[0];

    int resultCols =  outerFrameMatrix.cols - innerFrameMatrix.cols + 1;
    int resultRows = outerFrameMatrix.rows - innerFrameMatrix.rows + 1;
    if(resultCols < 0 || resultRows < 0 )
    {
        printf("Inner greater than Outer\n");
        outResult = Mat(10,10,CV_32FC1);
        return Point(0,0);
    }

    outResult = Mat(resultCols,resultRows,CV_32FC1);
    Point offset((outerFrameMatrix.cols - outResult.cols)/2 + 1 ,(outerFrameMatrix.rows-outResult.rows)/2 + 1);

    for(int y = offset.y, totalRowsToTraverse = outerFrameMatrix.rows - offset.y +1; y < totalRowsToTraverse; ++y)
    {
        for(int x = offset.x, totalColumnsToTraverse = outerFrameMatrix.cols - offset.x + 1; x < totalColumnsToTraverse; ++x)
        {
            outResult.at<float>(x-offset.x,y-offset.y) = Mor(outerFrameMatrix,innerFrameMatrix,x,y,float(meanOfOuterFrameMatrix),float(meanOfInnerFrameMatrix),innerFrameMatrix.cols,innerFrameMatrix.rows);
        }
    }
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1);

    double maxVal;
    Point maxLoc;
    minMaxLoc( outResult, NULL, &maxVal, NULL, &maxLoc);

    drawBestMatchlocationInResult(maxLoc, outResult);

    return maxLoc + offset;
}

Point matchSAD(const Mat &OuterFrameMatrix,const Mat &InnerFrameMatrix, Mat &outResult)
{
    int outerX = OuterFrameMatrix.cols;
    int outerY = OuterFrameMatrix.rows;

    int innerX = InnerFrameMatrix.cols;
    int innerY = InnerFrameMatrix.rows;

    int resultCols =  OuterFrameMatrix.cols - InnerFrameMatrix.cols + 1;
    int resultRows = OuterFrameMatrix.rows - InnerFrameMatrix.rows + 1;
    float result[resultCols * resultRows];

    float minDifference = FLT_MAX;
    Point posMinDifferenceInOuterFrame;

    outResult = Mat(resultCols, resultRows, CV_32FC1);

    for(int leftUpperY = 0; leftUpperY < outerY - innerY; leftUpperY++)
    {
        for(int leftUpperX = 0; leftUpperX < outerX - innerX; leftUpperX++)
        {

            float difference = 0;
            for(int offsetX = 0; offsetX <= innerX; offsetX++)
            {
                for(int offsetY = 0; offsetY <= innerY; offsetY++)
                {
                    Point posInOuterFrame = Point(leftUpperX + offsetX, leftUpperY + offsetY);
                    Point posInInnerFrame = Point(offsetX, offsetY);
                    difference += OuterFrameMatrix.at<uchar>(posInOuterFrame) - InnerFrameMatrix.at<uchar>(posInInnerFrame);
                }
            }
            if(difference < minDifference)
            {
                minDifference = difference;
                // get the mid-Point of the innerFrame in outerFrame-Coordinates
                posMinDifferenceInOuterFrame = Point(leftUpperX + innerX/2, leftUpperY + innerY/2);
            }
            result[leftUpperX + leftUpperY * resultCols] = difference;
            //outResult.at<float>(leftUpperX,leftUpperY) = difference;
        }
    }

    //minDifference, result hold additional information
    outResult = Mat(resultCols, resultRows, CV_32FC1, result);
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1, Mat());
    return posMinDifferenceInOuterFrame;
}

void determineValues(const Mat &Matrix, float &minValue, float &maxValue, float &meanValue)
{
    meanValue = 0;
    minValue = FLT_MAX;
    maxValue = FLT_MIN;
    for(int y = 0; y < Matrix.rows; y++)
    {
        for(int x = 0; x < Matrix.cols; x++)
        {
            Point pos = Point(x, y);
            int value = Matrix.at<uchar>(pos);
            meanValue += value;
            if( value < minValue )
                minValue = value;
            if( value > maxValue)
                maxValue = value;
        }
    }
    meanValue /= Matrix.rows * Matrix.cols;
}

Point matchKKFMF(const Mat &OuterFrameMatrix,const Mat &InnerFrameMatrix, Mat &outResult)
{
    int outerX = OuterFrameMatrix.cols;
    int outerY = OuterFrameMatrix.rows;
    float outerMinValue;
    float outerMaxValue;
    float outerMeanValue;
    determineValues(OuterFrameMatrix, outerMinValue, outerMaxValue, outerMeanValue);

    int innerX = InnerFrameMatrix.cols;
    int innerY = InnerFrameMatrix.rows;
    float innerMinValue;
    float innerMaxValue;
    float innerMeanValue;
    determineValues(InnerFrameMatrix, innerMinValue, innerMaxValue, innerMeanValue);

    int resultCols =  OuterFrameMatrix.cols - InnerFrameMatrix.cols + 1;
    int resultRows = OuterFrameMatrix.rows - InnerFrameMatrix.rows + 1;
    float result[resultCols * resultRows];

    float maxSimilarity = FLT_MIN;
    Point posMaxSimilarityInOuterFrame;

    outResult = Mat(resultCols, resultRows, CV_32FC1);

    for(int leftUpperY = 0; leftUpperY < outerY - innerY; leftUpperY++)
    {
        for(int leftUpperX = 0; leftUpperX < outerX - innerX; leftUpperX++)
        {

            float similarity = 0;
            for(int offsetX = 0; offsetX <= innerX; offsetX++)
            {
                for(int offsetY = 0; offsetY <= innerY; offsetY++)
                {
                    Point posInOuterFrame = Point(leftUpperX + offsetX, leftUpperY + offsetY);
                    Point posInInnerFrame = Point(offsetX, offsetY);
                    float outerValue = (OuterFrameMatrix.at<uchar>(posInOuterFrame) - outerMeanValue) / outerMeanValue;
                    float innerValue = (InnerFrameMatrix.at<uchar>(posInInnerFrame) - innerMeanValue) / outerMeanValue;
                    similarity += outerValue * innerValue;
                }
            }
            if(similarity > maxSimilarity)
            {
                maxSimilarity = similarity;
                // get the mid-Point of the innerFrame in outerFrame-Coordinates
                posMaxSimilarityInOuterFrame = Point(leftUpperX + innerX/2, leftUpperY + innerY/2);
            }
            result[leftUpperX + leftUpperY * resultCols] = similarity;
            //outResult.at<float>(leftUpperX,leftUpperY) = difference;
        }
    }

    //minDifference, result hold additional information
    outResult = Mat(resultCols, resultRows, CV_32FC1, result);
    normalize( outResult, outResult, 0, 1, NORM_MINMAX, -1, Mat());
    return posMaxSimilarityInOuterFrame;
}
<|endoftext|>


<commit_before>/*
    cpp-match-case - Code covered by the MIT License
    Author: mutouyun (http://darkc.at)
*/

#pragma once

#include "capo/preprocessor.hpp"

#include <utility>     // std::forward
#include <regex>       // std::regex, std::regex_match
#include <string>      // std::string
#include <tuple>       // std::tuple
#include <type_traits> // std::add_pointer, std::remove_reference, ...
#include <cstddef>     // size_t

namespace match {

// To remove reference and cv qualification from a type.

template <typename T>
struct underlying : std::remove_cv<typename std::remove_reference<T>::type> {};

// The helper meta-predicate capable of distinguishing all our patterns.

template <typename T>
struct is_pattern : std::false_type {};

template <typename T>
struct pattern_checker : is_pattern<typename underlying<T>::type> {};

/*
 * Constant pattern
*/

template <typename T>
struct constant
{
    const T& t_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        return (std::forward<U>(tar) == t_);
    }
};

template <typename T>
struct is_pattern<constant<T>> : std::true_type {};

/*
 * Variable pattern
*/

template <typename T>
struct variable
{
    T& t_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        t_ = std::forward<U>(tar);
        return (t_ == std::forward<U>(tar));
    }
};

template <typename T>
struct is_pattern<variable<T>> : std::true_type {};

/*
 * Wildcard pattern
*/

struct wildcard
{
    constexpr wildcard(void) {}

    template <typename U>
    bool operator()(U&&) const
    {
        return true;
    }
};

constexpr wildcard _;

template <>
struct is_pattern<wildcard> : std::true_type{};

/*
 * Predicate pattern, for lambda-expressions or other callable objects.
*/

template <typename F>
struct predicate
{
    F judge_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        return !!(this->judge_(std::forward<U>(tar)));
    }
};

template <typename T>
struct is_pattern<predicate<T>> : std::true_type {};

struct is_functor_checker_
{
    template <typename T> static std::true_type  check(decltype(&T::operator())*);
    template <typename T> static std::false_type check(...);
};
template <typename T>
struct is_functor : decltype(is_functor_checker_::check<T>(nullptr)) {};

template <typename T, bool = std::is_function<typename std::remove_pointer<T>::type>::value ||
                                  is_functor<T>::value>
struct is_closure_;
template <typename T> struct is_closure_<T, true>  : std::true_type  {};
template <typename T> struct is_closure_<T, false> : std::false_type {};

template <typename T>
struct is_closure : is_closure_<typename underlying<T>::type> {};

template <typename T>
inline auto converter(T&& arg)
    -> typename std::enable_if<is_closure<T>::value, predicate<T&&>>::type
{
    return { std::forward<T>(arg) };
}

/*
 * Regular expression pattern
*/

struct regex
{
    std::regex r_;

    template <typename T>
    regex(T&& r)
        : r_(std::forward<T>(r))
    {}

    template <typename U>
    bool operator()(U&& tar) const
    {
        return std::regex_match(std::forward<U>(tar), r_);
    }
};

template <>
struct is_pattern<regex> : std::true_type{};

#define Regex(...) match::regex { __VA_ARGS__ }

/*
 * Type pattern
*/

template <typename T> inline const T* addr(const T* t) { return t; }
template <typename T> inline       T* addr(      T* t) { return t; }
template <typename T> inline const T* addr(const T& t) { return std::addressof(t); }
template <typename T> inline       T* addr(      T& t) { return std::addressof(t); }

template <typename T, bool = std::is_polymorphic<typename underlying<T>::type>::value>
struct type;

template <>
struct type<wildcard, false>
{
    template <typename U>
    bool operator()(U&&) const
    {
        return true;
    }
};

template <typename T>
struct type<T, false>
{
    template <typename U>
    bool operator()(const volatile U&) const
    {
        return std::is_same<typename underlying<T>::type, U>::value;
    }
};

template <typename T>
struct type<T, true>
{
    template <typename U>
    bool operator()(U&& tar) const
    {
        using p_t = typename underlying<T>::type const volatile *;
        return (dynamic_cast<p_t>(addr(tar)) != nullptr);
    }
};

template <typename T, bool Cond>
struct is_pattern<type<T, Cond>> : std::true_type{};

#define Type(...) match::type<__VA_ARGS__> {}

/*
 * Constructor pattern
*/

template <typename...>
struct model;

template <>
struct model<> {};

template <typename T1, typename... T>
struct model<T1, T...> : model<T...> { T1 m_; };

template <typename Tp, size_t N>
struct model_strip;
template <typename T1, typename... T, size_t N>
struct model_strip<model<T1, T...>, N> : model_strip<model<T...>, N - 1> {};
template <typename T1, typename... T>
struct model_strip<model<T1, T...>, 0> { using type = model<T1, T...>; };
template <typename Tp>
struct model_strip<Tp, 0>              { using type = Tp; };

template <typename Tp>
struct model_length              : std::integral_constant<size_t, 0> {};
template <typename... T>
struct model_length<model<T...>> : std::integral_constant<size_t, sizeof...(T)> {};

template <typename T, typename U>
struct model_append                 { using type = model<T, U>; };
template <typename... T, typename U>
struct model_append<model<T...>, U> { using type = model<T..., U>; };

template <typename Tp>
struct model_reverse { using type = Tp; };
template <typename T1, typename... T>
struct model_reverse<model<T1, T...>>
{
    using head = typename model_reverse<model<T...>>::type;
    using type = typename model_append<head, T1>::type;
};

template <typename... T>
struct layout
{
    using model_t = typename model_reverse<model<T...>>::type;

    template <typename U, typename V>
    struct rep;
    template <typename U, typename V>
    struct rep<U&, V>        { using type = V&; };
    template <typename U, typename V>
    struct rep<U&&, V>       { using type = V&&; };
    template <typename U, typename V>
    struct rep<const U&, V>  { using type = const V&; };
    template <typename U, typename V>
    struct rep<const U&&, V> { using type = const V&&; };

    template <size_t N, typename U>
    static auto & get(U&& tar)
    {
        decltype(auto) mm = reinterpret_cast<typename rep<U&&, model_t>::type>(tar);
        return static_cast<typename model_strip<model_t, model_length<model_t>::value - N - 1>::type &>(mm).m_;
    }
};

template <class Bind>
struct bindings_base
{
    template <size_t N, typename T, typename U>
    static auto apply(const T&, U&&)
        -> typename std::enable_if<(std::tuple_size<T>::value <= N), bool>::type
    {
        return true;
    }

    template <size_t N, typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<(std::tuple_size<T>::value > N), bool>::type
    {
        using layout_t = typename Bind::layout_t;
        if ( std::get<N>(tp)(layout_t::template get<N>(tar)) )
        {
            return apply<N + 1>(tp, std::forward<U>(tar));
        }
        return false;
    }

    template <typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<std::is_pointer<typename underlying<U>::type>::value, bool>::type
    {
        return apply<0>(tp, *std::forward<U>(tar));
    }

    template <typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<!std::is_pointer<typename underlying<U>::type>::value, bool>::type
    {
        return apply<0>(tp, std::forward<U>(tar));
    }
};

template <class C>
struct bindings;

template <typename C, typename... T>
struct constructor : type<C>
{
    std::tuple<T...> tp_;

    template <typename... U>
    constructor(U&&... args)
        : tp_(std::forward<U>(args)...)
    {}

    template <typename U>
    bool operator()(U&& tar) const
    {
        if ( type<C>::operator()(std::forward<U>(tar)) )
        {
            return bindings<typename underlying<U>::type>::apply(tp_, std::forward<U>(tar));
        }
        return false;
    }
};

template <typename C, typename... T>
struct is_pattern<constructor<C, T...>> : std::true_type{};

#define MATCH_REGIST_TYPE(TYPE, ...)                                      \
    namespace match                                                       \
    {                                                                     \
        template <> struct bindings<TYPE> : bindings_base<bindings<TYPE>> \
        {                                                                 \
            using layout_t = layout<__VA_ARGS__>;                         \
        };                                                                \
        template <> struct bindings<TYPE*> : bindings<TYPE> {};           \
    }

/*
 * Sequence pattern
*/

template <typename... T>
struct sequence
{
    std::tuple<T...> tp_;

    template <typename... U>
    sequence(U&&... args)
        : tp_(std::forward<U>(args)...)
    {}

    template <size_t N, typename U, typename It>
    auto apply(U&&, It&&) const
        -> typename std::enable_if<(sizeof...(T) <= N), bool>::type
    {
        return true;
    }

    template <size_t N, typename U, typename It>
    auto apply(U&& tar, It&& it) const
        -> typename std::enable_if<(sizeof...(T) > N), bool>::type
    {
        if ( it == tar.end() )       return false;
        if ( std::get<N>(tp_)(*it) ) return apply<N + 1>(std::forward<U>(tar), ++it);
        return false;
    }

    template <typename U>
    bool operator()(U&& tar) const
    {
        return apply<0>(std::forward<U>(tar), tar.begin());
    }
};

template <typename... T>
struct is_pattern<sequence<T...>> : std::true_type{};

/*
 * "filter" is a common function used to provide convenience to the users by converting
 * constant values into constant patterns and regular variables into variable patterns.
 * If the users defined a suitable converter for a specific type, the filter would choose
 * the custom converter for wrapping that variable of the type.
*/

void converter(...);

template <typename T>
inline auto filter(T&& arg)
    -> typename std::enable_if<pattern_checker<T>::value, T&&>::type
{
    return std::forward<T>(arg);
}

template <typename T>
inline auto filter(const T& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                                std::is_same<decltype(converter(arg)), void>::value,
                                constant<T>>::type
{
    return { arg };
}

template <typename T>
inline auto filter(T& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                                std::is_same<decltype(converter(arg)), void>::value,
                                variable<T>>::type
{
    return { arg };
}

template <typename T>
inline auto filter(T&& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                               !std::is_same<decltype(converter(std::forward<T>(arg))), void>::value,
                                             decltype(converter(std::forward<T>(arg)))>::type
{
    return converter(std::forward<T>(arg));
}

/*
 * Here is a part of the constructor & sequence pattern.
 * I have to implement it here, because gcc needs the filter be declared before it.
*/

template <typename T = wildcard, typename... P>
inline auto C(P&&... args)
    -> constructor<T, decltype(filter(std::forward<P>(args)))...>
{
    return { filter(std::forward<P>(args))... };
}

template <typename... P>
inline auto S(P&&... args)
    -> sequence<decltype(filter(std::forward<P>(args)))...>
{
    return { filter(std::forward<P>(args))... };
}

} // namespace match

#define Match(...)                                         \
    {                                                      \
        auto target_ = std::forward_as_tuple(__VA_ARGS__); \
        if (false)

#define MATCH_CASE_ARG_(N, ...) && ( match::filter( CAPO_PP_A_(N, __VA_ARGS__) )( std::get<N - 1>(target_) ) )
#define P(...)                  ( true CAPO_PP_REPEAT_(CAPO_PP_COUNT_(__VA_ARGS__), MATCH_CASE_ARG_, __VA_ARGS__) )

#define With(...) \
        } else if (__VA_ARGS__) {

#define Case(...) With( P(__VA_ARGS__) )

#define Otherwise() \
        } else {

#define EndMatch \
    }
<commit_msg>Update match.hpp<commit_after>/*
    cpp-pattern-matching - Code covered by the MIT License
    Author: mutouyun (http://darkc.at)
*/

#pragma once

#include "capo/preprocessor.hpp"

#include <utility>     // std::forward
#include <regex>       // std::regex, std::regex_match
#include <string>      // std::string
#include <tuple>       // std::tuple
#include <type_traits> // std::add_pointer, std::remove_reference, ...
#include <cstddef>     // size_t

namespace match {

// To remove reference and cv qualification from a type.

template <typename T>
struct underlying : std::remove_cv<typename std::remove_reference<T>::type> {};

// The helper meta-predicate capable of distinguishing all our patterns.

template <typename T>
struct is_pattern : std::false_type {};

template <typename T>
struct pattern_checker : is_pattern<typename underlying<T>::type> {};

/*
 * Constant pattern
*/

template <typename T>
struct constant
{
    const T& t_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        return (std::forward<U>(tar) == t_);
    }
};

template <typename T>
struct is_pattern<constant<T>> : std::true_type {};

/*
 * Variable pattern
*/

template <typename T>
struct variable
{
    T& t_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        t_ = std::forward<U>(tar);
        return (t_ == std::forward<U>(tar));
    }
};

template <typename T>
struct is_pattern<variable<T>> : std::true_type {};

/*
 * Wildcard pattern
*/

struct wildcard
{
    constexpr wildcard(void) {}

    template <typename U>
    bool operator()(U&&) const
    {
        return true;
    }
};

constexpr wildcard _;

template <>
struct is_pattern<wildcard> : std::true_type{};

/*
 * Predicate pattern, for lambda-expressions or other callable objects.
*/

template <typename F>
struct predicate
{
    F judge_;

    template <typename U>
    bool operator()(U&& tar) const
    {
        return !!(this->judge_(std::forward<U>(tar)));
    }
};

template <typename T>
struct is_pattern<predicate<T>> : std::true_type {};

struct is_functor_checker_
{
    template <typename T> static std::true_type  check(decltype(&T::operator())*);
    template <typename T> static std::false_type check(...);
};
template <typename T>
struct is_functor : decltype(is_functor_checker_::check<T>(nullptr)) {};

template <typename T, bool = std::is_function<typename std::remove_pointer<T>::type>::value ||
                                  is_functor<T>::value>
struct is_closure_;
template <typename T> struct is_closure_<T, true>  : std::true_type  {};
template <typename T> struct is_closure_<T, false> : std::false_type {};

template <typename T>
struct is_closure : is_closure_<typename underlying<T>::type> {};

template <typename T>
inline auto converter(T&& arg)
    -> typename std::enable_if<is_closure<T>::value, predicate<T&&>>::type
{
    return { std::forward<T>(arg) };
}

/*
 * Regular expression pattern
*/

struct regex
{
    std::regex r_;

    template <typename T>
    regex(T&& r)
        : r_(std::forward<T>(r))
    {}

    template <typename U>
    bool operator()(U&& tar) const
    {
        return std::regex_match(std::forward<U>(tar), r_);
    }
};

template <>
struct is_pattern<regex> : std::true_type{};

#define Regex(...) match::regex { __VA_ARGS__ }

/*
 * Type pattern
*/

template <typename T> inline const T* addr(const T* t) { return t; }
template <typename T> inline       T* addr(      T* t) { return t; }
template <typename T> inline const T* addr(const T& t) { return std::addressof(t); }
template <typename T> inline       T* addr(      T& t) { return std::addressof(t); }

template <typename T, bool = std::is_polymorphic<typename underlying<T>::type>::value>
struct type;

template <>
struct type<wildcard, false>
{
    template <typename U>
    bool operator()(U&&) const
    {
        return true;
    }
};

template <typename T>
struct type<T, false>
{
    template <typename U>
    bool operator()(const volatile U&) const
    {
        return std::is_same<typename underlying<T>::type, U>::value;
    }
};

template <typename T>
struct type<T, true>
{
    template <typename U>
    bool operator()(U&& tar) const
    {
        using p_t = typename underlying<T>::type const volatile *;
        return (dynamic_cast<p_t>(addr(tar)) != nullptr);
    }
};

template <typename T, bool Cond>
struct is_pattern<type<T, Cond>> : std::true_type{};

#define Type(...) match::type<__VA_ARGS__> {}

/*
 * Constructor pattern
*/

template <typename...>
struct model;

template <>
struct model<> {};

template <typename T1, typename... T>
struct model<T1, T...> : model<T...> { T1 m_; };

template <typename Tp, size_t N>
struct model_strip;
template <typename T1, typename... T, size_t N>
struct model_strip<model<T1, T...>, N> : model_strip<model<T...>, N - 1> {};
template <typename T1, typename... T>
struct model_strip<model<T1, T...>, 0> { using type = model<T1, T...>; };
template <typename Tp>
struct model_strip<Tp, 0>              { using type = Tp; };

template <typename Tp>
struct model_length              : std::integral_constant<size_t, 0> {};
template <typename... T>
struct model_length<model<T...>> : std::integral_constant<size_t, sizeof...(T)> {};

template <typename T, typename U>
struct model_append                 { using type = model<T, U>; };
template <typename... T, typename U>
struct model_append<model<T...>, U> { using type = model<T..., U>; };

template <typename Tp>
struct model_reverse { using type = Tp; };
template <typename T1, typename... T>
struct model_reverse<model<T1, T...>>
{
    using head = typename model_reverse<model<T...>>::type;
    using type = typename model_append<head, T1>::type;
};

template <typename... T>
struct layout
{
    using model_t = typename model_reverse<model<T...>>::type;

    template <typename U, typename V>
    struct rep;
    template <typename U, typename V>
    struct rep<U&, V>        { using type = V&; };
    template <typename U, typename V>
    struct rep<U&&, V>       { using type = V&&; };
    template <typename U, typename V>
    struct rep<const U&, V>  { using type = const V&; };
    template <typename U, typename V>
    struct rep<const U&&, V> { using type = const V&&; };

    template <size_t N, typename U>
    static auto & get(U&& tar)
    {
        decltype(auto) mm = reinterpret_cast<typename rep<U&&, model_t>::type>(tar);
        return static_cast<typename model_strip<model_t, model_length<model_t>::value - N - 1>::type &>(mm).m_;
    }
};

template <class Bind>
struct bindings_base
{
    template <size_t N, typename T, typename U>
    static auto apply(const T&, U&&)
        -> typename std::enable_if<(std::tuple_size<T>::value <= N), bool>::type
    {
        return true;
    }

    template <size_t N, typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<(std::tuple_size<T>::value > N), bool>::type
    {
        using layout_t = typename Bind::layout_t;
        if ( std::get<N>(tp)(layout_t::template get<N>(tar)) )
        {
            return apply<N + 1>(tp, std::forward<U>(tar));
        }
        return false;
    }

    template <typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<std::is_pointer<typename underlying<U>::type>::value, bool>::type
    {
        return apply<0>(tp, *std::forward<U>(tar));
    }

    template <typename T, typename U>
    static auto apply(const T& tp, U&& tar)
        -> typename std::enable_if<!std::is_pointer<typename underlying<U>::type>::value, bool>::type
    {
        return apply<0>(tp, std::forward<U>(tar));
    }
};

template <class C>
struct bindings;

template <typename C, typename... T>
struct constructor : type<C>
{
    std::tuple<T...> tp_;

    template <typename... U>
    constructor(U&&... args)
        : tp_(std::forward<U>(args)...)
    {}

    template <typename U>
    bool operator()(U&& tar) const
    {
        if ( type<C>::operator()(std::forward<U>(tar)) )
        {
            return bindings<typename underlying<U>::type>::apply(tp_, std::forward<U>(tar));
        }
        return false;
    }
};

template <typename C, typename... T>
struct is_pattern<constructor<C, T...>> : std::true_type{};

#define MATCH_REGIST_TYPE(TYPE, ...)                                      \
    namespace match                                                       \
    {                                                                     \
        template <> struct bindings<TYPE> : bindings_base<bindings<TYPE>> \
        {                                                                 \
            using layout_t = layout<__VA_ARGS__>;                         \
        };                                                                \
        template <> struct bindings<TYPE*> : bindings<TYPE> {};           \
    }

/*
 * Sequence pattern
*/

template <typename... T>
struct sequence
{
    std::tuple<T...> tp_;

    template <typename... U>
    sequence(U&&... args)
        : tp_(std::forward<U>(args)...)
    {}

    template <size_t N, typename U, typename It>
    auto apply(U&&, It&&) const
        -> typename std::enable_if<(sizeof...(T) <= N), bool>::type
    {
        return true;
    }

    template <size_t N, typename U, typename It>
    auto apply(U&& tar, It&& it) const
        -> typename std::enable_if<(sizeof...(T) > N), bool>::type
    {
        if ( it == tar.end() )       return false;
        if ( std::get<N>(tp_)(*it) ) return apply<N + 1>(std::forward<U>(tar), ++it);
        return false;
    }

    template <typename U>
    bool operator()(U&& tar) const
    {
        return apply<0>(std::forward<U>(tar), tar.begin());
    }
};

template <typename... T>
struct is_pattern<sequence<T...>> : std::true_type{};

/*
 * "filter" is a common function used to provide convenience to the users by converting
 * constant values into constant patterns and regular variables into variable patterns.
 * If the users defined a suitable converter for a specific type, the filter would choose
 * the custom converter for wrapping that variable of the type.
*/

void converter(...);

template <typename T>
inline auto filter(T&& arg)
    -> typename std::enable_if<pattern_checker<T>::value, T&&>::type
{
    return std::forward<T>(arg);
}

template <typename T>
inline auto filter(const T& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                                std::is_same<decltype(converter(arg)), void>::value,
                                constant<T>>::type
{
    return { arg };
}

template <typename T>
inline auto filter(T& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                                std::is_same<decltype(converter(arg)), void>::value,
                                variable<T>>::type
{
    return { arg };
}

template <typename T>
inline auto filter(T&& arg)
    -> typename std::enable_if<!pattern_checker<T>::value &&
                               !std::is_same<decltype(converter(std::forward<T>(arg))), void>::value,
                                             decltype(converter(std::forward<T>(arg)))>::type
{
    return converter(std::forward<T>(arg));
}

/*
 * Here is a part of the constructor & sequence pattern.
 * I have to implement it here, because gcc needs the filter be declared before it.
*/

template <typename T = wildcard, typename... P>
inline auto C(P&&... args)
    -> constructor<T, decltype(filter(std::forward<P>(args)))...>
{
    return { filter(std::forward<P>(args))... };
}

template <typename... P>
inline auto S(P&&... args)
    -> sequence<decltype(filter(std::forward<P>(args)))...>
{
    return { filter(std::forward<P>(args))... };
}

} // namespace match

#define Match(...)                                         \
    {                                                      \
        auto target_ = std::forward_as_tuple(__VA_ARGS__); \
        if (false)

#define MATCH_CASE_ARG_(N, ...) && ( match::filter( CAPO_PP_A_(N, __VA_ARGS__) )( std::get<N - 1>(target_) ) )
#define P(...)                  ( true CAPO_PP_REPEAT_(CAPO_PP_COUNT_(__VA_ARGS__), MATCH_CASE_ARG_, __VA_ARGS__) )

#define With(...) \
        } else if (__VA_ARGS__) {

#define Case(...) With( P(__VA_ARGS__) )

#define Otherwise() \
        } else {

#define EndMatch \
    }
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "core/CompileConfig.h"

#if OUZEL_SUPPORTS_DIRECTSOUND

#include "AudioDeviceDS.hpp"
#include "core/Engine.hpp"
#include "core/windows/WindowWin.hpp"
#include "utils/Log.hpp"

BOOL CALLBACK enumCallback(LPGUID, LPCWSTR description, LPCWSTR, LPVOID)
{
    char temp[256];
    WideCharToMultiByte(CP_UTF8, 0, description, -1, temp, sizeof(temp), nullptr, nullptr);

    ouzel::Log(ouzel::Log::Level::INFO) << "Using " << temp << " for audio";
    return FALSE;
}

namespace ouzel
{
    namespace audio
    {
        AudioDeviceDS::AudioDeviceDS():
            AudioDevice(Audio::Driver::DIRECTSOUND), running(false)
        {
            std::fill(std::begin(notifyEvents), std::end(notifyEvents), INVALID_HANDLE_VALUE);
        }

        AudioDeviceDS::~AudioDeviceDS()
        {
            running = false;
            if (audioThread.joinable()) audioThread.join();

            for (HANDLE notifyEvent : notifyEvents)
            {
                if (notifyEvent != INVALID_HANDLE_VALUE) CloseHandle(notifyEvent);
            }

            if (notify) notify->Release();
            if (buffer) buffer->Release();
            if (primaryBuffer) primaryBuffer->Release();
            if (directSound) directSound->Release();
        }

        bool AudioDeviceDS::init(bool debugAudio)
        {
            if (!AudioDevice::init(debugAudio))
            {
                return false;
            }

            HRESULT hr = DirectSoundEnumerateW(enumCallback, this);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to enumerate DirectSound 8 devices, error: " << hr;
                return false;
            }

            hr = DirectSoundCreate8(&DSDEVID_DefaultPlayback, &directSound, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound 8 instance, error: " << hr;
                return false;
            }

            WindowWin* windowWin = static_cast<WindowWin*>(sharedEngine->getWindow());

            hr = directSound->SetCooperativeLevel(windowWin->getNativeWindow(), DSSCL_PRIORITY);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set cooperative level for DirectSound 8, error: " << hr;
                return false;
            }

            DSBUFFERDESC primaryBufferDesc;
            primaryBufferDesc.dwSize = sizeof(primaryBufferDesc);
            primaryBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
            primaryBufferDesc.dwBufferBytes = 0;
            primaryBufferDesc.dwReserved = 0;
            primaryBufferDesc.lpwfxFormat = nullptr;
            primaryBufferDesc.guid3DAlgorithm = GUID_NULL;

            hr = directSound->CreateSoundBuffer(&primaryBufferDesc, &primaryBuffer, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                return false;
            }

            WAVEFORMATEX waveFormat;
            waveFormat.wFormatTag = WAVE_FORMAT_PCM;
            waveFormat.nChannels = channels;
            waveFormat.nSamplesPerSec = sampleRate;
            waveFormat.wBitsPerSample = 16;
            waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
            waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
            waveFormat.cbSize = 0;

            hr = primaryBuffer->SetFormat(&waveFormat);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set DirectSound buffer format, error: " << hr;
                return false;
            }

            format = Audio::Format::SINT16;

            IDirectSoundBuffer* tempBuffer = nullptr;

            DSBUFFERDESC bufferDesc;
            bufferDesc.dwSize = sizeof(bufferDesc);
            bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;
            bufferDesc.dwBufferBytes = 2 * bufferSize;
            bufferDesc.dwReserved = 0;
            bufferDesc.lpwfxFormat = &waveFormat;
            bufferDesc.guid3DAlgorithm = GUID_NULL;

            hr = directSound->CreateSoundBuffer(&bufferDesc, &tempBuffer, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                return false;
            }

            hr = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, reinterpret_cast<void**>(&buffer));
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                tempBuffer->Release();
                return false;
            }

            hr = tempBuffer->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void**>(&notify));
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to get DirectSound notify interface, error: " << hr;
                tempBuffer->Release();
                return false;
            }

            tempBuffer->Release();

            uint8_t* bufferPointer;
            DWORD lockedBufferSize;
            hr = buffer->Lock(0, bufferDesc.dwBufferBytes, reinterpret_cast<void**>(&bufferPointer), &lockedBufferSize, nullptr, 0, 0);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to lock DirectSound buffer, error: " << hr;
                return false;
            }

            getData(lockedBufferSize / (channels * sizeof(int16_t)), data);
            std::copy(data.begin(), data.end(), bufferPointer);

            hr = buffer->Unlock(bufferPointer, lockedBufferSize, nullptr, 0);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to unlock DirectSound buffer, error: " << hr;
                return false;
            }

            nextBuffer = 0;

            notifyEvents[0] = CreateEvent(nullptr, true, false, nullptr);
            notifyEvents[1] = CreateEvent(nullptr, true, false, nullptr);

            DSBPOSITIONNOTIFY positionNotifyEvents[2];
            positionNotifyEvents[0].dwOffset = bufferSize - 1;
            positionNotifyEvents[0].hEventNotify = notifyEvents[0];

            positionNotifyEvents[1].dwOffset = 2 * bufferSize - 1;
            positionNotifyEvents[1].hEventNotify = notifyEvents[1];

            hr = notify->SetNotificationPositions(2, positionNotifyEvents);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set DirectSound notification positions, error: " << hr;
                return false;
            }

            hr = buffer->Play(0, 0, DSBPLAY_LOOPING);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to play DirectSound buffer, error: " << hr;
                return false;
            }

            running = true;
            audioThread = std::thread(&AudioDeviceDS::run, this);

            return true;
        }

        void AudioDeviceDS::run()
        {
            sharedEngine->setCurrentThreadName("Audio");

            while (running)
            {
                if (WaitForSingleObject(notifyEvents[nextBuffer], INFINITE) == WAIT_OBJECT_0)
                {
                    ResetEvent(notifyEvents[nextBuffer]);

                    if (!process())
                    {
                        break;
                    }

                    uint8_t* bufferPointer;
                    DWORD lockedBufferSize;
                    HRESULT hr = buffer->Lock(nextBuffer * bufferSize, bufferSize, reinterpret_cast<void**>(&bufferPointer), &lockedBufferSize, nullptr, 0, 0);
                    if (FAILED(hr))
                    {
                        Log(Log::Level::ERR) << "Failed to lock DirectSound buffer, error: " << hr;
                        break;
                    }

                    if (!getData(lockedBufferSize / (channels * sizeof(int16_t)), data))
                    {
                        break;
                    }

                    std::copy(data.begin(), data.end(), bufferPointer);

                    hr = buffer->Unlock(bufferPointer, lockedBufferSize, nullptr, 0);
                    if (FAILED(hr))
                    {
                        Log(Log::Level::ERR) << "Failed to unlock DirectSound buffer, error: " << hr;
                        break;
                    }

                    nextBuffer = (nextBuffer + 1) % 2;
                }
            }
        }
    } // namespace audio
} // namespace ouzel

#endif
<commit_msg>Signal the DirectSound events and exit the audio thread if not running anymore<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "core/CompileConfig.h"

#if OUZEL_SUPPORTS_DIRECTSOUND

#include "AudioDeviceDS.hpp"
#include "core/Engine.hpp"
#include "core/windows/WindowWin.hpp"
#include "utils/Log.hpp"

BOOL CALLBACK enumCallback(LPGUID, LPCWSTR description, LPCWSTR, LPVOID)
{
    char temp[256];
    WideCharToMultiByte(CP_UTF8, 0, description, -1, temp, sizeof(temp), nullptr, nullptr);

    ouzel::Log(ouzel::Log::Level::INFO) << "Using " << temp << " for audio";
    return FALSE;
}

namespace ouzel
{
    namespace audio
    {
        AudioDeviceDS::AudioDeviceDS():
            AudioDevice(Audio::Driver::DIRECTSOUND), running(false)
        {
            std::fill(std::begin(notifyEvents), std::end(notifyEvents), INVALID_HANDLE_VALUE);
        }

        AudioDeviceDS::~AudioDeviceDS()
        {
            running = false;
            for (HANDLE notifyEvent : notifyEvents)
            {
                SetEvent(notifyEvent);
            }
            if (audioThread.joinable()) audioThread.join();

            for (HANDLE notifyEvent : notifyEvents)
            {
                if (notifyEvent != INVALID_HANDLE_VALUE) CloseHandle(notifyEvent);
            }

            if (notify) notify->Release();
            if (buffer) buffer->Release();
            if (primaryBuffer) primaryBuffer->Release();
            if (directSound) directSound->Release();
        }

        bool AudioDeviceDS::init(bool debugAudio)
        {
            if (!AudioDevice::init(debugAudio))
            {
                return false;
            }

            HRESULT hr = DirectSoundEnumerateW(enumCallback, this);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to enumerate DirectSound 8 devices, error: " << hr;
                return false;
            }

            hr = DirectSoundCreate8(&DSDEVID_DefaultPlayback, &directSound, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound 8 instance, error: " << hr;
                return false;
            }

            WindowWin* windowWin = static_cast<WindowWin*>(sharedEngine->getWindow());

            hr = directSound->SetCooperativeLevel(windowWin->getNativeWindow(), DSSCL_PRIORITY);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set cooperative level for DirectSound 8, error: " << hr;
                return false;
            }

            DSBUFFERDESC primaryBufferDesc;
            primaryBufferDesc.dwSize = sizeof(primaryBufferDesc);
            primaryBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
            primaryBufferDesc.dwBufferBytes = 0;
            primaryBufferDesc.dwReserved = 0;
            primaryBufferDesc.lpwfxFormat = nullptr;
            primaryBufferDesc.guid3DAlgorithm = GUID_NULL;

            hr = directSound->CreateSoundBuffer(&primaryBufferDesc, &primaryBuffer, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                return false;
            }

            WAVEFORMATEX waveFormat;
            waveFormat.wFormatTag = WAVE_FORMAT_PCM;
            waveFormat.nChannels = channels;
            waveFormat.nSamplesPerSec = sampleRate;
            waveFormat.wBitsPerSample = 16;
            waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
            waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
            waveFormat.cbSize = 0;

            hr = primaryBuffer->SetFormat(&waveFormat);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set DirectSound buffer format, error: " << hr;
                return false;
            }

            format = Audio::Format::SINT16;

            IDirectSoundBuffer* tempBuffer = nullptr;

            DSBUFFERDESC bufferDesc;
            bufferDesc.dwSize = sizeof(bufferDesc);
            bufferDesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY;
            bufferDesc.dwBufferBytes = 2 * bufferSize;
            bufferDesc.dwReserved = 0;
            bufferDesc.lpwfxFormat = &waveFormat;
            bufferDesc.guid3DAlgorithm = GUID_NULL;

            hr = directSound->CreateSoundBuffer(&bufferDesc, &tempBuffer, nullptr);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                return false;
            }

            hr = tempBuffer->QueryInterface(IID_IDirectSoundBuffer8, reinterpret_cast<void**>(&buffer));
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to create DirectSound buffer, error: " << hr;
                tempBuffer->Release();
                return false;
            }

            hr = tempBuffer->QueryInterface(IID_IDirectSoundNotify, reinterpret_cast<void**>(&notify));
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to get DirectSound notify interface, error: " << hr;
                tempBuffer->Release();
                return false;
            }

            tempBuffer->Release();

            uint8_t* bufferPointer;
            DWORD lockedBufferSize;
            hr = buffer->Lock(0, bufferDesc.dwBufferBytes, reinterpret_cast<void**>(&bufferPointer), &lockedBufferSize, nullptr, 0, 0);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to lock DirectSound buffer, error: " << hr;
                return false;
            }

            getData(lockedBufferSize / (channels * sizeof(int16_t)), data);
            std::copy(data.begin(), data.end(), bufferPointer);

            hr = buffer->Unlock(bufferPointer, lockedBufferSize, nullptr, 0);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to unlock DirectSound buffer, error: " << hr;
                return false;
            }

            nextBuffer = 0;

            notifyEvents[0] = CreateEvent(nullptr, true, false, nullptr);
            notifyEvents[1] = CreateEvent(nullptr, true, false, nullptr);

            DSBPOSITIONNOTIFY positionNotifyEvents[2];
            positionNotifyEvents[0].dwOffset = bufferSize - 1;
            positionNotifyEvents[0].hEventNotify = notifyEvents[0];

            positionNotifyEvents[1].dwOffset = 2 * bufferSize - 1;
            positionNotifyEvents[1].hEventNotify = notifyEvents[1];

            hr = notify->SetNotificationPositions(2, positionNotifyEvents);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to set DirectSound notification positions, error: " << hr;
                return false;
            }

            hr = buffer->Play(0, 0, DSBPLAY_LOOPING);
            if (FAILED(hr))
            {
                Log(Log::Level::ERR) << "Failed to play DirectSound buffer, error: " << hr;
                return false;
            }

            running = true;
            audioThread = std::thread(&AudioDeviceDS::run, this);

            return true;
        }

        void AudioDeviceDS::run()
        {
            sharedEngine->setCurrentThreadName("Audio");

            for (;;)
            {
                if (WaitForSingleObject(notifyEvents[nextBuffer], INFINITE) == WAIT_OBJECT_0)
                {
                    if (!running) break;

                    ResetEvent(notifyEvents[nextBuffer]);

                    if (!process())
                    {
                        break;
                    }

                    uint8_t* bufferPointer;
                    DWORD lockedBufferSize;
                    HRESULT hr = buffer->Lock(nextBuffer * bufferSize, bufferSize, reinterpret_cast<void**>(&bufferPointer), &lockedBufferSize, nullptr, 0, 0);
                    if (FAILED(hr))
                    {
                        Log(Log::Level::ERR) << "Failed to lock DirectSound buffer, error: " << hr;
                        break;
                    }

                    if (!getData(lockedBufferSize / (channels * sizeof(int16_t)), data))
                    {
                        break;
                    }

                    std::copy(data.begin(), data.end(), bufferPointer);

                    hr = buffer->Unlock(bufferPointer, lockedBufferSize, nullptr, 0);
                    if (FAILED(hr))
                    {
                        Log(Log::Level::ERR) << "Failed to unlock DirectSound buffer, error: " << hr;
                        break;
                    }

                    nextBuffer = (nextBuffer + 1) % 2;
                }
            }
        }
    } // namespace audio
} // namespace ouzel

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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 "SelectionCriterionRule.h"
#include "SelectionCriterion.h"
#include "XmlDomainSerializingContext.h"
#include "SelectionCriteriaDefinition.h"
#include "SelectionCriterionTypeInterface.h"
#include "RuleParser.h"
#include <assert.h>

#define base CRule

using std::string;

const CSelectionCriterionRule::SMatchingRuleDescription CSelectionCriterionRule::_astMatchesWhen[CSelectionCriterionRule::ENbMatchesWhen] = {
    { "Is", true },
    { "IsNot", true },
    { "Includes", false },
    { "Excludes", false }
};

CSelectionCriterionRule::CSelectionCriterionRule() : _pSelectionCriterion(NULL), _eMatchesWhen(CSelectionCriterionRule::EIs), _iMatchValue(0)
{
}

// Class kind
string CSelectionCriterionRule::getKind() const
{
    return "SelectionCriterionRule";
}

// Content dumping
void CSelectionCriterionRule::logValue(string& strValue, CErrorContext& errorContext) const
{
    (void)errorContext;

    // Dump rule
    dump(strValue);
}

// Parse
bool CSelectionCriterionRule::parse(CRuleParser& ruleParser, string& strError)
{
    // Criterion
    _pSelectionCriterion = ruleParser.getSelectionCriteriaDefinition()->getSelectionCriterion(ruleParser.getType());

    // Check existence
    if (!_pSelectionCriterion) {

        strError = "Couldn't find selection criterion " + ruleParser.getType();

        return false;
    }

    // Verb
    string strMatchesWhen;

    if (!ruleParser.next(strMatchesWhen, strError)) {

        return false;
    }
    // Value
    string strValue;

    if (!ruleParser.next(strValue, strError)) {

        return false;
    }

    // Matches when
    if (!setMatchesWhen(strMatchesWhen, strError)) {

        strError = "Verb error: " + strError;

        return false;
    }

    // Value
    if (!_pSelectionCriterion->getCriterionType()->getNumericalValue(strValue, _iMatchValue)) {

        strError = "Value error: " + strError;

        return false;
    }

    return true;
}

// Dump
void CSelectionCriterionRule::dump(string& strResult) const
{
    // Criterion
    strResult += _pSelectionCriterion->getName();
    strResult += " ";
    // Verb
    strResult += _astMatchesWhen[_eMatchesWhen].pcMatchesWhen;
    strResult += " ";
    // Value
    string strValue;
    _pSelectionCriterion->getCriterionType()->getLiteralValue(_iMatchValue, strValue);
    strResult += strValue;
}

// Rule check
bool CSelectionCriterionRule::matches() const
{
    assert(_pSelectionCriterion);

    switch(_eMatchesWhen) {
    case EIs:
        return _pSelectionCriterion->is(_iMatchValue);
    case EIsNot:
        return _pSelectionCriterion->isNot(_iMatchValue);
    case EIncludes:
        return _pSelectionCriterion->includes(_iMatchValue);
    case EExcludes:
        return _pSelectionCriterion->excludes(_iMatchValue);
    default:
        assert(0);
        return false;
    }
}

// From IXmlSink
bool CSelectionCriterionRule::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
{
    // Retrieve actual context
    CXmlDomainSerializingContext& xmlDomainSerializingContext = static_cast<CXmlDomainSerializingContext&>(serializingContext);

    // Get selection criterion
    string strSelectionCriterion = xmlElement.getAttributeString("SelectionCriterion");

    _pSelectionCriterion = xmlDomainSerializingContext.getSelectionCriteriaDefinition()->getSelectionCriterion(strSelectionCriterion);

    // Check existence
    if (!_pSelectionCriterion) {

        xmlDomainSerializingContext.setError("Couldn't find selection criterion " + strSelectionCriterion + " in " + getKind() + " " + xmlElement.getPath());

        return false;
    }

    // Get MatchesWhen
    string strMatchesWhen = xmlElement.getAttributeString("MatchesWhen");
    string strError;

    if (!setMatchesWhen(strMatchesWhen, strError)) {

        xmlDomainSerializingContext.setError("Wrong MatchesWhen attribute " + strMatchesWhen + " in " + getKind() + " " + xmlElement.getPath() + ": " + strError);

        return false;
    }

    // Get Value
    string strValue = xmlElement.getAttributeString("Value");

    if (!_pSelectionCriterion->getCriterionType()->getNumericalValue(strValue, _iMatchValue)) {

        xmlDomainSerializingContext.setError("Wrong Value attribute value " + strValue + " in " + getKind() + " " + xmlElement.getPath());

        return false;
    }

    // Done
    return true;
}

// From IXmlSource
void CSelectionCriterionRule::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
{
    (void)serializingContext;

    assert(_pSelectionCriterion);

    // Set selection criterion
    xmlElement.setAttributeString("SelectionCriterion", _pSelectionCriterion->getName());

    // Set MatchesWhen
    xmlElement.setAttributeString("MatchesWhen", _astMatchesWhen[_eMatchesWhen].pcMatchesWhen);

    // Set Value
    string strValue;

     _pSelectionCriterion->getCriterionType()->getLiteralValue(_iMatchValue, strValue);

    xmlElement.setAttributeString("Value", strValue);
}

// XML MatchesWhen attribute parsing
bool CSelectionCriterionRule::setMatchesWhen(const string& strMatchesWhen, string& strError)
{
    uint32_t uiMatchesWhen;

    for (uiMatchesWhen = 0; uiMatchesWhen < ENbMatchesWhen; uiMatchesWhen++) {

        const SMatchingRuleDescription* pstMatchingRuleDescription = &_astMatchesWhen[uiMatchesWhen];

        if (strMatchesWhen == pstMatchingRuleDescription->pcMatchesWhen) {

            // Found it!

            // Get Type
            const ISelectionCriterionTypeInterface* pSelectionCriterionType = _pSelectionCriterion->getCriterionType();

            // Check compatibility if relevant
            if (!pSelectionCriterionType->isTypeInclusive() && !pstMatchingRuleDescription->bExclusiveTypeCompatible) {

                strError = "Value incompatible with exclusive kind of type";

                return false;
            }

            // Store
            _eMatchesWhen = (MatchesWhen)uiMatchesWhen;

            return true;
        }
    }

    strError = "Value not found";

    return false;
}
<commit_msg>Fix error message in case of unknown criterion value<commit_after>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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 "SelectionCriterionRule.h"
#include "SelectionCriterion.h"
#include "XmlDomainSerializingContext.h"
#include "SelectionCriteriaDefinition.h"
#include "SelectionCriterionTypeInterface.h"
#include "RuleParser.h"
#include <assert.h>

#define base CRule

using std::string;

const CSelectionCriterionRule::SMatchingRuleDescription CSelectionCriterionRule::_astMatchesWhen[CSelectionCriterionRule::ENbMatchesWhen] = {
    { "Is", true },
    { "IsNot", true },
    { "Includes", false },
    { "Excludes", false }
};

CSelectionCriterionRule::CSelectionCriterionRule() : _pSelectionCriterion(NULL), _eMatchesWhen(CSelectionCriterionRule::EIs), _iMatchValue(0)
{
}

// Class kind
string CSelectionCriterionRule::getKind() const
{
    return "SelectionCriterionRule";
}

// Content dumping
void CSelectionCriterionRule::logValue(string& strValue, CErrorContext& errorContext) const
{
    (void)errorContext;

    // Dump rule
    dump(strValue);
}

// Parse
bool CSelectionCriterionRule::parse(CRuleParser& ruleParser, string& strError)
{
    // Criterion
    _pSelectionCriterion = ruleParser.getSelectionCriteriaDefinition()->getSelectionCriterion(ruleParser.getType());

    // Check existence
    if (!_pSelectionCriterion) {

        strError = "Couldn't find selection criterion " + ruleParser.getType();

        return false;
    }

    // Verb
    string strMatchesWhen;

    if (!ruleParser.next(strMatchesWhen, strError)) {

        return false;
    }
    // Value
    string strValue;

    if (!ruleParser.next(strValue, strError)) {

        return false;
    }

    // Matches when
    if (!setMatchesWhen(strMatchesWhen, strError)) {

        strError = "Verb error: " + strError;

        return false;
    }

    // Value
    if (!_pSelectionCriterion->getCriterionType()->getNumericalValue(strValue, _iMatchValue)) {

        strError = "Value error: \"" + strValue + "\" is not part of criterion \"" +
                   _pSelectionCriterion->getCriterionName() + "\"";

        return false;
    }

    return true;
}

// Dump
void CSelectionCriterionRule::dump(string& strResult) const
{
    // Criterion
    strResult += _pSelectionCriterion->getName();
    strResult += " ";
    // Verb
    strResult += _astMatchesWhen[_eMatchesWhen].pcMatchesWhen;
    strResult += " ";
    // Value
    string strValue;
    _pSelectionCriterion->getCriterionType()->getLiteralValue(_iMatchValue, strValue);
    strResult += strValue;
}

// Rule check
bool CSelectionCriterionRule::matches() const
{
    assert(_pSelectionCriterion);

    switch(_eMatchesWhen) {
    case EIs:
        return _pSelectionCriterion->is(_iMatchValue);
    case EIsNot:
        return _pSelectionCriterion->isNot(_iMatchValue);
    case EIncludes:
        return _pSelectionCriterion->includes(_iMatchValue);
    case EExcludes:
        return _pSelectionCriterion->excludes(_iMatchValue);
    default:
        assert(0);
        return false;
    }
}

// From IXmlSink
bool CSelectionCriterionRule::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
{
    // Retrieve actual context
    CXmlDomainSerializingContext& xmlDomainSerializingContext = static_cast<CXmlDomainSerializingContext&>(serializingContext);

    // Get selection criterion
    string strSelectionCriterion = xmlElement.getAttributeString("SelectionCriterion");

    _pSelectionCriterion = xmlDomainSerializingContext.getSelectionCriteriaDefinition()->getSelectionCriterion(strSelectionCriterion);

    // Check existence
    if (!_pSelectionCriterion) {

        xmlDomainSerializingContext.setError("Couldn't find selection criterion " + strSelectionCriterion + " in " + getKind() + " " + xmlElement.getPath());

        return false;
    }

    // Get MatchesWhen
    string strMatchesWhen = xmlElement.getAttributeString("MatchesWhen");
    string strError;

    if (!setMatchesWhen(strMatchesWhen, strError)) {

        xmlDomainSerializingContext.setError("Wrong MatchesWhen attribute " + strMatchesWhen + " in " + getKind() + " " + xmlElement.getPath() + ": " + strError);

        return false;
    }

    // Get Value
    string strValue = xmlElement.getAttributeString("Value");

    if (!_pSelectionCriterion->getCriterionType()->getNumericalValue(strValue, _iMatchValue)) {

        xmlDomainSerializingContext.setError("Wrong Value attribute value " + strValue + " in " + getKind() + " " + xmlElement.getPath());

        return false;
    }

    // Done
    return true;
}

// From IXmlSource
void CSelectionCriterionRule::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
{
    (void)serializingContext;

    assert(_pSelectionCriterion);

    // Set selection criterion
    xmlElement.setAttributeString("SelectionCriterion", _pSelectionCriterion->getName());

    // Set MatchesWhen
    xmlElement.setAttributeString("MatchesWhen", _astMatchesWhen[_eMatchesWhen].pcMatchesWhen);

    // Set Value
    string strValue;

     _pSelectionCriterion->getCriterionType()->getLiteralValue(_iMatchValue, strValue);

    xmlElement.setAttributeString("Value", strValue);
}

// XML MatchesWhen attribute parsing
bool CSelectionCriterionRule::setMatchesWhen(const string& strMatchesWhen, string& strError)
{
    uint32_t uiMatchesWhen;

    for (uiMatchesWhen = 0; uiMatchesWhen < ENbMatchesWhen; uiMatchesWhen++) {

        const SMatchingRuleDescription* pstMatchingRuleDescription = &_astMatchesWhen[uiMatchesWhen];

        if (strMatchesWhen == pstMatchingRuleDescription->pcMatchesWhen) {

            // Found it!

            // Get Type
            const ISelectionCriterionTypeInterface* pSelectionCriterionType = _pSelectionCriterion->getCriterionType();

            // Check compatibility if relevant
            if (!pSelectionCriterionType->isTypeInclusive() && !pstMatchingRuleDescription->bExclusiveTypeCompatible) {

                strError = "Value incompatible with exclusive kind of type";

                return false;
            }

            // Store
            _eMatchesWhen = (MatchesWhen)uiMatchesWhen;

            return true;
        }
    }

    strError = "Value not found";

    return false;
}
<|endoftext|>


<commit_before>
#include "hierarchical_system.hpp"

#include <algorithm>
#include <map>
#include <vector>

#include "geometry/frame.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/vanishes_before.hpp"

namespace principia {

using base::make_not_null_unique;
using quantities::si::Kilogram;
using quantities::si::Metre;
using testing_utilities::AlmostEquals;
using testing_utilities::VanishesBefore;
using ::testing::ElementsAre;

namespace physics {

class HierarchicalSystemTest : public ::testing::Test {
 protected:
  using Frame = geometry::Frame<serialization::Frame::TestTag,
                                serialization::Frame::TEST,
                                /*frame_is_inertial=*/true>;
};

TEST_F(HierarchicalSystemTest, HierarchicalSystem) {
  // e, i, Ω, ω, and mean anomaly are 0.
  KeplerianElements<Frame> elements;

  // Invariant: |body_indices[bodies[i]] == i| for all |i|.
  std::map<not_null<MassiveBody const*>, int> body_indices;
  std::vector<not_null<MassiveBody const*>> bodies;

  auto const new_body = [&body_indices, &bodies](Mass const& mass) {
    auto body = make_not_null_unique<MassiveBody>(mass);
    bodies.emplace_back(body.get());
    body_indices[body.get()] = body_indices.size();
    return body;
  };

  // We construct a system as follows, where the |body_indices|
  // are, from left to right, 0, 2, 3, 1.
  // |<1 m>|     |<1 m>|
  // 2     1     1     2
  //   |<   7/3 m   >|

  HierarchicalSystem<Frame> system(new_body(2 * Kilogram));
  elements.semimajor_axis = 7.0 / 3.0 * Metre;
  system.Add(new_body(2 * Kilogram), /*parent=*/bodies[0], elements);
  elements.semimajor_axis = 1 * Metre;
  system.Add(new_body(1 * Kilogram), /*parent=*/bodies[0], elements);
  elements.mean_anomaly = π * Radian;
  system.Add(new_body(1 * Kilogram), /*parent=*/bodies[1], elements);

  auto barycentric_system = system.ConsumeBarycentricSystem();
  // primary, closest secondary, furthest secondary, child of furthest
  // secondary.
  std::vector<int> expected_order = {0, 2, 1, 3};
  for (int i = 0; i < barycentric_system.bodies.size(); ++i) {
    EXPECT_TRUE(bodies[expected_order[i]] == barycentric_system.bodies[i].get())
        << i;
  }
  std::vector<Length> x_positions;
  std::transform(barycentric_system.degrees_of_freedom.begin(),
                 barycentric_system.degrees_of_freedom.end(),
                 std::back_inserter(x_positions),
                 [](DegreesOfFreedom<Frame> const& dof) {
                   return (dof.position() - Frame::origin).coordinates().x;
                 });
  EXPECT_THAT(x_positions,
              ElementsAre(AlmostEquals(-1.5 * Metre, 1),
                          AlmostEquals(-0.5 * Metre, 2),
                          1.5 * Metre,
                          0.5 * Metre));
}

TEST_F(HierarchicalSystemTest, FromMeanMotions) {
  // e, i, Ω, ω, and mean anomaly are 0.
  KeplerianElements<Frame> elements;

  // Invariant: |body_indices[bodies[i]] == i| for all |i|.
  std::map<not_null<MassiveBody const*>, int> body_indices;
  std::vector<not_null<MassiveBody const*>> bodies;

  auto const new_body = [&body_indices,
                         &bodies](GravitationalParameter const& mass) {
    auto body = make_not_null_unique<MassiveBody>(mass);
    bodies.emplace_back(body.get());
    body_indices[body.get()] = body_indices.size();
    return body;
  };

  // We construct a system as follows, where the |body_indices|
  // are, from left to right, 0, 2, 1.
  // |<1 m>|
  // 1     1     1
  //    |<1.5 m >|

  HierarchicalSystem<Frame> system(new_body(SIUnit<GravitationalParameter>()));
  elements.mean_motion = Sqrt(3 / Pow<3>(1.5)) * Radian / Second;
  system.Add(new_body(SIUnit<GravitationalParameter>()),
             /*parent=*/bodies[0],
             elements);
  elements.mean_motion = Sqrt(2) * Radian / Second;
  system.Add(new_body(SIUnit<GravitationalParameter>()),
             /*parent=*/bodies[0],
             elements);

  auto barycentric_system = system.ConsumeBarycentricSystem();

  std::vector<int> expected_order = {0, 2, 1};
  for (int i = 0; i < barycentric_system.bodies.size(); ++i) {
    EXPECT_TRUE(bodies[expected_order[i]] == barycentric_system.bodies[i].get())
        << i;
  }
  std::vector<Length> x_positions;
  std::transform(barycentric_system.degrees_of_freedom.begin(),
                 barycentric_system.degrees_of_freedom.end(),
                 std::back_inserter(x_positions),
                 [](DegreesOfFreedom<Frame> const& dof) {
                   return (dof.position() - Frame::origin).coordinates().x;
                 });
  EXPECT_THAT(x_positions,
              ElementsAre(-1 * Metre,
                          0 * Metre,
                          1 * Metre));
}

}  // namespace physics
}  // namespace principia
<commit_msg>cancellation<commit_after>
#include "hierarchical_system.hpp"

#include <algorithm>
#include <map>
#include <vector>

#include "geometry/frame.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/vanishes_before.hpp"

namespace principia {

using base::make_not_null_unique;
using quantities::si::Kilogram;
using quantities::si::Metre;
using testing_utilities::AlmostEquals;
using testing_utilities::VanishesBefore;
using ::testing::ElementsAre;

namespace physics {

class HierarchicalSystemTest : public ::testing::Test {
 protected:
  using Frame = geometry::Frame<serialization::Frame::TestTag,
                                serialization::Frame::TEST,
                                /*frame_is_inertial=*/true>;
};

TEST_F(HierarchicalSystemTest, HierarchicalSystem) {
  // e, i, Ω, ω, and mean anomaly are 0.
  KeplerianElements<Frame> elements;

  // Invariant: |body_indices[bodies[i]] == i| for all |i|.
  std::map<not_null<MassiveBody const*>, int> body_indices;
  std::vector<not_null<MassiveBody const*>> bodies;

  auto const new_body = [&body_indices, &bodies](Mass const& mass) {
    auto body = make_not_null_unique<MassiveBody>(mass);
    bodies.emplace_back(body.get());
    body_indices[body.get()] = body_indices.size();
    return body;
  };

  // We construct a system as follows, where the |body_indices|
  // are, from left to right, 0, 2, 3, 1.
  // |<1 m>|     |<1 m>|
  // 2     1     1     2
  //   |<   7/3 m   >|

  HierarchicalSystem<Frame> system(new_body(2 * Kilogram));
  elements.semimajor_axis = 7.0 / 3.0 * Metre;
  system.Add(new_body(2 * Kilogram), /*parent=*/bodies[0], elements);
  elements.semimajor_axis = 1 * Metre;
  system.Add(new_body(1 * Kilogram), /*parent=*/bodies[0], elements);
  elements.mean_anomaly = π * Radian;
  system.Add(new_body(1 * Kilogram), /*parent=*/bodies[1], elements);

  auto barycentric_system = system.ConsumeBarycentricSystem();
  // primary, closest secondary, furthest secondary, child of furthest
  // secondary.
  std::vector<int> expected_order = {0, 2, 1, 3};
  for (int i = 0; i < barycentric_system.bodies.size(); ++i) {
    EXPECT_TRUE(bodies[expected_order[i]] == barycentric_system.bodies[i].get())
        << i;
  }
  std::vector<Length> x_positions;
  std::transform(barycentric_system.degrees_of_freedom.begin(),
                 barycentric_system.degrees_of_freedom.end(),
                 std::back_inserter(x_positions),
                 [](DegreesOfFreedom<Frame> const& dof) {
                   return (dof.position() - Frame::origin).coordinates().x;
                 });
  EXPECT_THAT(x_positions,
              ElementsAre(AlmostEquals(-1.5 * Metre, 1),
                          AlmostEquals(-0.5 * Metre, 2),
                          1.5 * Metre,
                          0.5 * Metre));
}

TEST_F(HierarchicalSystemTest, FromMeanMotions) {
  // e, i, Ω, ω, and mean anomaly are 0.
  KeplerianElements<Frame> elements;

  // Invariant: |body_indices[bodies[i]] == i| for all |i|.
  std::map<not_null<MassiveBody const*>, int> body_indices;
  std::vector<not_null<MassiveBody const*>> bodies;

  auto const new_body = [&body_indices,
                         &bodies](GravitationalParameter const& mass) {
    auto body = make_not_null_unique<MassiveBody>(mass);
    bodies.emplace_back(body.get());
    body_indices[body.get()] = body_indices.size();
    return body;
  };

  // We construct a system as follows, where the |body_indices|
  // are, from left to right, 0, 2, 1.
  // |<1 m>|
  // 1     1     1
  //    |<1.5 m >|

  HierarchicalSystem<Frame> system(new_body(SIUnit<GravitationalParameter>()));
  elements.mean_motion = Sqrt(3 / Pow<3>(1.5)) * Radian / Second;
  system.Add(new_body(SIUnit<GravitationalParameter>()),
             /*parent=*/bodies[0],
             elements);
  elements.mean_motion = Sqrt(2) * Radian / Second;
  system.Add(new_body(SIUnit<GravitationalParameter>()),
             /*parent=*/bodies[0],
             elements);

  auto barycentric_system = system.ConsumeBarycentricSystem();

  std::vector<int> expected_order = {0, 2, 1};
  for (int i = 0; i < barycentric_system.bodies.size(); ++i) {
    EXPECT_TRUE(bodies[expected_order[i]] == barycentric_system.bodies[i].get())
        << i;
  }
  std::vector<Length> x_positions;
  std::transform(barycentric_system.degrees_of_freedom.begin(),
                 barycentric_system.degrees_of_freedom.end(),
                 std::back_inserter(x_positions),
                 [](DegreesOfFreedom<Frame> const& dof) {
                   return (dof.position() - Frame::origin).coordinates().x;
                 });
  EXPECT_THAT(x_positions,
              ElementsAre(-1 * Metre,
                          VanishesBefore(1 * Metre, 1),
                          1 * Metre));
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>#include "ofxTCPClient.h"
#include "ofAppRunner.h"

//--------------------------
ofxTCPClient::ofxTCPClient(){

	verbose		= false;
	connected	= false;
	messageSize = 0;
	port		= 0;
	index		= -1;
	str			= "";
	tmpStr		= "";
	ipAddr		="000.000.000.000";

	partialPrevMsg = "";

	memset(tmpBuff,  0, TCP_MAX_MSG_SIZE+1);
}

//--------------------------
ofxTCPClient::~ofxTCPClient(){
	close();
}

//--------------------------
void ofxTCPClient::setVerbose(bool _verbose){
	verbose = _verbose;
}

//--------------------------
bool ofxTCPClient::setup(string ip, int _port, bool blocking){

	if( !TCPClient.Create() ){
		if(verbose)printf("ofxTCPClient: Create() failed\n");
		return false;
	}else if( !TCPClient.Connect((char *)ip.c_str(), _port) ){
		if(verbose)printf("ofxTCPClient: Connect(%s, %i) failed\n", ip.c_str(), _port);
		TCPClient.Close(); //we free the connection
		return false;
	}

	TCPClient.SetNonBlocking(!blocking);

	port		= _port;
	ipAddr		= ip;
	connected	= true;
	return true;
}

//don't use this one
//for server to use internally only!
//--------------------------
bool ofxTCPClient::setup(int _index, bool blocking){
	index = _index;

	//this fetches the port that the server
	//sets up the connection on
	//different to the server's listening port
	InetAddr addr;
	if( TCPClient.GetRemoteAddr(&addr) ){
		port   =  addr.GetPort();
		ipAddr =  addr.DottedDecimal();
	}

	TCPClient.SetNonBlocking(!blocking);
	connected 	= true;
	return true;
}

//--------------------------
bool ofxTCPClient::close(){
	if( connected ){

		if( !TCPClient.Close() ){
			if(verbose)printf("ofxTCPClient: Close() failed\n");
			return false;
		}else{
			connected = false;
			return true;
		}
	}else{
		return true;
	}
}

//--------------------------
bool ofxTCPClient::send(string message){
	// tcp is a stream oriented protocol
	// so there's no way to be sure were
	// a message ends without using a terminator
	// note that you will receive a trailing [/TCP]\0
	// if sending from here and receiving from receiveRaw or
	// other applications
	message = partialPrevMsg + message + STR_END_MSG;
	message += (char)0; //for flash
	int ret = TCPClient.SendAll( message.c_str(), message.length() );
	if( ret == 0 ){
		if(verbose)printf("ofxTCPClient: other side disconnected\n");
		close();
		return false;
	}else if(ret<0){
		if(verbose)printf("ofxTCPClient: sendAll() failed\n");
		return false;
	}else if(ret<(int)message.length()){
		// in case of partial send, store the
		// part that hasn't been sent and send
		// with the next message to not corrupt
		// next messages
		partialPrevMsg=message.substr(ret);
		return true;
	}else{
		partialPrevMsg = "";
		return true;
	}
}

//--------------------------
bool ofxTCPClient::sendRaw(string message){
	if( message.length() == 0) return false;

	if( !TCPClient.SendAll(message.c_str(), message.length()) ){
		if(verbose)printf("ofxTCPClient: sendRawBytes() failed\n");
		close();
		return false;
	}else{
		return true;
	}
}

//--------------------------
bool ofxTCPClient::sendRawBytes(const char* rawBytes, const int numBytes){
	if( numBytes <= 0) return false;

	if( !TCPClient.SendAll(rawBytes, numBytes) ){
		if(verbose)printf("ofxTCPClient: sendRawBytes() failed\n");
		close();
		return false;
	}else{
		return true;
	}
}

//this only works after you have called receive
//--------------------------
int ofxTCPClient::getNumReceivedBytes(){
	return messageSize;
}

//--------------------------
static void removeZeros(char * buffer, int size){
	for(int i=0;i<size-1;i++){
		if(buffer[i]==(char)0){
			for(int j=i;j<size-1;j++){
				buffer[j]=buffer[j+1];
			}
			buffer[size-1]=(char)0;
		}
	}
}

//--------------------------
string ofxTCPClient::receive(){

	str    = "";
	int length=-2;
	//only get data from the buffer if we don't have already some complete message
	if(tmpStr.find(STR_END_MSG)==string::npos){
		memset(tmpBuff,  0, TCP_MAX_MSG_SIZE+1); //one more so there's always a \0 at the end for string concat
		length = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
		if(length>0){ // don't copy the data if there was an error or disconnection
			removeZeros(tmpBuff,length);
			tmpStr += tmpBuff;
		}
	}

	// check for connection reset or disconnection
	if((length==-1 && errno==TCP_CONNRESET ) || length == 0){
		close();
		if(tmpStr.length()==0) // return if there's no more data left in the buffer
			return "";
	}

	// process any available data
	if(tmpStr.find(STR_END_MSG)!=string::npos){
		str=tmpStr.substr(0,tmpStr.find(STR_END_MSG));
		tmpStr=tmpStr.substr(tmpStr.find(STR_END_MSG)+STR_END_MSG_LEN);
	}
	return str;
}

//--------------------------
int ofxTCPClient::receiveRawBytes(char * receiveBuffer, int numBytes){
	messageSize = TCPClient.Receive(receiveBuffer, numBytes);
	if(messageSize==0){
		close();
	}
	return messageSize;
}

//--------------------------
string ofxTCPClient::receiveRaw(){
	messageSize = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
	if(messageSize==0){
		close();
	}
	return tmpBuff;
}

//--------------------------
bool ofxTCPClient::isConnected(){
	return connected;
}

//--------------------------
int ofxTCPClient::getPort(){
	return port;
}

//--------------------------
string ofxTCPClient::getIP(){
	return ipAddr;
}

<commit_msg>add null terminator at the end of the received buffer in receiveRaw. Closes #213<commit_after>#include "ofxTCPClient.h"
#include "ofAppRunner.h"

//--------------------------
ofxTCPClient::ofxTCPClient(){

	verbose		= false;
	connected	= false;
	messageSize = 0;
	port		= 0;
	index		= -1;
	str			= "";
	tmpStr		= "";
	ipAddr		="000.000.000.000";

	partialPrevMsg = "";

	memset(tmpBuff,  0, TCP_MAX_MSG_SIZE+1);
}

//--------------------------
ofxTCPClient::~ofxTCPClient(){
	close();
}

//--------------------------
void ofxTCPClient::setVerbose(bool _verbose){
	verbose = _verbose;
}

//--------------------------
bool ofxTCPClient::setup(string ip, int _port, bool blocking){

	if( !TCPClient.Create() ){
		if(verbose)printf("ofxTCPClient: Create() failed\n");
		return false;
	}else if( !TCPClient.Connect((char *)ip.c_str(), _port) ){
		if(verbose)printf("ofxTCPClient: Connect(%s, %i) failed\n", ip.c_str(), _port);
		TCPClient.Close(); //we free the connection
		return false;
	}

	TCPClient.SetNonBlocking(!blocking);

	port		= _port;
	ipAddr		= ip;
	connected	= true;
	return true;
}

//don't use this one
//for server to use internally only!
//--------------------------
bool ofxTCPClient::setup(int _index, bool blocking){
	index = _index;

	//this fetches the port that the server
	//sets up the connection on
	//different to the server's listening port
	InetAddr addr;
	if( TCPClient.GetRemoteAddr(&addr) ){
		port   =  addr.GetPort();
		ipAddr =  addr.DottedDecimal();
	}

	TCPClient.SetNonBlocking(!blocking);
	connected 	= true;
	return true;
}

//--------------------------
bool ofxTCPClient::close(){
	if( connected ){

		if( !TCPClient.Close() ){
			if(verbose)printf("ofxTCPClient: Close() failed\n");
			return false;
		}else{
			connected = false;
			return true;
		}
	}else{
		return true;
	}
}

//--------------------------
bool ofxTCPClient::send(string message){
	// tcp is a stream oriented protocol
	// so there's no way to be sure were
	// a message ends without using a terminator
	// note that you will receive a trailing [/TCP]\0
	// if sending from here and receiving from receiveRaw or
	// other applications
	message = partialPrevMsg + message + STR_END_MSG;
	message += (char)0; //for flash
	int ret = TCPClient.SendAll( message.c_str(), message.length() );
	if( ret == 0 ){
		if(verbose)printf("ofxTCPClient: other side disconnected\n");
		close();
		return false;
	}else if(ret<0){
		if(verbose)printf("ofxTCPClient: sendAll() failed\n");
		return false;
	}else if(ret<(int)message.length()){
		// in case of partial send, store the
		// part that hasn't been sent and send
		// with the next message to not corrupt
		// next messages
		partialPrevMsg=message.substr(ret);
		return true;
	}else{
		partialPrevMsg = "";
		return true;
	}
}

//--------------------------
bool ofxTCPClient::sendRaw(string message){
	if( message.length() == 0) return false;

	if( !TCPClient.SendAll(message.c_str(), message.length()) ){
		if(verbose)printf("ofxTCPClient: sendRawBytes() failed\n");
		close();
		return false;
	}else{
		return true;
	}
}

//--------------------------
bool ofxTCPClient::sendRawBytes(const char* rawBytes, const int numBytes){
	if( numBytes <= 0) return false;

	if( !TCPClient.SendAll(rawBytes, numBytes) ){
		if(verbose)printf("ofxTCPClient: sendRawBytes() failed\n");
		close();
		return false;
	}else{
		return true;
	}
}

//this only works after you have called receive
//--------------------------
int ofxTCPClient::getNumReceivedBytes(){
	return messageSize;
}

//--------------------------
static void removeZeros(char * buffer, int size){
	for(int i=0;i<size-1;i++){
		if(buffer[i]==(char)0){
			for(int j=i;j<size-1;j++){
				buffer[j]=buffer[j+1];
			}
			buffer[size-1]=(char)0;
		}
	}
}

//--------------------------
string ofxTCPClient::receive(){

	str    = "";
	int length=-2;
	//only get data from the buffer if we don't have already some complete message
	if(tmpStr.find(STR_END_MSG)==string::npos){
		memset(tmpBuff,  0, TCP_MAX_MSG_SIZE+1); //one more so there's always a \0 at the end for string concat
		length = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
		if(length>0){ // don't copy the data if there was an error or disconnection
			removeZeros(tmpBuff,length);
			tmpStr += tmpBuff;
		}
	}

	// check for connection reset or disconnection
	if((length==-1 && errno==TCP_CONNRESET ) || length == 0){
		close();
		if(tmpStr.length()==0) // return if there's no more data left in the buffer
			return "";
	}

	// process any available data
	if(tmpStr.find(STR_END_MSG)!=string::npos){
		str=tmpStr.substr(0,tmpStr.find(STR_END_MSG));
		tmpStr=tmpStr.substr(tmpStr.find(STR_END_MSG)+STR_END_MSG_LEN);
	}
	return str;
}

//--------------------------
int ofxTCPClient::receiveRawBytes(char * receiveBuffer, int numBytes){
	messageSize = TCPClient.Receive(receiveBuffer, numBytes);
	if(messageSize==0){
		close();
	}
	return messageSize;
}

//--------------------------
string ofxTCPClient::receiveRaw(){
	messageSize = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
	if(messageSize==0){
		close();
	}else if(messageSize<TCP_MAX_MSG_SIZE) {
        // null terminate!!
        tmpBuff[messageSize] = 0;
    }

	return tmpBuff;
}

//--------------------------
bool ofxTCPClient::isConnected(){
	return connected;
}

//--------------------------
int ofxTCPClient::getPort(){
	return port;
}

//--------------------------
string ofxTCPClient::getIP(){
	return ipAddr;
}

<|endoftext|>