<commit_before>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "parametersparser.h"

const int DEFAULT_COUNT_THRESHOLD = 0;
const int DEFAULT_TIME_THRESHOLD = 1;
const int DEFAULT_PRINT_HEAP_HISTOGRAM = 0;
const char* HEX_CHARS = "0123456789ABCDEF";

enum {
    TIME_OPT = 0,
    COUNT_OPT,
    PRINT_HEAP_HISTOGRAM_OPT,
    THE_END
};

char *tokens[] = {
    [TIME_OPT] = strdup("time"),
    [COUNT_OPT] = strdup("count"),
    [PRINT_HEAP_HISTOGRAM_OPT] = strdup("printHeapHistogram"),
    [THE_END] = NULL
};

void checkValueProvided(char *value, int option) {
   if (value == NULL) {
      fprintf(stderr, "Suboption '%s=<value>' did not have a value\n", tokens[option]);
      abort();
   }
}

char* toHex(char* s) {
   int len = strlen(s);
   char *result = new char[len * 2 + 1];

   for (int i = 0; i < len; i++) {
     char c = s[i];
     result[2 * i] = HEX_CHARS[(c >> 4) & 0xF];
     result[2 * i + 1] = HEX_CHARS[c & 0xF];
   }

   result[len * 2] = '\0';
   return result;
}

ParametersParser::ParametersParser() {
}

AgentParameters ParametersParser::parse(char *options) {
  AgentParameters result;
  //sets defaults
  result.count_threshold = DEFAULT_COUNT_THRESHOLD;
  result.time_threshold = DEFAULT_TIME_THRESHOLD;
  result.print_heap_histogram = DEFAULT_PRINT_HEAP_HISTOGRAM;

  if (options != NULL) {
     // Copy input options since getsubopt modifies its input
     char *subopts = new char[strlen(options) + 1];
     strcpy(subopts, options);

     char *value;

     while (*subopts != '\0') {
        switch (getsubopt(&subopts, tokens, &value)) {
           case COUNT_OPT:
              checkValueProvided(value, COUNT_OPT);
              result.count_threshold = (strlen(value) == 0) ? DEFAULT_COUNT_THRESHOLD : atoi(value);
              break;

           case TIME_OPT:
              checkValueProvided(value, TIME_OPT);
              result.time_threshold = (strlen(value) == 0) ? DEFAULT_TIME_THRESHOLD : atoi(value);
              break;

          case PRINT_HEAP_HISTOGRAM_OPT:
              checkValueProvided(value, PRINT_HEAP_HISTOGRAM_OPT);
              result.print_heap_histogram = (strlen(value) == 0) ? DEFAULT_PRINT_HEAP_HISTOGRAM : atoi(value);
              break;

          default:
              // Print the unrecognised option name and value. On Darwin, value omits the option name.
              fprintf(stderr, "Unknown suboption '%s' (hex '%s')\n", value, toHex(value));
              fprintf(stderr, "Valid suboptions are:\n");
              for (int i = TIME_OPT; i < THE_END; i++) {
                 char* option = tokens[i];
                 fprintf(stderr, "  '%s' (hex '%s')\n", option, toHex(option));
              }
              abort();
              break;
        }
     }
  }
  return result;
}
<commit_msg>Tolerate unrecognised agent parameters<commit_after>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "parametersparser.h"

const int DEFAULT_COUNT_THRESHOLD = 0;
const int DEFAULT_TIME_THRESHOLD = 1;
const int DEFAULT_PRINT_HEAP_HISTOGRAM = 0;

enum {
    TIME_OPT = 0,
    COUNT_OPT,
    PRINT_HEAP_HISTOGRAM_OPT,
    THE_END
};

char *tokens[] = {
    [TIME_OPT] = strdup("time"),
    [COUNT_OPT] = strdup("count"),
    [PRINT_HEAP_HISTOGRAM_OPT] = strdup("printHeapHistogram"),
    [THE_END] = NULL
};

void checkValueProvided(char *value, int option) {
   if (value == NULL) {
      fprintf(stderr, "Suboption '%s=<value>' did not have a value\n", tokens[option]);
      abort();
   }
}

ParametersParser::ParametersParser() {
}

AgentParameters ParametersParser::parse(char *options) {
  AgentParameters result;
  //sets defaults
  result.count_threshold = DEFAULT_COUNT_THRESHOLD;
  result.time_threshold = DEFAULT_TIME_THRESHOLD;
  result.print_heap_histogram = DEFAULT_PRINT_HEAP_HISTOGRAM;

  if (options != NULL) {
     // Copy input options since getsubopt modifies its input
     char *subopts = new char[strlen(options) + 1];
     strcpy(subopts, options);

     char *value;

     while (*subopts != '\0') {
        switch (getsubopt(&subopts, tokens, &value)) {
           case COUNT_OPT:
              checkValueProvided(value, COUNT_OPT);
              result.count_threshold = (strlen(value) == 0) ? DEFAULT_COUNT_THRESHOLD : atoi(value);
              break;

           case TIME_OPT:
              checkValueProvided(value, TIME_OPT);
              result.time_threshold = (strlen(value) == 0) ? DEFAULT_TIME_THRESHOLD : atoi(value);
              break;

          case PRINT_HEAP_HISTOGRAM_OPT:
              checkValueProvided(value, PRINT_HEAP_HISTOGRAM_OPT);
              result.print_heap_histogram = (strlen(value) == 0) ? DEFAULT_PRINT_HEAP_HISTOGRAM : atoi(value);
              break;

          default:
              // Print the unrecognised option name and value.
              // Note: Darwin's getsubopt omits the option name and equals sign from value in this case.
              fprintf(stderr, "Unknown suboption '%s'\n", value);
              break;
        }
     }
  }
  return result;
}
<|endoftext|>


<commit_before>#ifndef _FUNCTIONTRAITS_H
#define _FUNCTIONTRAITS_H

#include <functional>
#include <tuple>

// 转换为std::function和函数指针
template<typename T>
class FunctionTraits;

// 普通函数
template<typename Ret, typename... Args>
class FunctionTraits<Ret(Args...)>
{
public:
	enum
    {
        Arity = sizeof...(Args)
    };

	typedef Ret functionType(Args...);
    using returnType = Ret;
	using stlFunctionType = std::function<functionType>;
    using pointer = Ret(*)(Args...);

#if 0
    template<std::size_t N>
    using argType = typename std::tuple_element<N, std::tuple<Args...>>::type;
#else
	template<std::size_t N>
	class args
	{
    public:
		static_assert(N < Arity, "Index is out of range, index must less than sizeof Args");
		using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
	};
#endif
};

// 函数指针
template<typename Ret, typename... Args>
class FunctionTraits<Ret(*)(Args...)> : public FunctionTraits<Ret(Args...)>{};

// std::function
template <typename Ret, typename... Args>
class FunctionTraits<std::function<Ret(Args...)>> : public FunctionTraits<Ret(Args...)>{};

// 成员函数
#define MEMBER_FUNTION_TRAITS(...) \
template <typename ReturnType, typename ClassType, typename... Args> \
class FunctionTraits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : public FunctionTraits<ReturnType(Args...)>{}; \

MEMBER_FUNTION_TRAITS()
MEMBER_FUNTION_TRAITS(const)
MEMBER_FUNTION_TRAITS(volatile)
MEMBER_FUNTION_TRAITS(const volatile)

// 函数对象
template<typename Callable>
class FunctionTraits : public FunctionTraits<decltype(&Callable::operator())>{};

template <typename Function>
typename FunctionTraits<Function>::stlFunctionType toFunction(const Function& lambda)
{
	return static_cast<typename FunctionTraits<Function>::stlFunctionType>(lambda);
}

template <typename Function>
typename FunctionTraits<Function>::stlFunctionType toFunction(Function&& lambda)
{
	return static_cast<typename FunctionTraits<Function>::stlFunctionType>(std::forward<Function>(lambda));
}

template <typename Function>
typename FunctionTraits<Function>::pointer toFunctionPointer(const Function& lambda)
{
	return static_cast<typename FunctionTraits<Function>::pointer>(lambda);
}

#endif
<commit_msg>Update functiontraits<commit_after>#ifndef _FUNCTIONTRAITS_H
#define _FUNCTIONTRAITS_H

#include <functional>
#include <tuple>

// 转换为std::function和函数指针
template<typename T>
struct FunctionTraits;

// 普通函数
template<typename Ret, typename... Args>
struct FunctionTraits<Ret(Args...)>
{
	enum
    {
        Arity = sizeof...(Args)
    };

	typedef Ret functionType(Args...);
    using returnType = Ret;
	using stlFunctionType = std::function<functionType>;
    using pointer = Ret(*)(Args...);

#if 0
    template<std::size_t N>
    using argType = typename std::tuple_element<N, std::tuple<Args...>>::type;
#else
	template<std::size_t N>
	struct args
	{
		static_assert(N < Arity, "Index is out of range, index must less than sizeof Args");
		using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
	};
#endif
};

// 函数指针
template<typename Ret, typename... Args>
struct FunctionTraits<Ret(*)(Args...)> : public FunctionTraits<Ret(Args...)>{};

// std::function
template <typename Ret, typename... Args>
struct FunctionTraits<std::function<Ret(Args...)>> : public FunctionTraits<Ret(Args...)>{};

// 成员函数
#define MEMBER_FUNTION_TRAITS(...) \
template <typename ReturnType, typename ClassType, typename... Args> \
struct FunctionTraits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : public FunctionTraits<ReturnType(Args...)>{}; \

MEMBER_FUNTION_TRAITS()
MEMBER_FUNTION_TRAITS(const)
MEMBER_FUNTION_TRAITS(volatile)
MEMBER_FUNTION_TRAITS(const volatile)

// 函数对象
template<typename Callable>
struct FunctionTraits : public FunctionTraits<decltype(&Callable::operator())>{};

template <typename Function>
typename FunctionTraits<Function>::stlFunctionType toFunction(const Function& lambda)
{
	return static_cast<typename FunctionTraits<Function>::stlFunctionType>(lambda);
}

template <typename Function>
typename FunctionTraits<Function>::stlFunctionType toFunction(Function&& lambda)
{
	return static_cast<typename FunctionTraits<Function>::stlFunctionType>(std::forward<Function>(lambda));
}

template <typename Function>
typename FunctionTraits<Function>::pointer toFunctionPointer(const Function& lambda)
{
	return static_cast<typename FunctionTraits<Function>::pointer>(lambda);
}

#endif
<|endoftext|>


<commit_before>
#include "Factory.hh"
#include "evaluators.hh"
#include "PrintingEvaluator.hh"
#include "operands.hh"
#include "operations.hh"
#include "Tokenizer.hh"

#include <iostream>
#include <stdexcept>
#include <list>
#include <stack>
#include <string>

//
// Edsger Dijkstra invented the Shunting-yard algorithm to convert infix expressions to postfix (RPN).
//
// http://scriptasylum.com/tutorials/infix_postfix/algorithms/infix-postfix/index.htm
// http://everything2.com/title/Infix+to+postfix+conversion+algorithm

void Factory::transform(
        std::ostream & aResultPostfixExpression,
        const std::string & aInfixExpression,
        const std::string & aOperations )
{
    init_precedencetab();
    std::stack<char> op_stack;

    std::string::const_iterator it  = aInfixExpression.begin();
    std::string::const_iterator end = aInfixExpression.end();

    while (it != end)
    {
        if ( aOperations.find(*it) != std::string::npos )
        {
            // check precedences
            while (!op_stack.empty() &&
                    aOperations.find(op_stack.top()) != std::string::npos &&
                    cmpprecedence(op_stack.top(), *it) >= 0)
            {
                aResultPostfixExpression << op_stack.top() << " ";
                op_stack.pop();
            }
            op_stack.push(*it);
        }
        else if ( *it == '(' )
            op_stack.push( *it );
        else if ( *it == ')' )
        {
            while (!op_stack.empty() &&
                    op_stack.top() != '(')
            {
                aResultPostfixExpression << op_stack.top() << " ";
                op_stack.pop();
            }
            op_stack.pop();
        }
        else aResultPostfixExpression << *it << " ";
        ++it;
    }

    while (!op_stack.empty())
    {
        aResultPostfixExpression << op_stack.top() << " ";
        op_stack.pop();
    }
}

/// @deprecated
int Factory::eval( std::istream & infix,  const std::string & ops  )
{
    std::stack<int> args;
    std::string token;

    while (infix >> token)
    {
        std::cout << "token: " << token << std::endl;
        if (ops.find(token) != std::string::npos)
        {
            int tmp = args.top();
            args.pop();

            switch (*token.c_str())
            {
                case '+': args.top() += tmp; break;
                case '-': args.top() -= tmp; break;
                case '|': args.top() = args.top() || tmp; break;
                case '*': args.top() *= tmp; break;
                case '/': args.top() /= tmp; break;
                case '^': args.top() ^= tmp; break;
                case '&': args.top() = args.top() && tmp; break;
                case '<': args.top() = args.top() < tmp; break;
                case '>': args.top() = args.top() > tmp; break;
                default: std::cout << "?" << *token.c_str() << "?"; break;
            }
        }
        else
        {
            std::stringstream s( token.c_str() );
            int tmp;
            s >> tmp;
            args.push( tmp /*atoi(token.c_str())*/ );
        }
    }

    if (args.size() != 1)
        throw std::runtime_error("blad w wyrazeniu");

    return args.top();
}

void Factory::transform(
        ExpressionTokensStack & aResultPostfixExpression,
        const std::string & aInfixExpression,
        const std::string & aOperations  )
{
    init_precedencetab();

    std::list< ExpressionTokenPtr>  lExpressionTokensList;
    std::stack<std::string> op_stack;
    std::stringstream lExpressionStream(aInfixExpression);

    Tokenizer lTokenizer;
    std::string lTok = lTokenizer.nextStrToken( lExpressionStream );

    while ( ! lTok.empty() )
    {
        if ( lTok.size() == 1 &&
             aOperations.find(lTok[0]) != std::string::npos )
        {
            // check precedences
            while (!op_stack.empty() &&
                   aOperations.find(op_stack.top()[0]) != std::string::npos &&
                   cmpprecedence(op_stack.top()[0], lTok[0]) >= 0)
            {
                lExpressionTokensList.push_back( createToken( op_stack.top() ) );
                op_stack.pop();
            }
            op_stack.push(lTok);
        }
        else if ( lTok == "(" )
            op_stack.push( lTok );
        else if ( lTok == ")" )
        {
            while (!op_stack.empty() &&
                    op_stack.top() != "(")
            {
                lExpressionTokensList.push_back( createToken( op_stack.top() ) );
                op_stack.pop();
            }
            op_stack.pop();
        }
        else lExpressionTokensList.push_back( createToken( lTok ) );

        lTok = lTokenizer.nextStrToken( lExpressionStream );
    }

    while ( ! op_stack.empty() )
    {
        lExpressionTokensList.push_back( createToken( op_stack.top() ) );

        op_stack.pop();
    }

    while ( ! lExpressionTokensList.empty() )
    {
        aResultPostfixExpression.push( lExpressionTokensList.back() );
        lExpressionTokensList.pop_back();
    }
}

std::string Factory::evalExpression( const std::string & aInfixInput )
{
    ExpressionTokensStack     lStack;
    Factory().transform(lStack, aInfixInput );

    Evaluators::Evaluator lEvaluator;
//    Evaluators::PrintingEvaluator lEvaluator( std::cout );
    Evaluators::evaluate( lStack, lEvaluator );

    if ( ! lEvaluator.getOperandsStack().empty() )
    {
        std::stringstream lFormatter;
        Operands::OperandPtr lOperand = lEvaluator.getOperandsStack().top();
        Evaluators::PrintingEvaluator lResult( lFormatter );
        lOperand->accept( lResult );
        return lFormatter.str();
    }

    return "";
}

std::string Factory::nextStrToken( std::istream & aInput )
{
    std::string lResult;
    return (aInput >> lResult) ? lResult : "";
}

ExpressionTokenPtr Factory::createToken( const std::string & aInput )
{
    ExpressionTokenPtr lResult;

    if ( ! aInput.empty() )
    {
        if ( aInput.size() > 1 )
        {
            lResult = Operands::Numeric::Ptr( new Operands::Numeric( std::stod( aInput ) ) );
        }
        else
        {
            switch ( aInput[0] )
            {
                case '+': lResult = Operations::Add::Ptr( new Operations::Add() ); break;
                case '-': lResult = Operations::Sub::Ptr( new Operations::Sub() ); break;
                case '|': lResult = Operations::Or::Ptr( new Operations::Or() ); break;
                case '*': lResult = Operations::Mul::Ptr( new Operations::Mul() ); break;
                case '/': lResult = Operations::Div::Ptr( new Operations::Div() ); break;
                case '^': lResult = Operations::Pow::Ptr( new Operations::Pow() ); break;
                case '&': lResult = Operations::And::Ptr( new Operations::And() ); break;
                case '<': lResult = Operations::Lt::Ptr( new Operations::Lt() ); break;
                case '>': lResult = Operations::Gt::Ptr( new Operations::Gt() ); break;
                default:
                    {
                        lResult = Operands::Numeric::Ptr( new Operands::Numeric( std::stod( aInput ) ) );
                    }
                break;
            }
        }
    }

    return lResult;
}

ExpressionTokenPtr Factory::createToken( const char aInput )
{
    return createToken( std::string(1, aInput) );
}

void Factory::init_precedencetab()
{
    // +, -, *, /, ^
    precedencetab['<'] = 0;
    precedencetab['>'] = 0;
    precedencetab['+'] = 1;
    precedencetab['-'] = 2;
    precedencetab['|'] = 2;
    precedencetab['*'] = 3;
    precedencetab['/'] = 3;
    precedencetab['^'] = 3;
    precedencetab['&'] = 3;
}
<commit_msg>Handle string concatenation (+).<commit_after>
#include "Factory.hh"
#include "evaluators.hh"
#include "PrintingEvaluator.hh"
#include "operands.hh"
#include "operations.hh"
#include "Tokenizer.hh"

#include <iostream>
#include <stdexcept>
#include <list>
#include <stack>
#include <string>

//
// Edsger Dijkstra invented the Shunting-yard algorithm to convert infix expressions to postfix (RPN).
//
// http://scriptasylum.com/tutorials/infix_postfix/algorithms/infix-postfix/index.htm
// http://everything2.com/title/Infix+to+postfix+conversion+algorithm

void Factory::transform(
        std::ostream & aResultPostfixExpression,
        const std::string & aInfixExpression,
        const std::string & aOperations )
{
    init_precedencetab();
    std::stack<char> op_stack;

    std::string::const_iterator it  = aInfixExpression.begin();
    std::string::const_iterator end = aInfixExpression.end();

    while (it != end)
    {
        if ( aOperations.find(*it) != std::string::npos )
        {
            // check precedences
            while (!op_stack.empty() &&
                    aOperations.find(op_stack.top()) != std::string::npos &&
                    cmpprecedence(op_stack.top(), *it) >= 0)
            {
                aResultPostfixExpression << op_stack.top() << " ";
                op_stack.pop();
            }
            op_stack.push(*it);
        }
        else if ( *it == '(' )
            op_stack.push( *it );
        else if ( *it == ')' )
        {
            while (!op_stack.empty() &&
                    op_stack.top() != '(')
            {
                aResultPostfixExpression << op_stack.top() << " ";
                op_stack.pop();
            }
            op_stack.pop();
        }
        else aResultPostfixExpression << *it << " ";
        ++it;
    }

    while (!op_stack.empty())
    {
        aResultPostfixExpression << op_stack.top() << " ";
        op_stack.pop();
    }
}

/// @deprecated
int Factory::eval( std::istream & infix,  const std::string & ops  )
{
    std::stack<int> args;
    std::string token;

    while (infix >> token)
    {
        std::cout << "token: " << token << std::endl;
        if (ops.find(token) != std::string::npos)
        {
            int tmp = args.top();
            args.pop();

            switch (*token.c_str())
            {
                case '+': args.top() += tmp; break;
                case '-': args.top() -= tmp; break;
                case '|': args.top() = args.top() || tmp; break;
                case '*': args.top() *= tmp; break;
                case '/': args.top() /= tmp; break;
                case '^': args.top() ^= tmp; break;
                case '&': args.top() = args.top() && tmp; break;
                case '<': args.top() = args.top() < tmp; break;
                case '>': args.top() = args.top() > tmp; break;
                default: std::cout << "?" << *token.c_str() << "?"; break;
            }
        }
        else
        {
            std::stringstream s( token.c_str() );
            int tmp;
            s >> tmp;
            args.push( tmp /*atoi(token.c_str())*/ );
        }
    }

    if (args.size() != 1)
        throw std::runtime_error("blad w wyrazeniu");

    return args.top();
}

void Factory::transform(
        ExpressionTokensStack & aResultPostfixExpression,
        const std::string & aInfixExpression,
        const std::string & aOperations  )
{
    init_precedencetab();

    std::list< ExpressionTokenPtr>  lExpressionTokensList;
    std::stack<std::string> op_stack;
    std::stringstream lExpressionStream(aInfixExpression);

    Tokenizer lTokenizer;
    std::string lTok = lTokenizer.nextStrToken( lExpressionStream );

    while ( ! lTok.empty() )
    {
        if ( lTok.size() == 1 &&
             aOperations.find(lTok[0]) != std::string::npos )
        {
            // check precedences
            while (!op_stack.empty() &&
                   aOperations.find(op_stack.top()[0]) != std::string::npos &&
                   cmpprecedence(op_stack.top()[0], lTok[0]) >= 0)
            {
                lExpressionTokensList.push_back( createToken( op_stack.top() ) );
                op_stack.pop();
            }
            op_stack.push(lTok);
        }
        else if ( lTok == "(" )
            op_stack.push( lTok );
        else if ( lTok == ")" )
        {
            while (!op_stack.empty() &&
                    op_stack.top() != "(")
            {
                lExpressionTokensList.push_back( createToken( op_stack.top() ) );
                op_stack.pop();
            }
            op_stack.pop();
        }
        else lExpressionTokensList.push_back( createToken( lTok ) );

        lTok = lTokenizer.nextStrToken( lExpressionStream );
    }

    while ( ! op_stack.empty() )
    {
        lExpressionTokensList.push_back( createToken( op_stack.top() ) );

        op_stack.pop();
    }

    while ( ! lExpressionTokensList.empty() )
    {
        aResultPostfixExpression.push( lExpressionTokensList.back() );
        lExpressionTokensList.pop_back();
    }
}

std::string Factory::evalExpression( const std::string & aInfixInput )
{
    ExpressionTokensStack     lStack;
    Factory().transform(lStack, aInfixInput );

    Evaluators::Evaluator lEvaluator;
//    Evaluators::PrintingEvaluator lEvaluator( std::cout );
    Evaluators::evaluate( lStack, lEvaluator );

    if ( ! lEvaluator.getOperandsStack().empty() )
    {
        std::stringstream lFormatter;
        Operands::OperandPtr lOperand = lEvaluator.getOperandsStack().top();
        Evaluators::PrintingEvaluator lResult( lFormatter );
        lOperand->accept( lResult );
        return lFormatter.str();
    }

    return "";
}

std::string Factory::nextStrToken( std::istream & aInput )
{
    std::string lResult;
    return (aInput >> lResult) ? lResult : "";
}

ExpressionTokenPtr Factory::createToken( const std::string & aInput )
{
    ExpressionTokenPtr lResult;

    if ( ! aInput.empty() )
    {
        if ( aInput.size() > 1 )
        {
            lResult = Operands::Numeric::Ptr( new Operands::Numeric( std::stod( aInput ) ) );
        }
        else
        {
            switch ( aInput[0] )
            {
                case '+': lResult = Operations::Add::Ptr( new Operations::Add() ); break;
                case '-': lResult = Operations::Sub::Ptr( new Operations::Sub() ); break;
                case '|': lResult = Operations::Or::Ptr( new Operations::Or() ); break;
                case '*': lResult = Operations::Mul::Ptr( new Operations::Mul() ); break;
                case '/': lResult = Operations::Div::Ptr( new Operations::Div() ); break;
                case '^': lResult = Operations::Pow::Ptr( new Operations::Pow() ); break;
                case '&': lResult = Operations::And::Ptr( new Operations::And() ); break;
                case '<': lResult = Operations::Lt::Ptr( new Operations::Lt() ); break;
                case '>': lResult = Operations::Gt::Ptr( new Operations::Gt() ); break;
                default:
                    {
                        try
                        {
                            lResult = Operands::Numeric::Ptr( new Operands::Numeric( std::stod( aInput ) ) );
                        }
                        catch ( std::invalid_argument & e )
                        {
                        }

                        lResult = Operands::Text::Ptr( new Operands::Text( aInput ) );
                    }
                break;
            }
        }
    }

    return lResult;
}

ExpressionTokenPtr Factory::createToken( const char aInput )
{
    return createToken( std::string(1, aInput) );
}

void Factory::init_precedencetab()
{
    // +, -, *, /, ^
    precedencetab['<'] = 0;
    precedencetab['>'] = 0;
    precedencetab['+'] = 1;
    precedencetab['-'] = 2;
    precedencetab['|'] = 2;
    precedencetab['*'] = 3;
    precedencetab['/'] = 3;
    precedencetab['^'] = 3;
    precedencetab['&'] = 3;
}
<|endoftext|>


<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <ctime>
#include <thread>
#include <utils/asyncworker.h>
#include <utils/fs.h>
#include <utils/period_worker.h>
#include <utils/skiplist.h>
#include <utils/utils.h>

BOOST_AUTO_TEST_CASE(SkipListCheck) {
  using int_lst = dariadb::utils::skiplist<size_t, size_t>;

  int_lst lst;
  const size_t insertions = 33;
  size_t sum_before = 0;
  for (size_t i = 0; i < insertions; i += 3) {
    lst.insert(i, i * 5);
    lst.insert(i + 2, (i + 2) * 10);
    lst.insert(i + 1, (i + 1) * 10);
    lst.insert(i, i * 10);
    sum_before += i + i + 2 + i + 1;
  }
  lst.print();
  BOOST_CHECK_EQUAL(lst.size(), size_t(33));
  for (auto &kv : lst) {
    kv.second = kv.first * 11;
  }
  lst.remove(0);
  BOOST_CHECK_EQUAL(lst.size(), size_t(32));
  for (size_t i = 0; i < 33; ++i) {
    auto fpos = lst.find(i);
    if (fpos != lst.end()) {
      auto kv = *fpos;
      BOOST_CHECK_EQUAL(kv.second, i * 11);
    } else {
      if (i != 0) { // we remove 0;
        BOOST_CHECK(fpos != lst.end());
      }
    }
  }
  size_t sum = 0;
  for (auto it = lst.begin(); it != lst.end(); ++it) {
    sum += it->first;
  }
  BOOST_CHECK_EQUAL(sum, sum_before);

  sum = 0;
  for (auto it = lst.cbegin(); it != lst.cend(); ++it) {
    sum += it->first;
  }
  BOOST_CHECK_EQUAL(sum, sum_before);

  lst.remove(size_t(3));
  lst.print();
  BOOST_CHECK(lst.find(size_t(3)) == lst.end());

  auto ub = lst.upper_bound(size_t(4));
  BOOST_CHECK_EQUAL(ub->first, size_t(5));

  auto lb = lst.lower_bound(size_t(4));
  BOOST_CHECK_EQUAL(lb->first, size_t(2));

  lb = lst.lower_bound(size_t(3));
  BOOST_CHECK_EQUAL(lb->first, size_t(2));

  lst.remove_if(lst.begin(), lst.end(),
                [](const int_lst::pair_type &kv) { return kv.first < 20; });
  for (auto it : lst) {
    BOOST_CHECK(it.first >= 20);
  }
  lst.print();
}

BOOST_AUTO_TEST_CASE(CountZero) {
  BOOST_CHECK_EQUAL(dariadb::utils::clz(67553994410557440), 8);
  BOOST_CHECK_EQUAL(dariadb::utils::clz(3458764513820540928), 2);
  BOOST_CHECK_EQUAL(dariadb::utils::clz(15), 60);

  BOOST_CHECK_EQUAL(dariadb::utils::ctz(240), 4);
  BOOST_CHECK_EQUAL(dariadb::utils::ctz(3840), 8);
}

BOOST_AUTO_TEST_CASE(InInterval) {
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 1));
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 2));
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 5));
  BOOST_CHECK(!dariadb::utils::inInterval(1, 5, 0));
  BOOST_CHECK(!dariadb::utils::inInterval(0, 1, 2));
}

BOOST_AUTO_TEST_CASE(BitOperations) {
  uint8_t value = 0;
  for (int8_t i = 0; i < 7; i++) {
    value = dariadb::utils::BitOperations::set(value, i);
    BOOST_CHECK_EQUAL(dariadb::utils::BitOperations::check(value, i), true);
  }

  for (int8_t i = 0; i < 7; i++) {
    value = dariadb::utils::BitOperations::clr(value, i);
  }

  for (int8_t i = 0; i < 7; i++) {
    BOOST_CHECK_EQUAL(dariadb::utils::BitOperations::check(value, i), false);
  }
}

BOOST_AUTO_TEST_CASE(FileUtils) {
  std::string filename = "foo/bar/test.txt";
  BOOST_CHECK_EQUAL(dariadb::utils::fs::filename(filename), "test");
  BOOST_CHECK_EQUAL(dariadb::utils::fs::parent_path(filename), "foo/bar");

  auto ls_res = dariadb::utils::fs::ls(".");
  BOOST_CHECK(ls_res.size() > 0);

  const std::string fname = "mapped_file.test";
  auto mapf = dariadb::utils::fs::MappedFile::touch(fname, 1024);
  for (uint8_t i = 0; i < 100; i++) {
    mapf->data()[i] = i;
  }
  mapf->close();

  ls_res = dariadb::utils::fs::ls(".", ".test");
  BOOST_CHECK(ls_res.size() == 1);
  auto reopen_mapf = dariadb::utils::fs::MappedFile::open(fname);
  for (uint8_t i = 0; i < 100; i++) {
    BOOST_CHECK_EQUAL(reopen_mapf->data()[i], i);
  }
  reopen_mapf->close();
  dariadb::utils::fs::rm(fname);

  std::string parent_p = "path1";
  std::string child_p = "path2";
  auto concat_p = dariadb::utils::fs::append_path(parent_p, child_p);
  BOOST_CHECK_EQUAL(dariadb::utils::fs::parent_path(concat_p), parent_p);
}

class TestPeriodWorker : public dariadb::utils::PeriodWorker {
public:
  TestPeriodWorker(const std::chrono::milliseconds sleep_time)
      : dariadb::utils::PeriodWorker(sleep_time) {
    call_count = 0;
  }
  void call() { call_count++; }
  size_t call_count;
};

BOOST_AUTO_TEST_CASE(PeriodWorkerTest) {
  auto secs_1 = std::chrono::milliseconds(1000);
  auto secs_3 = std::chrono::milliseconds(1300);
  std::unique_ptr<TestPeriodWorker> worker{new TestPeriodWorker(secs_1)};
  worker->start_worker();
  std::this_thread::sleep_for(secs_3);
  worker->stop_worker();
  BOOST_CHECK(worker->call_count > 1);
}

class TestWorker : public dariadb::utils::AsyncWorker<int> {
public:
  int value;
  TestWorker() : value(0) {}
  void call_async(const int &data) override { value += data; }
};

BOOST_AUTO_TEST_CASE(Worker) {

  TestWorker worker;

  worker.start_async();

  BOOST_CHECK(!worker.is_busy());

  worker.add_async_data(1);
  worker.add_async_data(2);
  worker.add_async_data(3);
  worker.add_async_data(4);

  worker.flush_async();

  BOOST_CHECK(!worker.is_busy());

  worker.stop_async();
  BOOST_CHECK(worker.stoped());
  BOOST_CHECK_EQUAL(worker.value, (int)1 + 2 + 3 + 4);
}
<commit_msg>rm debug prints.<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>
#include <chrono>
#include <ctime>
#include <thread>
#include <utils/asyncworker.h>
#include <utils/fs.h>
#include <utils/period_worker.h>
#include <utils/skiplist.h>
#include <utils/utils.h>

BOOST_AUTO_TEST_CASE(SkipListCheck) {
  using int_lst = dariadb::utils::skiplist<size_t, size_t>;

  int_lst lst;
  const size_t insertions = 33;
  size_t sum_before = 0;
  for (size_t i = 0; i < insertions; i += 3) {
    lst.insert(i, i * 5);
    lst.insert(i + 2, (i + 2) * 10);
    lst.insert(i + 1, (i + 1) * 10);
    lst.insert(i, i * 10);
    sum_before += i + i + 2 + i + 1;
  }
  //lst.print();
  BOOST_CHECK_EQUAL(lst.size(), size_t(33));
  for (auto &kv : lst) {
    kv.second = kv.first * 11;
  }
  lst.remove(0);
  BOOST_CHECK_EQUAL(lst.size(), size_t(32));
  for (size_t i = 0; i < 33; ++i) {
    auto fpos = lst.find(i);
    if (fpos != lst.end()) {
      auto kv = *fpos;
      BOOST_CHECK_EQUAL(kv.second, i * 11);
    } else {
      if (i != 0) { // we remove 0;
        BOOST_CHECK(fpos != lst.end());
      }
    }
  }
  size_t sum = 0;
  for (auto it = lst.begin(); it != lst.end(); ++it) {
    sum += it->first;
  }
  BOOST_CHECK_EQUAL(sum, sum_before);

  sum = 0;
  for (auto it = lst.cbegin(); it != lst.cend(); ++it) {
    sum += it->first;
  }
  BOOST_CHECK_EQUAL(sum, sum_before);

  lst.remove(size_t(3));
  //lst.print();
  BOOST_CHECK(lst.find(size_t(3)) == lst.end());

  auto ub = lst.upper_bound(size_t(4));
  BOOST_CHECK_EQUAL(ub->first, size_t(5));

  auto lb = lst.lower_bound(size_t(4));
  BOOST_CHECK_EQUAL(lb->first, size_t(2));

  lb = lst.lower_bound(size_t(3));
  BOOST_CHECK_EQUAL(lb->first, size_t(2));

  lst.remove_if(lst.begin(), lst.end(),
                [](const int_lst::pair_type &kv) { return kv.first < 20; });
  for (auto it : lst) {
    BOOST_CHECK(it.first >= 20);
  }
  //lst.print();
}

BOOST_AUTO_TEST_CASE(CountZero) {
  BOOST_CHECK_EQUAL(dariadb::utils::clz(67553994410557440), 8);
  BOOST_CHECK_EQUAL(dariadb::utils::clz(3458764513820540928), 2);
  BOOST_CHECK_EQUAL(dariadb::utils::clz(15), 60);

  BOOST_CHECK_EQUAL(dariadb::utils::ctz(240), 4);
  BOOST_CHECK_EQUAL(dariadb::utils::ctz(3840), 8);
}

BOOST_AUTO_TEST_CASE(InInterval) {
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 1));
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 2));
  BOOST_CHECK(dariadb::utils::inInterval(1, 5, 5));
  BOOST_CHECK(!dariadb::utils::inInterval(1, 5, 0));
  BOOST_CHECK(!dariadb::utils::inInterval(0, 1, 2));
}

BOOST_AUTO_TEST_CASE(BitOperations) {
  uint8_t value = 0;
  for (int8_t i = 0; i < 7; i++) {
    value = dariadb::utils::BitOperations::set(value, i);
    BOOST_CHECK_EQUAL(dariadb::utils::BitOperations::check(value, i), true);
  }

  for (int8_t i = 0; i < 7; i++) {
    value = dariadb::utils::BitOperations::clr(value, i);
  }

  for (int8_t i = 0; i < 7; i++) {
    BOOST_CHECK_EQUAL(dariadb::utils::BitOperations::check(value, i), false);
  }
}

BOOST_AUTO_TEST_CASE(FileUtils) {
  std::string filename = "foo/bar/test.txt";
  BOOST_CHECK_EQUAL(dariadb::utils::fs::filename(filename), "test");
  BOOST_CHECK_EQUAL(dariadb::utils::fs::parent_path(filename), "foo/bar");

  auto ls_res = dariadb::utils::fs::ls(".");
  BOOST_CHECK(ls_res.size() > 0);

  const std::string fname = "mapped_file.test";
  auto mapf = dariadb::utils::fs::MappedFile::touch(fname, 1024);
  for (uint8_t i = 0; i < 100; i++) {
    mapf->data()[i] = i;
  }
  mapf->close();

  ls_res = dariadb::utils::fs::ls(".", ".test");
  BOOST_CHECK(ls_res.size() == 1);
  auto reopen_mapf = dariadb::utils::fs::MappedFile::open(fname);
  for (uint8_t i = 0; i < 100; i++) {
    BOOST_CHECK_EQUAL(reopen_mapf->data()[i], i);
  }
  reopen_mapf->close();
  dariadb::utils::fs::rm(fname);

  std::string parent_p = "path1";
  std::string child_p = "path2";
  auto concat_p = dariadb::utils::fs::append_path(parent_p, child_p);
  BOOST_CHECK_EQUAL(dariadb::utils::fs::parent_path(concat_p), parent_p);
}

class TestPeriodWorker : public dariadb::utils::PeriodWorker {
public:
  TestPeriodWorker(const std::chrono::milliseconds sleep_time)
      : dariadb::utils::PeriodWorker(sleep_time) {
    call_count = 0;
  }
  void call() { call_count++; }
  size_t call_count;
};

BOOST_AUTO_TEST_CASE(PeriodWorkerTest) {
  auto secs_1 = std::chrono::milliseconds(1000);
  auto secs_3 = std::chrono::milliseconds(1300);
  std::unique_ptr<TestPeriodWorker> worker{new TestPeriodWorker(secs_1)};
  worker->start_worker();
  std::this_thread::sleep_for(secs_3);
  worker->stop_worker();
  BOOST_CHECK(worker->call_count > 1);
}

class TestWorker : public dariadb::utils::AsyncWorker<int> {
public:
  int value;
  TestWorker() : value(0) {}
  void call_async(const int &data) override { value += data; }
};

BOOST_AUTO_TEST_CASE(Worker) {

  TestWorker worker;

  worker.start_async();

  BOOST_CHECK(!worker.is_busy());

  worker.add_async_data(1);
  worker.add_async_data(2);
  worker.add_async_data(3);
  worker.add_async_data(4);

  worker.flush_async();

  BOOST_CHECK(!worker.is_busy());

  worker.stop_async();
  BOOST_CHECK(worker.stoped());
  BOOST_CHECK_EQUAL(worker.value, (int)1 + 2 + 3 + 4);
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/cbor_builders.h"

#include "src/constants.h"
#include "src/crypto_utility.h"

namespace fido2_tests {

CborBuilder::CborBuilder() {}

CborBuilder::~CborBuilder() {}

bool CborBuilder::HasEntry(int key) {
  return request_map_.find(cbor::Value(key)) != request_map_.end();
}

void CborBuilder::SetArbitraryMapEntry(int key, cbor::Value&& value) {
  request_map_[cbor::Value(key)] = std::move(value);
}

void CborBuilder::SetArbitraryMapEntry(cbor::Value&& key, cbor::Value&& value) {
  request_map_[std::move(key)] = std::move(value);
}

void CborBuilder::RemoveArbitraryMapEntry(int key) {
  request_map_.erase(cbor::Value(key));
}

void CborBuilder::RemoveArbitraryMapEntry(cbor::Value&& key) {
  request_map_.erase(key);
}

cbor::Value CborBuilder::GetCbor() { return cbor::Value(request_map_); }

void MakeCredentialCborBuilder::SetMapEntry(MakeCredentialParameters key,
                                            cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void MakeCredentialCborBuilder::RemoveMapEntry(MakeCredentialParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void MakeCredentialCborBuilder::SetDefaultClientDataHash() {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetMapEntry(MakeCredentialParameters::kClientDataHash,
              cbor::Value(std::move(client_data_hash)));
}

void MakeCredentialCborBuilder::SetDefaultPublicKeyCredentialRpEntity(
    const std::string& rp_id) {
  cbor::Value::MapValue pub_key_cred_rp_entity;
  pub_key_cred_rp_entity[cbor::Value("id")] = cbor::Value(rp_id);
  SetMapEntry(MakeCredentialParameters::kRp,
              cbor::Value(std::move(pub_key_cred_rp_entity)));
}

void MakeCredentialCborBuilder::SetDefaultPublicKeyCredentialUserEntity() {
  cbor::Value::MapValue pub_key_cred_user_entity;
  cbor::Value::BinaryValue user_id(32, 0x1D);
  pub_key_cred_user_entity[cbor::Value("id")] = cbor::Value(std::move(user_id));
  // TODO(kaczmarczyck) remove in final product
  // name is not required, but the Yubikey uses it, so removing it would break
  // too many tests and prevent meaningful results
  // https://github.com/fido-alliance/fido-2-specs/pull/496
  pub_key_cred_user_entity[cbor::Value("name")] = cbor::Value("Adam");
  SetMapEntry(MakeCredentialParameters::kUser,
              cbor::Value(std::move(pub_key_cred_user_entity)));
}

void MakeCredentialCborBuilder::SetPublicKeyCredentialUserEntity(
    const cbor::Value::BinaryValue& user_id, const std::string& user_name) {
  cbor::Value::MapValue pub_key_cred_user_entity;
  pub_key_cred_user_entity[cbor::Value("id")] = cbor::Value(user_id);
  pub_key_cred_user_entity[cbor::Value("name")] = cbor::Value(user_name);
  SetMapEntry(MakeCredentialParameters::kUser,
              cbor::Value(std::move(pub_key_cred_user_entity)));
}

void MakeCredentialCborBuilder::SetEs256CredentialParameters() {
  cbor::Value::ArrayValue pub_key_cred_params;
  cbor::Value::MapValue es256_param;
  es256_param[cbor::Value("alg")] =
      cbor::Value(static_cast<int>(Algorithm::kEs256Algorithm));
  es256_param[cbor::Value("type")] = cbor::Value("public-key");
  pub_key_cred_params.push_back(cbor::Value(es256_param));
  SetMapEntry(MakeCredentialParameters::kPubKeyCredParams,
              cbor::Value(std::move(pub_key_cred_params)));
}

void MakeCredentialCborBuilder::SetRs256CredentialParameters() {
  cbor::Value::ArrayValue pub_key_cred_params;
  cbor::Value::MapValue rs256_param;
  rs256_param[cbor::Value("alg")] =
      cbor::Value(static_cast<int>(Algorithm::kRs256Algorithm));
  rs256_param[cbor::Value("type")] = cbor::Value("public-key");
  pub_key_cred_params.push_back(cbor::Value(rs256_param));
  SetMapEntry(MakeCredentialParameters::kPubKeyCredParams,
              cbor::Value(std::move(pub_key_cred_params)));
}

void MakeCredentialCborBuilder::SetExcludeListCredential(
    const cbor::Value::BinaryValue& cred_descriptor_id) {
  cbor::Value::ArrayValue exclude_list;
  cbor::Value::MapValue cred_descriptor;
  cred_descriptor[cbor::Value("type")] = cbor::Value("public-key");
  cred_descriptor[cbor::Value("id")] = cbor::Value(cred_descriptor_id);
  exclude_list.push_back(cbor::Value(cred_descriptor));
  SetMapEntry(MakeCredentialParameters::kExcludeList,
              cbor::Value(std::move(exclude_list)));
}

void MakeCredentialCborBuilder::SetResidentKeyOptions(bool is_rk_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("rk")] = cbor::Value(is_rk_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetUserPresenceOptions(bool is_up_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("up")] = cbor::Value(is_up_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetUserVerificationOptions(bool is_uv_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("uv")] = cbor::Value(is_uv_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetPinUvAuthParam(
    const cbor::Value::BinaryValue& auth_param) {
  SetMapEntry(MakeCredentialParameters::kPinUvAuthParam,
              cbor::Value(auth_param));
}

void MakeCredentialCborBuilder::SetDefaultPinUvAuthParam(
    const cbor::Value::BinaryValue& pin_token) {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetPinUvAuthParam(
      crypto_utility::LeftHmacSha256(pin_token, client_data_hash));
}

void MakeCredentialCborBuilder::SetDefaultPinUvAuthProtocol() {
  SetMapEntry(MakeCredentialParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void MakeCredentialCborBuilder::AddDefaultsForRequiredFields(
    const std::string& rp_id) {
  if (!HasEntry(1)) {
    SetDefaultClientDataHash();
  }
  if (!HasEntry(2)) {
    SetDefaultPublicKeyCredentialRpEntity(rp_id);
  }
  if (!HasEntry(3)) {
    SetDefaultPublicKeyCredentialUserEntity();
  }
  if (!HasEntry(4)) {
    SetEs256CredentialParameters();
  }
}

void GetAssertionCborBuilder::SetMapEntry(GetAssertionParameters key,
                                          cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void GetAssertionCborBuilder::RemoveMapEntry(GetAssertionParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void GetAssertionCborBuilder::SetRelyingParty(const std::string& rp_id) {
  SetMapEntry(GetAssertionParameters::kRpId, cbor::Value(rp_id));
}

void GetAssertionCborBuilder::SetDefaultClientDataHash() {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetMapEntry(GetAssertionParameters::kClientDataHash,
              cbor::Value(std::move(client_data_hash)));
}

void GetAssertionCborBuilder::SetAllowListCredential(
    const cbor::Value::BinaryValue& cred_descriptor_id) {
  cbor::Value::ArrayValue allow_list;
  cbor::Value::MapValue cred_descriptor;
  cred_descriptor[cbor::Value("type")] = cbor::Value("public-key");
  cred_descriptor[cbor::Value("id")] = cbor::Value(cred_descriptor_id);
  allow_list.push_back(cbor::Value(cred_descriptor));
  SetMapEntry(GetAssertionParameters::kAllowList,
              cbor::Value(std::move(allow_list)));
}

void GetAssertionCborBuilder::SetUserPresenceOptions(bool is_up_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("up")] = cbor::Value(is_up_active);
  SetMapEntry(GetAssertionParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void GetAssertionCborBuilder::SetUserVerificationOptions(bool is_uv_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("uv")] = cbor::Value(is_uv_active);
  SetMapEntry(GetAssertionParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void GetAssertionCborBuilder::SetPinUvAuthParam(
    const cbor::Value::BinaryValue& auth_param) {
  SetMapEntry(GetAssertionParameters::kPinUvAuthParam, cbor::Value(auth_param));
}

void GetAssertionCborBuilder::SetDefaultPinUvAuthParam(
    const cbor::Value::BinaryValue& pin_token) {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetPinUvAuthParam(
      crypto_utility::LeftHmacSha256(pin_token, client_data_hash));
}

void GetAssertionCborBuilder::SetDefaultPinUvAuthProtocol() {
  SetMapEntry(GetAssertionParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void GetAssertionCborBuilder::AddDefaultsForRequiredFields(std::string rp_id) {
  if (!HasEntry(1)) {
    SetRelyingParty(rp_id);
  }
  if (!HasEntry(2)) {
    SetDefaultClientDataHash();
  }
}

void AuthenticatorClientPinCborBuilder::SetMapEntry(ClientPinParameters key,
                                                    cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void AuthenticatorClientPinCborBuilder::RemoveMapEntry(
    ClientPinParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void AuthenticatorClientPinCborBuilder::SetDefaultPinProtocol() {
  SetMapEntry(ClientPinParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void AuthenticatorClientPinCborBuilder::SetSubCommand(
    PinSubCommand sub_command) {
  SetMapEntry(ClientPinParameters::kSubCommand,
              cbor::Value(static_cast<uint8_t>(sub_command)));
}

void AuthenticatorClientPinCborBuilder::SetKeyAgreement(
    const cbor::Value::MapValue& cose_key) {
  SetMapEntry(ClientPinParameters::kKeyAgreement, cbor::Value(cose_key));
}

void AuthenticatorClientPinCborBuilder::SetPinAuth(
    const cbor::Value::BinaryValue& pin_auth) {
  SetMapEntry(ClientPinParameters::kPinUvAuthParam, cbor::Value(pin_auth));
}

void AuthenticatorClientPinCborBuilder::SetNewPinEnc(
    const cbor::Value::BinaryValue& new_pin_enc) {
  SetMapEntry(ClientPinParameters::kNewPinEnc, cbor::Value(new_pin_enc));
}

void AuthenticatorClientPinCborBuilder::SetPinHashEnc(
    const cbor::Value::BinaryValue& pin_hash_enc) {
  SetMapEntry(ClientPinParameters::kPinHashEnc, cbor::Value(pin_hash_enc));
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinRetries() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinRetries);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetKeyAgreement() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetKeyAgreement);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForSetPin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_auth,
    const cbor::Value::BinaryValue& new_pin_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kSetPin);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(4)) {
    SetPinAuth(pin_auth);
  }
  if (!HasEntry(5)) {
    SetNewPinEnc(new_pin_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForChangePin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_auth,
    const cbor::Value::BinaryValue& new_pin_enc,
    const cbor::Value::BinaryValue& pin_hash_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kChangePin);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(4)) {
    SetPinAuth(pin_auth);
  }
  if (!HasEntry(5)) {
    SetNewPinEnc(new_pin_enc);
  }
  if (!HasEntry(6)) {
    SetPinHashEnc(pin_hash_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinUvAuthTokenUsingPin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_hash_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinToken);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(6)) {
    SetPinHashEnc(pin_hash_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinUvAuthTokenUsingUv(
    const cbor::Value::MapValue& cose_key) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinToken);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetUvRetries() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetUvRetries);
  }
}

}  // namespace fido2_tests

<commit_msg>fixes constant in CBOR builder<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/cbor_builders.h"

#include "src/constants.h"
#include "src/crypto_utility.h"

namespace fido2_tests {

CborBuilder::CborBuilder() {}

CborBuilder::~CborBuilder() {}

bool CborBuilder::HasEntry(int key) {
  return request_map_.find(cbor::Value(key)) != request_map_.end();
}

void CborBuilder::SetArbitraryMapEntry(int key, cbor::Value&& value) {
  request_map_[cbor::Value(key)] = std::move(value);
}

void CborBuilder::SetArbitraryMapEntry(cbor::Value&& key, cbor::Value&& value) {
  request_map_[std::move(key)] = std::move(value);
}

void CborBuilder::RemoveArbitraryMapEntry(int key) {
  request_map_.erase(cbor::Value(key));
}

void CborBuilder::RemoveArbitraryMapEntry(cbor::Value&& key) {
  request_map_.erase(key);
}

cbor::Value CborBuilder::GetCbor() { return cbor::Value(request_map_); }

void MakeCredentialCborBuilder::SetMapEntry(MakeCredentialParameters key,
                                            cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void MakeCredentialCborBuilder::RemoveMapEntry(MakeCredentialParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void MakeCredentialCborBuilder::SetDefaultClientDataHash() {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetMapEntry(MakeCredentialParameters::kClientDataHash,
              cbor::Value(std::move(client_data_hash)));
}

void MakeCredentialCborBuilder::SetDefaultPublicKeyCredentialRpEntity(
    const std::string& rp_id) {
  cbor::Value::MapValue pub_key_cred_rp_entity;
  pub_key_cred_rp_entity[cbor::Value("id")] = cbor::Value(rp_id);
  SetMapEntry(MakeCredentialParameters::kRp,
              cbor::Value(std::move(pub_key_cred_rp_entity)));
}

void MakeCredentialCborBuilder::SetDefaultPublicKeyCredentialUserEntity() {
  cbor::Value::MapValue pub_key_cred_user_entity;
  cbor::Value::BinaryValue user_id(32, 0x1D);
  pub_key_cred_user_entity[cbor::Value("id")] = cbor::Value(std::move(user_id));
  // TODO(kaczmarczyck) remove in final product
  // name is not required, but the Yubikey uses it, so removing it would break
  // too many tests and prevent meaningful results
  // https://github.com/fido-alliance/fido-2-specs/pull/496
  pub_key_cred_user_entity[cbor::Value("name")] = cbor::Value("Adam");
  SetMapEntry(MakeCredentialParameters::kUser,
              cbor::Value(std::move(pub_key_cred_user_entity)));
}

void MakeCredentialCborBuilder::SetPublicKeyCredentialUserEntity(
    const cbor::Value::BinaryValue& user_id, const std::string& user_name) {
  cbor::Value::MapValue pub_key_cred_user_entity;
  pub_key_cred_user_entity[cbor::Value("id")] = cbor::Value(user_id);
  pub_key_cred_user_entity[cbor::Value("name")] = cbor::Value(user_name);
  SetMapEntry(MakeCredentialParameters::kUser,
              cbor::Value(std::move(pub_key_cred_user_entity)));
}

void MakeCredentialCborBuilder::SetEs256CredentialParameters() {
  cbor::Value::ArrayValue pub_key_cred_params;
  cbor::Value::MapValue es256_param;
  es256_param[cbor::Value("alg")] =
      cbor::Value(static_cast<int>(Algorithm::kEs256Algorithm));
  es256_param[cbor::Value("type")] = cbor::Value("public-key");
  pub_key_cred_params.push_back(cbor::Value(es256_param));
  SetMapEntry(MakeCredentialParameters::kPubKeyCredParams,
              cbor::Value(std::move(pub_key_cred_params)));
}

void MakeCredentialCborBuilder::SetRs256CredentialParameters() {
  cbor::Value::ArrayValue pub_key_cred_params;
  cbor::Value::MapValue rs256_param;
  rs256_param[cbor::Value("alg")] =
      cbor::Value(static_cast<int>(Algorithm::kRs256Algorithm));
  rs256_param[cbor::Value("type")] = cbor::Value("public-key");
  pub_key_cred_params.push_back(cbor::Value(rs256_param));
  SetMapEntry(MakeCredentialParameters::kPubKeyCredParams,
              cbor::Value(std::move(pub_key_cred_params)));
}

void MakeCredentialCborBuilder::SetExcludeListCredential(
    const cbor::Value::BinaryValue& cred_descriptor_id) {
  cbor::Value::ArrayValue exclude_list;
  cbor::Value::MapValue cred_descriptor;
  cred_descriptor[cbor::Value("type")] = cbor::Value("public-key");
  cred_descriptor[cbor::Value("id")] = cbor::Value(cred_descriptor_id);
  exclude_list.push_back(cbor::Value(cred_descriptor));
  SetMapEntry(MakeCredentialParameters::kExcludeList,
              cbor::Value(std::move(exclude_list)));
}

void MakeCredentialCborBuilder::SetResidentKeyOptions(bool is_rk_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("rk")] = cbor::Value(is_rk_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetUserPresenceOptions(bool is_up_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("up")] = cbor::Value(is_up_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetUserVerificationOptions(bool is_uv_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("uv")] = cbor::Value(is_uv_active);
  SetMapEntry(MakeCredentialParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void MakeCredentialCborBuilder::SetPinUvAuthParam(
    const cbor::Value::BinaryValue& auth_param) {
  SetMapEntry(MakeCredentialParameters::kPinUvAuthParam,
              cbor::Value(auth_param));
}

void MakeCredentialCborBuilder::SetDefaultPinUvAuthParam(
    const cbor::Value::BinaryValue& pin_token) {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetPinUvAuthParam(
      crypto_utility::LeftHmacSha256(pin_token, client_data_hash));
}

void MakeCredentialCborBuilder::SetDefaultPinUvAuthProtocol() {
  SetMapEntry(MakeCredentialParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void MakeCredentialCborBuilder::AddDefaultsForRequiredFields(
    const std::string& rp_id) {
  if (!HasEntry(1)) {
    SetDefaultClientDataHash();
  }
  if (!HasEntry(2)) {
    SetDefaultPublicKeyCredentialRpEntity(rp_id);
  }
  if (!HasEntry(3)) {
    SetDefaultPublicKeyCredentialUserEntity();
  }
  if (!HasEntry(4)) {
    SetEs256CredentialParameters();
  }
}

void GetAssertionCborBuilder::SetMapEntry(GetAssertionParameters key,
                                          cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void GetAssertionCborBuilder::RemoveMapEntry(GetAssertionParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void GetAssertionCborBuilder::SetRelyingParty(const std::string& rp_id) {
  SetMapEntry(GetAssertionParameters::kRpId, cbor::Value(rp_id));
}

void GetAssertionCborBuilder::SetDefaultClientDataHash() {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetMapEntry(GetAssertionParameters::kClientDataHash,
              cbor::Value(std::move(client_data_hash)));
}

void GetAssertionCborBuilder::SetAllowListCredential(
    const cbor::Value::BinaryValue& cred_descriptor_id) {
  cbor::Value::ArrayValue allow_list;
  cbor::Value::MapValue cred_descriptor;
  cred_descriptor[cbor::Value("type")] = cbor::Value("public-key");
  cred_descriptor[cbor::Value("id")] = cbor::Value(cred_descriptor_id);
  allow_list.push_back(cbor::Value(cred_descriptor));
  SetMapEntry(GetAssertionParameters::kAllowList,
              cbor::Value(std::move(allow_list)));
}

void GetAssertionCborBuilder::SetUserPresenceOptions(bool is_up_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("up")] = cbor::Value(is_up_active);
  SetMapEntry(GetAssertionParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void GetAssertionCborBuilder::SetUserVerificationOptions(bool is_uv_active) {
  cbor::Value::MapValue authenticator_options;
  authenticator_options[cbor::Value("uv")] = cbor::Value(is_uv_active);
  SetMapEntry(GetAssertionParameters::kOptions,
              cbor::Value(std::move(authenticator_options)));
}

void GetAssertionCborBuilder::SetPinUvAuthParam(
    const cbor::Value::BinaryValue& auth_param) {
  SetMapEntry(GetAssertionParameters::kPinUvAuthParam, cbor::Value(auth_param));
}

void GetAssertionCborBuilder::SetDefaultPinUvAuthParam(
    const cbor::Value::BinaryValue& pin_token) {
  cbor::Value::BinaryValue client_data_hash(32, 0xcd);
  SetPinUvAuthParam(
      crypto_utility::LeftHmacSha256(pin_token, client_data_hash));
}

void GetAssertionCborBuilder::SetDefaultPinUvAuthProtocol() {
  SetMapEntry(GetAssertionParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void GetAssertionCborBuilder::AddDefaultsForRequiredFields(std::string rp_id) {
  if (!HasEntry(1)) {
    SetRelyingParty(rp_id);
  }
  if (!HasEntry(2)) {
    SetDefaultClientDataHash();
  }
}

void AuthenticatorClientPinCborBuilder::SetMapEntry(ClientPinParameters key,
                                                    cbor::Value&& value) {
  SetArbitraryMapEntry(static_cast<int>(key), std::move(value));
}

void AuthenticatorClientPinCborBuilder::RemoveMapEntry(
    ClientPinParameters key) {
  RemoveArbitraryMapEntry(static_cast<int>(key));
}

void AuthenticatorClientPinCborBuilder::SetDefaultPinProtocol() {
  SetMapEntry(ClientPinParameters::kPinUvAuthProtocol, cbor::Value(1));
}

void AuthenticatorClientPinCborBuilder::SetSubCommand(
    PinSubCommand sub_command) {
  SetMapEntry(ClientPinParameters::kSubCommand,
              cbor::Value(static_cast<uint8_t>(sub_command)));
}

void AuthenticatorClientPinCborBuilder::SetKeyAgreement(
    const cbor::Value::MapValue& cose_key) {
  SetMapEntry(ClientPinParameters::kKeyAgreement, cbor::Value(cose_key));
}

void AuthenticatorClientPinCborBuilder::SetPinAuth(
    const cbor::Value::BinaryValue& pin_auth) {
  SetMapEntry(ClientPinParameters::kPinUvAuthParam, cbor::Value(pin_auth));
}

void AuthenticatorClientPinCborBuilder::SetNewPinEnc(
    const cbor::Value::BinaryValue& new_pin_enc) {
  SetMapEntry(ClientPinParameters::kNewPinEnc, cbor::Value(new_pin_enc));
}

void AuthenticatorClientPinCborBuilder::SetPinHashEnc(
    const cbor::Value::BinaryValue& pin_hash_enc) {
  SetMapEntry(ClientPinParameters::kPinHashEnc, cbor::Value(pin_hash_enc));
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinRetries() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinRetries);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetKeyAgreement() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetKeyAgreement);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForSetPin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_auth,
    const cbor::Value::BinaryValue& new_pin_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kSetPin);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(4)) {
    SetPinAuth(pin_auth);
  }
  if (!HasEntry(5)) {
    SetNewPinEnc(new_pin_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForChangePin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_auth,
    const cbor::Value::BinaryValue& new_pin_enc,
    const cbor::Value::BinaryValue& pin_hash_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kChangePin);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(4)) {
    SetPinAuth(pin_auth);
  }
  if (!HasEntry(5)) {
    SetNewPinEnc(new_pin_enc);
  }
  if (!HasEntry(6)) {
    SetPinHashEnc(pin_hash_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinUvAuthTokenUsingPin(
    const cbor::Value::MapValue& cose_key,
    const cbor::Value::BinaryValue& pin_hash_enc) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinToken);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
  if (!HasEntry(6)) {
    SetPinHashEnc(pin_hash_enc);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetPinUvAuthTokenUsingUv(
    const cbor::Value::MapValue& cose_key) {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetPinUvAuthTokenUsingUv);
  }
  if (!HasEntry(3)) {
    SetKeyAgreement(cose_key);
  }
}

void AuthenticatorClientPinCborBuilder::AddDefaultsForGetUvRetries() {
  if (!HasEntry(1)) {
    SetDefaultPinProtocol();
  }
  if (!HasEntry(2)) {
    SetSubCommand(PinSubCommand::kGetUvRetries);
  }
}

}  // namespace fido2_tests

<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <flutter/flutter_window_controller.h>
#include <linux/limits.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <memory>
#include <vector>

#include "flutter/generated_plugin_registrant.h"

namespace {

// Returns the path of the directory containing this executable, or an empty
// string if the directory cannot be found.
std::string GetExecutableDirectory() {
  char buffer[PATH_MAX + 1];
  ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer));
  if (length > PATH_MAX) {
    std::cerr << "Couldn't locate executable" << std::endl;
    return "";
  }
  std::string executable_path(buffer, length);
  size_t last_separator_position = executable_path.find_last_of('/');
  if (last_separator_position == std::string::npos) {
    std::cerr << "Unabled to find parent directory of " << executable_path
              << std::endl;
    return "";
  }
  return executable_path.substr(0, last_separator_position);
}

}  // namespace

int main(int argc, char **argv) {
  // Resources are located relative to the executable.
  std::string base_directory = GetExecutableDirectory();
  if (base_directory.empty()) {
    base_directory = ".";
  }
  std::string data_directory = base_directory + "/data";
  std::string assets_path = data_directory + "/flutter_assets";
  std::string icu_data_path = data_directory + "/icudtl.dat";

  // Arguments for the Flutter Engine.
  std::vector<std::string> arguments;

  flutter::FlutterWindowController flutter_controller(icu_data_path);
  flutter::WindowProperties window_properties = {};
  window_properties.title = "Dart DevTools";
  window_properties.width = 800;
  window_properties.height = 600;

  // Start the engine.
  if (!flutter_controller.CreateWindow(window_properties, assets_path,
                                       arguments)) {
    return EXIT_FAILURE;
  }
  RegisterPlugins(&flutter_controller);

  // Run until the window is closed.
  while (flutter_controller.RunEventLoopWithTimeout(
      std::chrono::milliseconds::max())) {
  }
  return EXIT_SUCCESS;
}
<commit_msg>Add profiling support for Linux desktop (#1485)<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <flutter/flutter_window_controller.h>
#include <linux/limits.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <memory>
#include <vector>

#include "flutter/generated_plugin_registrant.h"

namespace {

// Returns the path of the directory containing this executable, or an empty
// string if the directory cannot be found.
std::string GetExecutableDirectory() {
  char buffer[PATH_MAX + 1];
  ssize_t length = readlink("/proc/self/exe", buffer, sizeof(buffer));
  if (length > PATH_MAX) {
    std::cerr << "Couldn't locate executable" << std::endl;
    return "";
  }
  std::string executable_path(buffer, length);
  size_t last_separator_position = executable_path.find_last_of('/');
  if (last_separator_position == std::string::npos) {
    std::cerr << "Unabled to find parent directory of " << executable_path
              << std::endl;
    return "";
  }
  return executable_path.substr(0, last_separator_position);
}

}  // namespace

int main(int argc, char **argv) {
  // Resources are located relative to the executable.
  std::string base_directory = GetExecutableDirectory();
  if (base_directory.empty()) {
    base_directory = ".";
  }
  std::string data_directory = base_directory + "/data";
  std::string assets_path = data_directory + "/flutter_assets";
  std::string icu_data_path = data_directory + "/icudtl.dat";

  // Arguments for the Flutter Engine.
  std::vector<std::string> arguments;
  arguments.push_back("--enable-dart-profiling");
  arguments.push_back("--trace-systrace");

  flutter::FlutterWindowController flutter_controller(icu_data_path);
  flutter::WindowProperties window_properties = {};
  window_properties.title = "Dart DevTools";
  window_properties.width = 800;
  window_properties.height = 600;

  // Start the engine.
  if (!flutter_controller.CreateWindow(window_properties, assets_path,
                                       arguments)) {
    return EXIT_FAILURE;
  }
  RegisterPlugins(&flutter_controller);

  // Run until the window is closed.
  while (flutter_controller.RunEventLoopWithTimeout(
      std::chrono::milliseconds::max())) {
  }
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: clipboardctl.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: tl $ $Date: 2001-03-30 14:23:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif
#ifndef _SFXTBXCTRL_HXX
#include <sfx2/tbxctrl.hxx>
#endif
#ifndef _SFX_BINDINGS_HXX
#include <sfx2/bindings.hxx>
#endif
#ifndef _SFXDISPATCH_HXX
#include <sfx2/dispatch.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _SFXINTITEM_HXX
#include <svtools/intitem.hxx>
#endif
#ifndef _SOT_EXCHANGE_HXX
#include <sot/exchange.hxx>
#endif
#ifndef _SFXENUMITEM_HXX
#include <svtools/eitem.hxx>
#endif
#ifndef _SV_TOOLBOX_HXX
#include <vcl/toolbox.hxx>
#endif

#ifndef _SVX_CLIPBOARDCTL_HXX_
#include <clipboardctl.hxx>
#endif
#ifndef _SVX_CLIPFMTITEM_HXX
#include <clipfmtitem.hxx>
#endif

#include <svxids.hrc>

/////////////////////////////////////////////////////////////////

SFX_IMPL_TOOLBOX_CONTROL( SvxClipBoardControl, SfxBoolItem /*SfxUInt16Item*/ );

SvxClipBoardControl::SvxClipBoardControl(
        USHORT nId, ToolBox& rTbx, SfxBindings& rBind ) :

    SfxToolBoxControl( nId, rTbx, rBind ),
    pPopup      (0),
    nItemId     (nId)
{
    ToolBox& rBox = GetToolBox();
    rBox.SetItemBits( nId, TIB_DROPDOWN | rBox.GetItemBits( nId ) );
    rBox.Invalidate();
}

SvxClipBoardControl::~SvxClipBoardControl()
{
    DelPopup();
}

SfxPopupWindow* SvxClipBoardControl::CreatePopupWindow()
{
    SfxPoolItem* pState = 0;
    SfxDispatcher &rDispatch = *GetBindings().GetDispatcher();
    SfxItemState eState = rDispatch.QueryState( SID_CLIPBOARD_FORMAT_ITEMS,
                                                pState );
    if (eState >= SFX_ITEM_AVAILABLE  &&  pState)
    {
        if (pPopup)
            pPopup->Clear();
        else
            pPopup = new PopupMenu;

        const SvxClipboardFmtItem &rFmtItem = *(SvxClipboardFmtItem *) pState;
        USHORT nCount = rFmtItem.Count();
        for (USHORT i = 0;  i < nCount;  ++i)
        {
            ULONG nFmtID =  rFmtItem.GetClipbrdFormatId( i );
            String aFmtStr( rFmtItem.GetClipbrdFormatName( i ) );
            if (!aFmtStr.Len())
                aFmtStr = SotExchange::GetFormatName( nFmtID );
            pPopup->InsertItem( (USHORT)nFmtID, aFmtStr );
        }

        ToolBox& rBox = GetToolBox();
        USHORT nId = GetId();
        rBox.SetItemDown( nId, TRUE );

        //Point aPt( rBox.OutputToScreenPixel( rBox.GetPointerPosPixel() ) );
        Point aPt( rBox.OutputToScreenPixel(
                        rBox.GetItemRect( nItemId ).BottomLeft() ) );
        pPopup->Execute( &rBox, rBox.ScreenToOutputPixel( aPt ) );
        rBox.SetItemDown( nId, FALSE );

        SfxUInt32Item aItem( SID_CLIPBOARD_FORMAT_ITEMS, pPopup->GetCurItemId() );
        rDispatch.Execute( SID_CLIPBOARD_FORMAT_ITEMS,
                           SFX_CALLMODE_SYNCHRON, &aItem, 0L );
    }

    GetToolBox().EndSelection();
    DelPopup();
    return 0;
}

SfxPopupWindowType SvxClipBoardControl::GetPopupWindowType() const
{
    return SFX_POPUPWINDOW_ONTIMEOUT;
}

void SvxClipBoardControl::StateChanged(
        USHORT nSID, SfxItemState eState, const SfxPoolItem* pState )
{
    GetToolBox().EnableItem( GetId(), (GetItemState(pState) != SFX_ITEM_DISABLED) );
}

void SvxClipBoardControl::DelPopup()
{
    if(pPopup)
    {
        delete pPopup;
        pPopup = 0;
    }
}

/////////////////////////////////////////////////////////////////

<commit_msg>Corrected to pass lvalue<commit_after>/*************************************************************************
 *
 *  $RCSfile: clipboardctl.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2001-04-10 16:37:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SFXAPP_HXX
#include <sfx2/app.hxx>
#endif
#ifndef _SFXTBXCTRL_HXX
#include <sfx2/tbxctrl.hxx>
#endif
#ifndef _SFX_BINDINGS_HXX
#include <sfx2/bindings.hxx>
#endif
#ifndef _SFXDISPATCH_HXX
#include <sfx2/dispatch.hxx>
#endif
#ifndef _SV_GEN_HXX
#include <tools/gen.hxx>
#endif
#ifndef _SFXINTITEM_HXX
#include <svtools/intitem.hxx>
#endif
#ifndef _SOT_EXCHANGE_HXX
#include <sot/exchange.hxx>
#endif
#ifndef _SFXENUMITEM_HXX
#include <svtools/eitem.hxx>
#endif
#ifndef _SV_TOOLBOX_HXX
#include <vcl/toolbox.hxx>
#endif

#ifndef _SVX_CLIPBOARDCTL_HXX_
#include <clipboardctl.hxx>
#endif
#ifndef _SVX_CLIPFMTITEM_HXX
#include <clipfmtitem.hxx>
#endif

#include <svxids.hrc>

/////////////////////////////////////////////////////////////////

SFX_IMPL_TOOLBOX_CONTROL( SvxClipBoardControl, SfxBoolItem /*SfxUInt16Item*/ );

SvxClipBoardControl::SvxClipBoardControl(
        USHORT nId, ToolBox& rTbx, SfxBindings& rBind ) :

    SfxToolBoxControl( nId, rTbx, rBind ),
    pPopup      (0),
    nItemId     (nId)
{
    ToolBox& rBox = GetToolBox();
    rBox.SetItemBits( nId, TIB_DROPDOWN | rBox.GetItemBits( nId ) );
    rBox.Invalidate();
}

SvxClipBoardControl::~SvxClipBoardControl()
{
    DelPopup();
}

SfxPopupWindow* SvxClipBoardControl::CreatePopupWindow()
{
    const SfxPoolItem* pState = 0;
    SfxDispatcher &rDispatch = *GetBindings().GetDispatcher();
    SfxItemState eState = rDispatch.QueryState( SID_CLIPBOARD_FORMAT_ITEMS,
                                                pState );
    if (eState >= SFX_ITEM_AVAILABLE  &&  pState)
    {
        if (pPopup)
            pPopup->Clear();
        else
            pPopup = new PopupMenu;

        const SvxClipboardFmtItem &rFmtItem = *(SvxClipboardFmtItem *) pState;
        USHORT nCount = rFmtItem.Count();
        for (USHORT i = 0;  i < nCount;  ++i)
        {
            ULONG nFmtID =  rFmtItem.GetClipbrdFormatId( i );
            String aFmtStr( rFmtItem.GetClipbrdFormatName( i ) );
            if (!aFmtStr.Len())
                aFmtStr = SotExchange::GetFormatName( nFmtID );
            pPopup->InsertItem( (USHORT)nFmtID, aFmtStr );
        }

        ToolBox& rBox = GetToolBox();
        USHORT nId = GetId();
        rBox.SetItemDown( nId, TRUE );

        //Point aPt( rBox.OutputToScreenPixel( rBox.GetPointerPosPixel() ) );
        Point aPt( rBox.OutputToScreenPixel(
                        rBox.GetItemRect( nItemId ).BottomLeft() ) );
        pPopup->Execute( &rBox, rBox.ScreenToOutputPixel( aPt ) );
        rBox.SetItemDown( nId, FALSE );

        SfxUInt32Item aItem( SID_CLIPBOARD_FORMAT_ITEMS, pPopup->GetCurItemId() );
        rDispatch.Execute( SID_CLIPBOARD_FORMAT_ITEMS,
                           SFX_CALLMODE_SYNCHRON, &aItem, 0L );
    }

    GetToolBox().EndSelection();
    DelPopup();
    return 0;
}

SfxPopupWindowType SvxClipBoardControl::GetPopupWindowType() const
{
    return SFX_POPUPWINDOW_ONTIMEOUT;
}

void SvxClipBoardControl::StateChanged(
        USHORT nSID, SfxItemState eState, const SfxPoolItem* pState )
{
    GetToolBox().EnableItem( GetId(), (GetItemState(pState) != SFX_ITEM_DISABLED) );
}

void SvxClipBoardControl::DelPopup()
{
    if(pPopup)
    {
        delete pPopup;
        pPopup = 0;
    }
}

/////////////////////////////////////////////////////////////////

<|endoftext|>


<commit_before>#include <monsoon/history/dir/io/replacement_map.h>
#include <memory>

namespace monsoon::history::io {

replacement_map::~replacement_map() noexcept {
  map_.clear_and_dispose([](entry_type* ptr) { delete ptr; });
}

auto replacement_map::read_at(monsoon::io::fd::offset_type off, void* buf, std::size_t& nbytes) const -> std::size_t {
  // Find the first region *after* off.
  auto iter = map_.upper_bound(off);
  assert(iter == map_.end() || iter->first > off);

  // Update nbytes to be clipped at next-region-start.
  if (iter != map_.end() && nbytes > iter->first - off)
    nbytes = iter->first - off;

  // If the first region *after* off is the very first in the list, we can't
  // read anything here.
  if (iter == map_.begin()) return 0;
  // Change iter to point at the at-or-before entry.
  --iter;

  // Validate assertions.
  assert(iter->first <= off);
  // If iter points at a before entry, this read can't be satisfied here.
  if (iter->first + iter->second.size() <= off) return 0;

  // Compute local offset into the *at* entry.
  const std::size_t local_off = off - iter->first;
  // And bytes that we can thus read.
  const std::size_t rlen = std::min(nbytes, std::size_t(iter->second.size() - local_off));
  // Validate our assertions: we must read something unless requested not to read anything.
  assert(rlen > 0 || nbytes == 0);
  // Do the read.
  std::memcpy(buf, iter->second.data() + local_off, rlen);
  return rlen; // Indicate we actually read something.
}

auto replacement_map::write_at(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes, bool overwrite) -> tx {
  if (overwrite)
    return write_at_with_overwrite_(off, buf, nbytes);
  else
    return write_at_without_overwrite_(off, buf, nbytes);
}

auto replacement_map::write_at_from_file(monsoon::io::fd::offset_type off, const monsoon::io::fd& fd, monsoon::io::fd::offset_type fd_off, std::size_t nbytes, bool overwrite) -> tx {
  std::unique_ptr<std::uint8_t[]> buffer{ new std::uint8_t[nbytes] };

  auto fd_nbytes = nbytes;
  std::uint8_t* buffer_pos = buffer.get();
  while (fd_nbytes > 0) {
    const auto rlen = fd.read_at(fd_off, buffer_pos, fd_nbytes);
    buffer_pos += rlen;
    fd_off += rlen;
    fd_nbytes -= rlen;
  }

  return write_at(off, buffer.get(), nbytes, overwrite);
}

auto replacement_map::write_at_with_overwrite_(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes) -> tx {
  const monsoon::io::fd::offset_type end_off = off + nbytes;
  if (end_off < off) throw std::overflow_error("replacement_map: off + nbytes");

  tx t;
  t.map_ = &map_;
  std::size_t bytes_from_pred = 0, bytes_from_succ = 0;

  // Find the first region *after* off.
  map_type::iterator succ = map_.upper_bound(off);
  assert(succ == map_.end() || succ->first > off);

  // Find the region at-or-before off.
  const map_type::iterator pred = (succ == map_.begin() ? map_.end() : std::prev(succ));
  assert(pred == map_.end() || pred->first <= off);

  // We may need to include some bytes from pred.
  if (pred != map_.end() && pred->end_offset() > off) {
    t.to_erase_.push_back(pred);
    bytes_from_pred = off - pred->first;
  }

  // Mark any full-replaced entries as to-be-erased.
  // Move succ forward until it's the first not-fully-replaced entry after off.
  while (succ != map_.end() && succ->end_offset() <= end_off)
    t.to_erase_.push_back(succ++);

  // We may need to include bytes from succ.
  if (succ != map_.end() && succ->first < end_off) {
    t.to_erase_.push_back(succ);
    bytes_from_succ = succ->end_offset() - end_off;
  }

  // Reserve at least some bytes into the vector.
  vector_type vector;
  const std::uint8_t* pred_buf = pred->second.data();
  const std::uint8_t* byte_buf = reinterpret_cast<const std::uint8_t*>(buf);
  const std::uint8_t* succ_buf = succ->second.data() + succ->second.size() - bytes_from_succ;
  while (bytes_from_succ > 0 || nbytes > 0 || bytes_from_pred > 0) {
    const std::size_t Max = vector.max_size();
    std::size_t to_reserve = bytes_from_pred;
    if (Max - to_reserve < nbytes) // overflow case
      to_reserve = Max;
    else
      to_reserve += nbytes;
    if (Max - to_reserve < bytes_from_succ) // overflow case
      to_reserve = Max;
    else
      to_reserve += nbytes;

    for (;;) {
      try {
        vector.resize(to_reserve);
        break;
      } catch (...) {
        if (to_reserve <= 1) throw;
        to_reserve /= 2;
      }
    }

    std::size_t wlen, written = 0;
    vector_type::iterator vector_pos = vector.begin();

    wlen = std::min(bytes_from_pred, to_reserve);
    vector_pos = std::copy_n(pred_buf, wlen, vector_pos);
    bytes_from_pred -= wlen;
    pred_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    wlen = std::min(nbytes, to_reserve);
    vector_pos = std::copy_n(byte_buf, wlen, vector_pos);
    nbytes -= wlen;
    byte_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    wlen = std::min(bytes_from_succ, to_reserve);
    vector_pos = std::copy_n(byte_buf, wlen, vector_pos);
    bytes_from_succ -= wlen;
    succ_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    assert(vector_pos == vector.end());
    t.to_insert_.emplace_back(std::make_unique<entry_type>(off, std::move(vector)));
    off += written;
  }

  return t;
}

auto replacement_map::write_at_without_overwrite_(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes) -> tx {
  const monsoon::io::fd::offset_type end_off = off + nbytes;
  if (end_off < off) throw std::overflow_error("replacement_map: off + nbytes");

  tx t;
  t.map_ = &map_;

  /* We only write in the gaps, so we position 'iter' and 'iter_succ' such that
   * they are the delimiters of the first gap at/after 'off'.
   */
  while (off < end_off) {
    // Find the first region *after* off.
    const map_type::iterator succ = map_.upper_bound(off);
    assert(succ == map_.end() || succ->first > off);

    // Find the region at-or-before off.
    map_type::iterator iter = (succ == map_.begin() ? map_.end() : std::prev(succ));
    assert(iter == map_.end() || iter->first <= off);
    if (iter != map_.end() && iter->end_offset() >= end_off) break; // GUARD: stop if there are no intersecting gaps.
    assert(iter->end_offset() < end_off);

    if (iter != map_.end() && iter->end_offset() > off) {
      const monsoon::io::fd::offset_type skip = iter->end_offset() - off;
      off += skip;
      buf = reinterpret_cast<const std::uint8_t*>(buf) + skip;
    }
    assert(iter == map_.end() || iter->end_offset() <= off);

    map_type::iterator iter_succ = (iter == map_.end() ? map_.end() : std::next(iter));
    if (iter_succ->first >= end_off) iter_succ = map_.end();
    assert(iter_succ == map_.end() || iter_succ->first > off);

    monsoon::io::fd::offset_type write_end_off = (iter_succ == map_.end() ? end_off : iter_succ->first);
    assert(write_end_off <= end_off);

    while (off < write_end_off) {
      vector_type vector;
      vector_type::size_type to_reserve = vector.max_size();
      if (to_reserve > write_end_off - off) to_reserve = write_end_off - off;
      for (;;) {
        try {
          vector.reserve(to_reserve);
          break;
        } catch (const std::bad_alloc&) {
          if (to_reserve <= 1u) throw;
          to_reserve /= 2u;
        }
      }

      std::copy_n(reinterpret_cast<const std::uint8_t*>(buf), to_reserve, std::back_inserter(vector));
      t.to_insert_.emplace_back(std::make_unique<entry_type>(off, std::move(vector)));
      off += to_reserve;
      buf = reinterpret_cast<const std::uint8_t*>(buf) + to_reserve;
    }

    assert(off == write_end_off);
    iter = std::move(iter_succ);
  }

  return t;
}

replacement_map::tx::~tx() noexcept = default;

void replacement_map::tx::commit() noexcept {
  assert(map_ != nullptr);

  std::for_each(
      std::move_iterator(to_erase_.begin()),
      std::move_iterator(to_erase_.end()),
      [this](map_type::iterator&& iter) {
        map_->erase_and_dispose(iter, [](entry_type* ptr) { delete ptr; });
      });

  std::for_each(
      std::move_iterator(to_insert_.begin()),
      std::move_iterator(to_insert_.end()),
      [this](std::unique_ptr<entry_type>&& entry) {
        bool inserted = false;
        map_type::iterator ipos;
        std::tie(ipos, inserted) = map_->insert(*entry);
        assert(inserted);
        entry.release();

        // Assert the inserted element causes no overlap.
        assert(ipos == map_->begin() || std::prev(ipos)->end_offset() <= ipos->first);
        assert(std::next(ipos) == map_->end() || std::next(ipos)->first >= ipos->end_offset());
      });

  map_ = nullptr;
  to_erase_.clear();
  to_insert_.clear();
}

} /* namespace monsoon::history::io */
<commit_msg>Use make_unique instead of new.<commit_after>#include <monsoon/history/dir/io/replacement_map.h>
#include <memory>

namespace monsoon::history::io {

replacement_map::~replacement_map() noexcept {
  map_.clear_and_dispose([](entry_type* ptr) { delete ptr; });
}

auto replacement_map::read_at(monsoon::io::fd::offset_type off, void* buf, std::size_t& nbytes) const -> std::size_t {
  // Find the first region *after* off.
  auto iter = map_.upper_bound(off);
  assert(iter == map_.end() || iter->first > off);

  // Update nbytes to be clipped at next-region-start.
  if (iter != map_.end() && nbytes > iter->first - off)
    nbytes = iter->first - off;

  // If the first region *after* off is the very first in the list, we can't
  // read anything here.
  if (iter == map_.begin()) return 0;
  // Change iter to point at the at-or-before entry.
  --iter;

  // Validate assertions.
  assert(iter->first <= off);
  // If iter points at a before entry, this read can't be satisfied here.
  if (iter->first + iter->second.size() <= off) return 0;

  // Compute local offset into the *at* entry.
  const std::size_t local_off = off - iter->first;
  // And bytes that we can thus read.
  const std::size_t rlen = std::min(nbytes, std::size_t(iter->second.size() - local_off));
  // Validate our assertions: we must read something unless requested not to read anything.
  assert(rlen > 0 || nbytes == 0);
  // Do the read.
  std::memcpy(buf, iter->second.data() + local_off, rlen);
  return rlen; // Indicate we actually read something.
}

auto replacement_map::write_at(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes, bool overwrite) -> tx {
  if (overwrite)
    return write_at_with_overwrite_(off, buf, nbytes);
  else
    return write_at_without_overwrite_(off, buf, nbytes);
}

auto replacement_map::write_at_from_file(monsoon::io::fd::offset_type off, const monsoon::io::fd& fd, monsoon::io::fd::offset_type fd_off, std::size_t nbytes, bool overwrite) -> tx {
  auto buffer = std::make_unique<std::uint8_t[]>(nbytes);

  auto fd_nbytes = nbytes;
  std::uint8_t* buffer_pos = buffer.get();
  while (fd_nbytes > 0) {
    const auto rlen = fd.read_at(fd_off, buffer_pos, fd_nbytes);
    buffer_pos += rlen;
    fd_off += rlen;
    fd_nbytes -= rlen;
  }

  return write_at(off, buffer.get(), nbytes, overwrite);
}

auto replacement_map::write_at_with_overwrite_(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes) -> tx {
  const monsoon::io::fd::offset_type end_off = off + nbytes;
  if (end_off < off) throw std::overflow_error("replacement_map: off + nbytes");

  tx t;
  t.map_ = &map_;
  std::size_t bytes_from_pred = 0, bytes_from_succ = 0;

  // Find the first region *after* off.
  map_type::iterator succ = map_.upper_bound(off);
  assert(succ == map_.end() || succ->first > off);

  // Find the region at-or-before off.
  const map_type::iterator pred = (succ == map_.begin() ? map_.end() : std::prev(succ));
  assert(pred == map_.end() || pred->first <= off);

  // We may need to include some bytes from pred.
  if (pred != map_.end() && pred->end_offset() > off) {
    t.to_erase_.push_back(pred);
    bytes_from_pred = off - pred->first;
  }

  // Mark any full-replaced entries as to-be-erased.
  // Move succ forward until it's the first not-fully-replaced entry after off.
  while (succ != map_.end() && succ->end_offset() <= end_off)
    t.to_erase_.push_back(succ++);

  // We may need to include bytes from succ.
  if (succ != map_.end() && succ->first < end_off) {
    t.to_erase_.push_back(succ);
    bytes_from_succ = succ->end_offset() - end_off;
  }

  // Reserve at least some bytes into the vector.
  vector_type vector;
  const std::uint8_t* pred_buf = pred->second.data();
  const std::uint8_t* byte_buf = reinterpret_cast<const std::uint8_t*>(buf);
  const std::uint8_t* succ_buf = succ->second.data() + succ->second.size() - bytes_from_succ;
  while (bytes_from_succ > 0 || nbytes > 0 || bytes_from_pred > 0) {
    const std::size_t Max = vector.max_size();
    std::size_t to_reserve = bytes_from_pred;
    if (Max - to_reserve < nbytes) // overflow case
      to_reserve = Max;
    else
      to_reserve += nbytes;
    if (Max - to_reserve < bytes_from_succ) // overflow case
      to_reserve = Max;
    else
      to_reserve += nbytes;

    for (;;) {
      try {
        vector.resize(to_reserve);
        break;
      } catch (...) {
        if (to_reserve <= 1) throw;
        to_reserve /= 2;
      }
    }

    std::size_t wlen, written = 0;
    vector_type::iterator vector_pos = vector.begin();

    wlen = std::min(bytes_from_pred, to_reserve);
    vector_pos = std::copy_n(pred_buf, wlen, vector_pos);
    bytes_from_pred -= wlen;
    pred_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    wlen = std::min(nbytes, to_reserve);
    vector_pos = std::copy_n(byte_buf, wlen, vector_pos);
    nbytes -= wlen;
    byte_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    wlen = std::min(bytes_from_succ, to_reserve);
    vector_pos = std::copy_n(byte_buf, wlen, vector_pos);
    bytes_from_succ -= wlen;
    succ_buf += wlen;
    to_reserve -= wlen;
    written += wlen;

    assert(vector_pos == vector.end());
    t.to_insert_.emplace_back(std::make_unique<entry_type>(off, std::move(vector)));
    off += written;
  }

  return t;
}

auto replacement_map::write_at_without_overwrite_(monsoon::io::fd::offset_type off, const void* buf, std::size_t nbytes) -> tx {
  const monsoon::io::fd::offset_type end_off = off + nbytes;
  if (end_off < off) throw std::overflow_error("replacement_map: off + nbytes");

  tx t;
  t.map_ = &map_;

  /* We only write in the gaps, so we position 'iter' and 'iter_succ' such that
   * they are the delimiters of the first gap at/after 'off'.
   */
  while (off < end_off) {
    // Find the first region *after* off.
    const map_type::iterator succ = map_.upper_bound(off);
    assert(succ == map_.end() || succ->first > off);

    // Find the region at-or-before off.
    map_type::iterator iter = (succ == map_.begin() ? map_.end() : std::prev(succ));
    assert(iter == map_.end() || iter->first <= off);
    if (iter != map_.end() && iter->end_offset() >= end_off) break; // GUARD: stop if there are no intersecting gaps.
    assert(iter->end_offset() < end_off);

    if (iter != map_.end() && iter->end_offset() > off) {
      const monsoon::io::fd::offset_type skip = iter->end_offset() - off;
      off += skip;
      buf = reinterpret_cast<const std::uint8_t*>(buf) + skip;
    }
    assert(iter == map_.end() || iter->end_offset() <= off);

    map_type::iterator iter_succ = (iter == map_.end() ? map_.end() : std::next(iter));
    if (iter_succ->first >= end_off) iter_succ = map_.end();
    assert(iter_succ == map_.end() || iter_succ->first > off);

    monsoon::io::fd::offset_type write_end_off = (iter_succ == map_.end() ? end_off : iter_succ->first);
    assert(write_end_off <= end_off);

    while (off < write_end_off) {
      vector_type vector;
      vector_type::size_type to_reserve = vector.max_size();
      if (to_reserve > write_end_off - off) to_reserve = write_end_off - off;
      for (;;) {
        try {
          vector.reserve(to_reserve);
          break;
        } catch (const std::bad_alloc&) {
          if (to_reserve <= 1u) throw;
          to_reserve /= 2u;
        }
      }

      std::copy_n(reinterpret_cast<const std::uint8_t*>(buf), to_reserve, std::back_inserter(vector));
      t.to_insert_.emplace_back(std::make_unique<entry_type>(off, std::move(vector)));
      off += to_reserve;
      buf = reinterpret_cast<const std::uint8_t*>(buf) + to_reserve;
    }

    assert(off == write_end_off);
    iter = std::move(iter_succ);
  }

  return t;
}

replacement_map::tx::~tx() noexcept = default;

void replacement_map::tx::commit() noexcept {
  assert(map_ != nullptr);

  std::for_each(
      std::move_iterator(to_erase_.begin()),
      std::move_iterator(to_erase_.end()),
      [this](map_type::iterator&& iter) {
        map_->erase_and_dispose(iter, [](entry_type* ptr) { delete ptr; });
      });

  std::for_each(
      std::move_iterator(to_insert_.begin()),
      std::move_iterator(to_insert_.end()),
      [this](std::unique_ptr<entry_type>&& entry) {
        bool inserted = false;
        map_type::iterator ipos;
        std::tie(ipos, inserted) = map_->insert(*entry);
        assert(inserted);
        entry.release();

        // Assert the inserted element causes no overlap.
        assert(ipos == map_->begin() || std::prev(ipos)->end_offset() <= ipos->first);
        assert(std::next(ipos) == map_->end() || std::next(ipos)->first >= ipos->end_offset());
      });

  map_ = nullptr;
  to_erase_.clear();
  to_insert_.clear();
}

} /* namespace monsoon::history::io */
<|endoftext|>


<commit_before><commit_msg>Notify race detectors (e.g. ThreadSanitizer) about the thread names ThreadSanitizer will print the name of the threads in data race reports.<commit_after><|endoftext|>