<commit_before>
#include "Expression.h"
#include "Tokenizer.h"
#include "Document.h"
#include "Editor.h"
#include "Log.h"
#include "Tcl.h"

#include <unordered_map>
#include <stack>

enum class Function
{
  Sum,
  Min,
  Max
};

enum class Operator
{
  Range,
  Multiply,
  Divide,
  Add,
  Subtract
};

static const std::unordered_map<std::string, std::tuple<uint32_t, Operator>> operatorTable_ = {
  { ":",  std::make_tuple(5, Operator::Range) },
  { "*",  std::make_tuple(4, Operator::Multiply) },
  { "/",  std::make_tuple(3, Operator::Divide) },
  { "+",  std::make_tuple(1, Operator::Add) },
  { "-",  std::make_tuple(1, Operator::Subtract) }
};

static const std::unordered_map<std::string, Function> functionTable_ = {
  { "SUM", Function::Sum },
  { "MIN", Function::Min },
  { "MAX", Function::Max }
};

std::string Expr::toStr() const
{
  switch (type_)
  {
    case Expr::Constant:
      return str::fromDouble(constant_);

    case Expr::Operator:
      return "Operator(" + str::fromInt(id_) + ")";

    case Expr::Function:
      return "Function(" + str::fromInt(id_) + ")";

    case Expr::Cell:
      return index_.toStr();
  }
}

double Expr::toDouble() const
{
  switch (type_)
  {
    case Expr::Constant:
      return constant_;

    case Expr::Cell:
      return doc::getCellValue(index_);

    default:
      return 0.0;
  }
}

static std::string stringExpr(std::vector<Expr> const& output)
{
  std::string result;
  for (auto const& expr : output)
    result += expr.toStr() + " ";
  return result;
}

static void printExpr(std::vector<Expr> const& output)
{
  const std::string result = "Output: " + stringExpr(output);

  logInfo(result);
  flashMessage(result);
}

static std::string tokenName(Token token)
{
  switch (token)
  {
    case Token::Number:
      return "Number";

    case Token::Cell:
      return "Cell";

    case Token::Operator:
      return "Operator";

    case Token::Identifier:
      return "Identifier";

    case Token::LeftParenthesis:
      return "LeftParenthesis";

    case Token::RightParenthesis:
      return "RightParenthesis";

    case Token::Comma:
      return "Comma";
  }

  return "Unknown";
}

static void printStack(std::vector<std::tuple<Token, std::string>> const& stack)
{
  std::string result = "Stack: ";
  for (auto const& value : stack)
    result += tokenName(std::get<0>(value)) + "(" + std::get<1>(value) + ") ";

  logInfo(result);
  flashMessage(result);
}

std::vector<Expr> parseExpression(std::string const& source)
{
  std::vector<Expr> output;

  std::vector<std::tuple<Token, std::string>> operatorStack;

  Tokenizer tokenizer(source);

  bool cont = true;
  while (cont && !tokenizer.eof())
  {
    Token token = tokenizer.next();

    switch (token)
    {
      case Token::Number:
        output.push_back(Expr(std::stof(tokenizer.value().c_str())));
        break;

      case Token::Cell:
        output.push_back(Expr(Index::fromStr(tokenizer.value())));
        break;

      case Token::Operator:
        {
          const int tokenPrecedence = std::get<0>(operatorTable_.at(tokenizer.value()));

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken != Token::Operator)
              break;

            int stackPrecedence;
            Operator stackOperator;
            std::tie(stackPrecedence, stackOperator) = operatorTable_.at(opValue);

            if (tokenPrecedence <= stackPrecedence)
            {
              output.push_back(Expr(Expr::Operator, (uint32_t)stackOperator));
              operatorStack.pop_back();
            }
            else
              break;
          }

          operatorStack.push_back(std::make_tuple(Token::Operator, tokenizer.value()));
        }
        break;

      case Token::Identifier:
        {
          if (functionTable_.count(tokenizer.value()) == 1)
          {
            operatorStack.push_back(std::make_tuple(Token::Identifier, tokenizer.value()));
          }
          else
          {
            logError("unknown function in expression '", source, "' - ", tokenizer.value());
            return {};
          }
        }
        break;

      case Token::LeftParenthesis:
        operatorStack.push_back(std::make_tuple(Token::LeftParenthesis, ""));
        break;

      case Token::RightParenthesis:
        {
          bool hasLeftParenthesis = false;

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();
            operatorStack.pop_back();

            if (opToken == Token::LeftParenthesis)
            {
              hasLeftParenthesis = true;
              break;
            }

            if (opToken != Token::Operator)
            {
              logError("parse error in expression '", source, "' - expected operator");
              return {};
            }

            output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
          }

          if (!hasLeftParenthesis)
          {
            logError("parse error in expression '", source, "' - missing start parenthesis");
            return {};
          }

          if (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken == Token::Identifier)
            {
              output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
              operatorStack.pop_back();
            }
          }
        }
        break;

      case Token::Comma:
        {
          bool foundLeftParenthesis = false;

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken == Token::LeftParenthesis)
            {
              foundLeftParenthesis = true;
              break;
            }

            operatorStack.pop_back();

            switch (opToken)
            {
              case Token::Operator:
                output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
                break;

              case Token::Identifier:
                output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
                break;

              default:
                logError("error in expression '", source, "' - did not expect ", opValue);
                return {};
            }
          }

          if (!foundLeftParenthesis)
          {
            logError("error in expression '", source, "' - missplaced parenthesis or comma");
            return {};
          }
        }
        break;

      case Token::EndOfFile:
        cont = false;
        break;

      case Token::Error:
        logError("parse error in expression '", source, "' - ", tokenizer.value());
        return {};
    };
  }

  while (!operatorStack.empty())
  {
    Token opToken;
    std::string opValue;
    std::tie(opToken, opValue) = operatorStack.back();
    operatorStack.pop_back();

    switch (opToken)
    {
      case Token::Operator:
        output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
        break;

      case Token::Identifier:
        output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
        break;

      case Token::LeftParenthesis:
        logError("parse error in expression '", source, "' - missing closing parenthesis");
        return {};

      default:
        logError("error in expression '", source, "' - did not expect ", opValue);
        return {};
    }
  }

  printExpr(output);

  return output;
}

Expr popExpr(std::vector<Expr> & valueStack)
{
  Expr expr = valueStack.back();
  valueStack.pop_back();
  return expr;
}

bool execOperator(std::vector<Expr> & valueStack, Operator op)
{
  const double b = popExpr(valueStack).toDouble();
  const double a = popExpr(valueStack).toDouble();

  switch (op)
  {
    case Operator::Multiply:
      valueStack.push_back(a * b);
      break;

    case Operator::Divide:
      valueStack.push_back(a / b);
      break;

    case Operator::Add:
      valueStack.push_back(a + b);
      break;

    case Operator::Subtract:
      valueStack.push_back(a - b);
      break;

    default:
      return false;
  }

  return true;
}

bool execFunction(std::vector<Expr> & valueStack, Function func)
{
  switch (func)
  {
    case Function::Sum:
      {
        if (valueStack.size() < 3)
        {
          logError("wrong number of arguments to SUM(range)");
          return false;
        }

        const Expr rangeOp = popExpr(valueStack);
        if (rangeOp.type_ != Expr::Operator || rangeOp.id_ != (uint32_t)Operator::Range)
        {
          logError("sum function expected range argument");
          return false;
        }

        const Expr endExpr = popExpr(valueStack);
        const Expr startExpr = popExpr(valueStack);

        if (startExpr.type_ != Expr::Cell || endExpr.type_ != Expr::Cell)
        {
          logError("invalid range, two cell references expected");
          return false;
        }

        Index const& startIdx = startExpr.index_;
        Index const& endIdx = endExpr.index_;

        if (startIdx.x > endIdx.x || startIdx.y > endIdx.y)
        {
          logError("invalid range, row and column in start index ", startIdx.toStr(), " must be less than end index ", endIdx.toStr());
          return false;
        }

        double sum = 0.0;
        for (int y = startIdx.y; y <= endIdx.y; ++y)
          for (int x = startIdx.x; x <= endIdx.x; ++x)
            sum += doc::getCellValue(Index(x, y));

        valueStack.push_back(sum);
      }
      break;

    case Function::Min:
      {
        if (valueStack.size() < 2)
        {
          logError("wrong number of arguments to MIN(a, b)");
          return false;
        }

        const double b = popExpr(valueStack).toDouble();
        const double a = popExpr(valueStack).toDouble();

        valueStack.push_back(std::min(a, b));
      }
      break;

    case Function::Max:
      {
        if (valueStack.size() < 2)
        {
          logError("wrong number of arguments to MAX(a, b)");
          return false;
        }

        const double b = popExpr(valueStack).toDouble();
        const double a = popExpr(valueStack).toDouble();

        valueStack.push_back(std::max(a, b));
      }
      break;
  }

  return true;
}

double evaluate(std::vector<Expr> const& expression)
{
  std::vector<Expr> valueStack;
  valueStack.reserve(expression.size());

  for (auto const& expr : expression)
  {
    switch (expr.type_)
    {
      case Expr::Constant:
      case Expr::Cell:
        valueStack.push_back(expr);
        break;

      case Expr::Operator:
        {
          if (expr.id_ == (uint32_t)Operator::Range)
          {
            valueStack.push_back(expr);
          }
          else
          {
            if (!execOperator(valueStack, (Operator)expr.id_))
              return 0.0f;
          }
        }
        break;

      case Expr::Function:
        {
          if (!execFunction(valueStack, (Function)expr.id_))
            return 0.0;
        }
        break;
    }
  }

  if (valueStack.size() != 1)
  {
    logError("error while calculating expression '", stringExpr(expression));
    return 0.0;
  }

  return valueStack.front().toDouble();
}

TCL_FUNC(calculate, "string ?string ...?")
{
  TCL_CHECK_ARGS(2, 1000);

  std::string expressionString;
  for (uint32_t i = 1; i < argc; ++i)
    expressionString += Jim_String(argv[i]) + std::string(" ");

  const std::vector<Expr> expr = parseExpression(expressionString);

  if (expr.empty())
    return JIM_ERR;

  const double result = evaluate(expr);
  TCL_DOUBLE_RESULT(result);
}
<commit_msg>Added documentation<commit_after>
#include "Expression.h"
#include "Tokenizer.h"
#include "Document.h"
#include "Editor.h"
#include "Log.h"
#include "Tcl.h"

#include <unordered_map>
#include <stack>

enum class Function
{
  Sum,
  Min,
  Max
};

enum class Operator
{
  Range,
  Multiply,
  Divide,
  Add,
  Subtract
};

static const std::unordered_map<std::string, std::tuple<uint32_t, Operator>> operatorTable_ = {
  { ":",  std::make_tuple(5, Operator::Range) },
  { "*",  std::make_tuple(4, Operator::Multiply) },
  { "/",  std::make_tuple(3, Operator::Divide) },
  { "+",  std::make_tuple(1, Operator::Add) },
  { "-",  std::make_tuple(1, Operator::Subtract) }
};

static const std::unordered_map<std::string, Function> functionTable_ = {
  { "SUM", Function::Sum },
  { "MIN", Function::Min },
  { "MAX", Function::Max }
};

std::string Expr::toStr() const
{
  switch (type_)
  {
    case Expr::Constant:
      return str::fromDouble(constant_);

    case Expr::Operator:
      return "Operator(" + str::fromInt(id_) + ")";

    case Expr::Function:
      return "Function(" + str::fromInt(id_) + ")";

    case Expr::Cell:
      return index_.toStr();
  }
}

double Expr::toDouble() const
{
  switch (type_)
  {
    case Expr::Constant:
      return constant_;

    case Expr::Cell:
      return doc::getCellValue(index_);

    default:
      return 0.0;
  }
}

static std::string stringExpr(std::vector<Expr> const& output)
{
  std::string result;
  for (auto const& expr : output)
    result += expr.toStr() + " ";
  return result;
}

static void printExpr(std::vector<Expr> const& output)
{
  const std::string result = "Output: " + stringExpr(output);

  logInfo(result);
  flashMessage(result);
}

static std::string tokenName(Token token)
{
  switch (token)
  {
    case Token::Number:
      return "Number";

    case Token::Cell:
      return "Cell";

    case Token::Operator:
      return "Operator";

    case Token::Identifier:
      return "Identifier";

    case Token::LeftParenthesis:
      return "LeftParenthesis";

    case Token::RightParenthesis:
      return "RightParenthesis";

    case Token::Comma:
      return "Comma";
  }

  return "Unknown";
}

static void printStack(std::vector<std::tuple<Token, std::string>> const& stack)
{
  std::string result = "Stack: ";
  for (auto const& value : stack)
    result += tokenName(std::get<0>(value)) + "(" + std::get<1>(value) + ") ";

  logInfo(result);
  flashMessage(result);
}

std::vector<Expr> parseExpression(std::string const& source)
{
  std::vector<Expr> output;

  std::vector<std::tuple<Token, std::string>> operatorStack;
  operatorStack.reserve(10);

  Tokenizer tokenizer(source);

  bool cont = true;
  while (cont && !tokenizer.eof())
  {
    Token token = tokenizer.next();

    switch (token)
    {
      case Token::Number:
        output.push_back(Expr(std::stof(tokenizer.value().c_str())));
        break;

      case Token::Cell:
        output.push_back(Expr(Index::fromStr(tokenizer.value())));
        break;

      case Token::Operator:
        {
          const int tokenPrecedence = std::get<0>(operatorTable_.at(tokenizer.value()));

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken != Token::Operator)
              break;

            int stackPrecedence;
            Operator stackOperator;
            std::tie(stackPrecedence, stackOperator) = operatorTable_.at(opValue);

            if (tokenPrecedence <= stackPrecedence)
            {
              output.push_back(Expr(Expr::Operator, (uint32_t)stackOperator));
              operatorStack.pop_back();
            }
            else
              break;
          }

          operatorStack.push_back(std::make_tuple(Token::Operator, tokenizer.value()));
        }
        break;

      case Token::Identifier:
        {
          if (functionTable_.count(tokenizer.value()) == 1)
          {
            operatorStack.push_back(std::make_tuple(Token::Identifier, tokenizer.value()));
          }
          else
          {
            logError("unknown function in expression '", source, "' - ", tokenizer.value());
            return {};
          }
        }
        break;

      case Token::LeftParenthesis:
        operatorStack.push_back(std::make_tuple(Token::LeftParenthesis, ""));
        break;

      case Token::RightParenthesis:
        {
          bool hasLeftParenthesis = false;

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();
            operatorStack.pop_back();

            if (opToken == Token::LeftParenthesis)
            {
              hasLeftParenthesis = true;
              break;
            }

            if (opToken != Token::Operator)
            {
              logError("parse error in expression '", source, "' - expected operator");
              return {};
            }

            output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
          }

          if (!hasLeftParenthesis)
          {
            logError("parse error in expression '", source, "' - missing start parenthesis");
            return {};
          }

          if (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken == Token::Identifier)
            {
              output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
              operatorStack.pop_back();
            }
          }
        }
        break;

      case Token::Comma:
        {
          bool foundLeftParenthesis = false;

          while (!operatorStack.empty())
          {
            Token opToken;
            std::string opValue;
            std::tie(opToken, opValue) = operatorStack.back();

            if (opToken == Token::LeftParenthesis)
            {
              foundLeftParenthesis = true;
              break;
            }

            operatorStack.pop_back();

            switch (opToken)
            {
              case Token::Operator:
                output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
                break;

              case Token::Identifier:
                output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
                break;

              default:
                logError("error in expression '", source, "' - did not expect ", opValue);
                return {};
            }
          }

          if (!foundLeftParenthesis)
          {
            logError("error in expression '", source, "' - missplaced parenthesis or comma");
            return {};
          }
        }
        break;

      case Token::EndOfFile:
        cont = false;
        break;

      case Token::Error:
        logError("parse error in expression '", source, "' - ", tokenizer.value());
        return {};
    };
  }

  while (!operatorStack.empty())
  {
    Token opToken;
    std::string opValue;
    std::tie(opToken, opValue) = operatorStack.back();
    operatorStack.pop_back();

    switch (opToken)
    {
      case Token::Operator:
        output.push_back(Expr(Expr::Operator, (uint32_t)std::get<1>(operatorTable_.at(opValue))));
        break;

      case Token::Identifier:
        output.push_back(Expr(Expr::Function, (uint32_t)functionTable_.at(opValue)));
        break;

      case Token::LeftParenthesis:
        logError("parse error in expression '", source, "' - missing closing parenthesis");
        return {};

      default:
        logError("error in expression '", source, "' - did not expect ", opValue);
        return {};
    }
  }

  printExpr(output);

  return output;
}

Expr popExpr(std::vector<Expr> & valueStack)
{
  Expr expr = valueStack.back();
  valueStack.pop_back();
  return expr;
}

bool execOperator(std::vector<Expr> & valueStack, Operator op)
{
  const double b = popExpr(valueStack).toDouble();
  const double a = popExpr(valueStack).toDouble();

  switch (op)
  {
    case Operator::Multiply:
      valueStack.push_back(a * b);
      break;

    case Operator::Divide:
      valueStack.push_back(a / b);
      break;

    case Operator::Add:
      valueStack.push_back(a + b);
      break;

    case Operator::Subtract:
      valueStack.push_back(a - b);
      break;

    default:
      return false;
  }

  return true;
}

bool execFunction(std::vector<Expr> & valueStack, Function func)
{
  switch (func)
  {
    case Function::Sum:
      {
        if (valueStack.size() < 3)
        {
          logError("wrong number of arguments to SUM(range)");
          return false;
        }

        const Expr rangeOp = popExpr(valueStack);
        if (rangeOp.type_ != Expr::Operator || rangeOp.id_ != (uint32_t)Operator::Range)
        {
          logError("sum function expected range argument");
          return false;
        }

        const Expr endExpr = popExpr(valueStack);
        const Expr startExpr = popExpr(valueStack);

        if (startExpr.type_ != Expr::Cell || endExpr.type_ != Expr::Cell)
        {
          logError("invalid range, two cell references expected");
          return false;
        }

        Index const& startIdx = startExpr.index_;
        Index const& endIdx = endExpr.index_;

        if (startIdx.x > endIdx.x || startIdx.y > endIdx.y)
        {
          logError("invalid range, row and column in start index ", startIdx.toStr(), " must be less than end index ", endIdx.toStr());
          return false;
        }

        double sum = 0.0;
        for (int y = startIdx.y; y <= endIdx.y; ++y)
          for (int x = startIdx.x; x <= endIdx.x; ++x)
            sum += doc::getCellValue(Index(x, y));

        valueStack.push_back(sum);
      }
      break;

    case Function::Min:
      {
        if (valueStack.size() < 2)
        {
          logError("wrong number of arguments to MIN(a, b)");
          return false;
        }

        const double b = popExpr(valueStack).toDouble();
        const double a = popExpr(valueStack).toDouble();

        valueStack.push_back(std::min(a, b));
      }
      break;

    case Function::Max:
      {
        if (valueStack.size() < 2)
        {
          logError("wrong number of arguments to MAX(a, b)");
          return false;
        }

        const double b = popExpr(valueStack).toDouble();
        const double a = popExpr(valueStack).toDouble();

        valueStack.push_back(std::max(a, b));
      }
      break;
  }

  return true;
}

double evaluate(std::vector<Expr> const& expression)
{
  std::vector<Expr> valueStack;
  valueStack.reserve(expression.size());

  for (auto const& expr : expression)
  {
    switch (expr.type_)
    {
      case Expr::Constant:
      case Expr::Cell:
        valueStack.push_back(expr);
        break;

      case Expr::Operator:
        {
          if (expr.id_ == (uint32_t)Operator::Range)
          {
            valueStack.push_back(expr);
          }
          else
          {
            if (!execOperator(valueStack, (Operator)expr.id_))
              return 0.0f;
          }
        }
        break;

      case Expr::Function:
        {
          if (!execFunction(valueStack, (Function)expr.id_))
            return 0.0;
        }
        break;
    }
  }

  if (valueStack.size() != 1)
  {
    logError("error while calculating expression '", stringExpr(expression));
    return 0.0;
  }

  return valueStack.front().toDouble();
}

TCL_FUNC(calculate, "string ?string ...?", "Evaluates the given expression in the same way a cell that starts with = is evaluated")
{
  TCL_CHECK_ARGS(2, 1000);

  std::string expressionString;
  for (uint32_t i = 1; i < argc; ++i)
    expressionString += Jim_String(argv[i]) + std::string(" ");

  const std::vector<Expr> expr = parseExpression(expressionString);

  if (expr.empty())
    return JIM_ERR;

  const double result = evaluate(expr);
  TCL_DOUBLE_RESULT(result);
}
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include "GameEngine.h"
#include "GameData.h"
#include "EntityContainer.h"
#include "RenderData.h"
#include "Timer.h"
#include "DeltatimeMonitor.h"
#include "VirtualGameStateController.h"

namespace flat2d
{
	void GameEngine::init(int screenWidth, int screenHeight, int fps)
	{
		this->screenWidth = screenWidth;
		this->screenHeight = screenHeight;
		this->screenFps = fps;
		this->screenTicksPerFrame = 1000 / fps;
	}

	void GameEngine::run(VirtualGameStateController *gameStateController) const
	{
		SDL_Renderer *renderer = gameData->getRenderData()->getRenderer();
		EntityContainer *entityContainer = gameData->getEntityContainer();

		Timer fpsTimer;
		Timer drawFpsTimer;

		fpsTimer.start();
		drawFpsTimer.start();

		// Loop stuff
		flat2d::Timer fpsCapTimer;;
		SDL_Event e;
		bool quit = false;

		// Main loop
		gameData->getDeltatimeMonitor()->updateDeltaTime();
		while (!quit) {
			fpsCapTimer.start();
			gameData->getDeltatimeMonitor()->updateDeltaTime();

			if (gameStateController) {
				quit = gameStateController->quit();
				if (gameStateController->gameStateCheck(gameData)) {
					continue;
				}
			}

			// Handle events
			while (SDL_PollEvent (&e) != 0) {
				if (e.type == SDL_QUIT) {
					quit = true;
					break;
				}
				if (gameStateController) {
					gameStateController->handle(e);
				}
				entityContainer->handleObjects(e, gameData);
			}

			entityContainer->moveObjects(gameData);

			// Clear screen to black
			SDL_SetRenderDrawColor( renderer, 0x0, 0x0, 0x0, 0xFF );
			SDL_RenderClear( renderer );
			entityContainer->renderObjects(gameData);

			SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);

			// Update the screen
			SDL_RenderPresent( renderer );

			int tickCount = fpsCapTimer.getTicks();
			if (tickCount < screenTicksPerFrame) {
				SDL_Delay(screenTicksPerFrame - tickCount);
			}
		}
	}
} // namespace flat2d
<commit_msg>Removes minor typo in GameEngine.cpp<commit_after>#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include "GameEngine.h"
#include "GameData.h"
#include "EntityContainer.h"
#include "RenderData.h"
#include "Timer.h"
#include "DeltatimeMonitor.h"
#include "VirtualGameStateController.h"

namespace flat2d
{
	void GameEngine::init(int screenWidth, int screenHeight, int fps)
	{
		this->screenWidth = screenWidth;
		this->screenHeight = screenHeight;
		this->screenFps = fps;
		this->screenTicksPerFrame = 1000 / fps;
	}

	void GameEngine::run(VirtualGameStateController *gameStateController) const
	{
		SDL_Renderer *renderer = gameData->getRenderData()->getRenderer();
		EntityContainer *entityContainer = gameData->getEntityContainer();

		Timer fpsTimer;
		Timer drawFpsTimer;

		fpsTimer.start();
		drawFpsTimer.start();

		// Loop stuff
		flat2d::Timer fpsCapTimer;
		SDL_Event e;
		bool quit = false;

		// Main loop
		gameData->getDeltatimeMonitor()->updateDeltaTime();
		while (!quit) {
			fpsCapTimer.start();
			gameData->getDeltatimeMonitor()->updateDeltaTime();

			if (gameStateController) {
				quit = gameStateController->quit();
				if (gameStateController->gameStateCheck(gameData)) {
					continue;
				}
			}

			// Handle events
			while (SDL_PollEvent (&e) != 0) {
				if (e.type == SDL_QUIT) {
					quit = true;
					break;
				}
				if (gameStateController) {
					gameStateController->handle(e);
				}
				entityContainer->handleObjects(e, gameData);
			}

			entityContainer->moveObjects(gameData);

			// Clear screen to black
			SDL_SetRenderDrawColor( renderer, 0x0, 0x0, 0x0, 0xFF );
			SDL_RenderClear( renderer );
			entityContainer->renderObjects(gameData);

			SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);

			// Update the screen
			SDL_RenderPresent( renderer );

			int tickCount = fpsCapTimer.getTicks();
			if (tickCount < screenTicksPerFrame) {
				SDL_Delay(screenTicksPerFrame - tickCount);
			}
		}
	}
} // namespace flat2d
<|endoftext|>


<commit_before>#include "GameWindow.h"

GameWindow::GameWindow(QMainWindow *parent) : QMainWindow(parent), m_fpga(this), m_game()
{
	/****General setup****/
	this->setWindowTitle("Scorch");
	this->setStatusBar(new QStatusBar);
    this->setWindowIcon(QIcon(QPixmap(":/resources/icon_big.png")));

	setFocus();
	setStyleSheet("QMainWindow::separator{ width:0px; height:0px;}");
	m_game.getView()->setFocusPolicy(Qt::NoFocus);

	/****Central widget****/
	GameModeWidget * m_gameModeWidget;
	AngleStatusWidget * m_currentAngle;
	FirePowerWidget * m_currentPower;

	this->setCentralWidget(m_game.getView());

	/****Bottom Widget (Information about player)****/
	QWidget* bottomWidget = new QWidget;
	QDockWidget* informationPanel = new QDockWidget;
	informationPanel->setAllowedAreas(Qt::BottomDockWidgetArea);
	informationPanel->setFeatures(QDockWidget::NoDockWidgetFeatures);
	GameBottomLayout *bottomLayout = new GameBottomLayout;

	m_gameModeWidget = new GameModeWidget;
	bottomLayout->addWidget(m_gameModeWidget);

	//This should be an object with custom paint method to make it interesting
	m_currentAngle = new AngleStatusWidget;
	m_currentAngle->setAngle(0);

	//This will be an object with custom paint method to make it interesting
	m_currentPower = new FirePowerWidget;
	m_currentPower->setPower(50);

	bottomLayout->addStretch();
	bottomLayout->addWidget(m_currentAngle);
	bottomLayout->setAlignment(m_currentAngle, Qt::AlignRight);
	bottomLayout->addWidget(m_currentPower);

	bottomWidget->setLayout(bottomLayout);
	informationPanel->setWidget(bottomWidget);

	this->addDockWidget(Qt::BottomDockWidgetArea, informationPanel);

	/****Menus****/
	m_menuBar = new QMenuBar;

	// File menu
	m_menuFichier = new QMenu("Fichier");
	m_actionQuit = new QAction("Quitter", this);
		m_actionQuit->setShortcut(QKeySequence("Q"));
	m_actionNewGame = new QAction("Nouvelle partie", this);
		m_actionNewGame->setShortcut(QKeySequence("N"));

	m_menuFichier->addAction(m_actionNewGame);
	m_menuFichier->addSeparator();
	m_menuFichier->addAction(m_actionQuit);
	m_menuBar->addMenu(m_menuFichier);

	// Game menu
	m_menuJeux = new QMenu("Jeux");
	m_actionPause = new QAction("Pause", this);
		m_actionPause->setShortcut(QKeySequence("P"));
	m_actionMuet = new QAction("Muet", this);
		m_actionMuet->setShortcut(QKeySequence("M"));

	m_menuJeux->addAction(m_actionPause);
	m_menuJeux->addSeparator();
	m_menuJeux->addAction(m_actionMuet);
	m_menuBar->addMenu(m_menuJeux);

	//Help menu
	m_menuAide = new QMenu("Aide");
	m_actionTutoriel = new QAction("Tutoriel", this);
	m_actionVersion = new QAction("Version", this);
	QAction* actionAboutQt = new QAction("A Propos de Qt", this);

	m_menuAide->addAction(m_actionTutoriel);
	m_menuAide->addSeparator();
	m_menuAide->addAction(m_actionVersion);
	m_menuAide->addSeparator();
	m_menuAide->addAction(actionAboutQt);
	m_menuBar->addMenu(m_menuAide);

	this->setMenuBar(m_menuBar);

	/****Connections****/
	// Connect Menu
	connect(m_actionQuit, &QAction::triggered, QApplication::instance(), &QApplication::quit);
	connect(actionAboutQt, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
	connect(m_actionPause, &QAction::triggered, this, &GameWindow::pausedTriggered);
	connect(m_actionNewGame, SIGNAL(triggered()), this, SLOT(openNewGame()));
	connect(m_actionTutoriel, SIGNAL(triggered()), this, SLOT(openTutoriel()));
	connect(m_actionVersion, SIGNAL(triggered()), this, SLOT(openVersion()));

	// Connect Input
	connect(&m_fpga, &FPGAReceiver::fpgaError, this, &GameWindow::displayStatusMessage);

	// Connect Game
	connect(&m_game, &Game::playerChanged, this, &GameWindow::playerChanged);
	connect(&m_game, &Game::angleChanged, this, &GameWindow::angleChanged);
	connect(&m_game, &Game::powerChanged, this, &GameWindow::powerChanged);
	connect(&m_game, &Game::stateChanged, this, &GameWindow::stateChanged);

	// Connect Info Widgets
	connect(this, &GameWindow::changeAngle, m_currentAngle, &AngleStatusWidget::setAngle);
	connect(this, &GameWindow::changePlayer, m_gameModeWidget, &GameModeWidget::setCurrentPlayer);
	connect(this, &GameWindow::changePower, m_currentPower, &FirePowerWidget::setPower);
	connect(this, &GameWindow::changeState, m_gameModeWidget, &GameModeWidget::setCurrentMode);
}

GameWindow::~GameWindow()
{
}

void GameWindow::displayStatusMessage(QString message)
{
	statusBar()->showMessage(message);
}

void GameWindow::playerChanged(Player p_player)
{
	emit changePlayer(p_player);
}

void GameWindow::stateChanged(InputState p_state)
{
	emit changeState(p_state);
}

void GameWindow::angleChanged(float p_angle)
{
	emit changeAngle(p_angle);
}

void GameWindow::powerChanged(float p_power)
{
	emit changePower(p_power);
}

void GameWindow::pausedTriggered()
{
	if (m_game.pause()) {
		m_game.setPause(false);
		m_actionPause->setText("&Pause");
	}
	else {
		m_game.setPause(true);
		if(m_game.pause())
			m_actionPause->setText("&Play");
	}
}

void GameWindow::keyPressEvent(QKeyEvent * KeyEvent)
{
    //NOTE: Hack to simulate correctly the FPGA input
    m_fpga.handlePressEvent(KeyEvent);
}

void GameWindow::customEvent(QEvent *event)
{
    if(event->type() == FPGAEvent::customFPGAEvent) {
        FPGAEvent* fpgaEvent = static_cast<FPGAEvent *>(event);

        QCoreApplication::postEvent(&m_game, new FPGAEvent(*fpgaEvent));
    }
}

void GameWindow::openNewGame()
{
    FenetreNewGame fenNewGame;
    fenNewGame.exec();
	if (fenNewGame.result() == QDialog::Accepted)
		m_game.newGame();
}

void GameWindow::openTutoriel()
{
    FenetreTutoriel fenTutoriel;
    fenTutoriel.exec();
}

void GameWindow::openVersion()
{
    FenetreVersion fenVersion;
    fenVersion.exec();
}

void GameWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    m_game.getView()->fitInView(m_game.getView()->sceneRect(), Qt::KeepAspectRatio);
}
<commit_msg>Changed input simulation to limit fire operation to space bar<commit_after>#include "GameWindow.h"

GameWindow::GameWindow(QMainWindow *parent) : QMainWindow(parent), m_fpga(this), m_game()
{
	/****General setup****/
	this->setWindowTitle("Scorch");
	this->setStatusBar(new QStatusBar);
    this->setWindowIcon(QIcon(QPixmap(":/resources/icon_big.png")));

	setFocus();
	setStyleSheet("QMainWindow::separator{ width:0px; height:0px;}");
	m_game.getView()->setFocusPolicy(Qt::NoFocus);

	/****Central widget****/
	GameModeWidget * m_gameModeWidget;
	AngleStatusWidget * m_currentAngle;
	FirePowerWidget * m_currentPower;

	this->setCentralWidget(m_game.getView());

	/****Bottom Widget (Information about player)****/
	QWidget* bottomWidget = new QWidget;
	QDockWidget* informationPanel = new QDockWidget;
	informationPanel->setAllowedAreas(Qt::BottomDockWidgetArea);
	informationPanel->setFeatures(QDockWidget::NoDockWidgetFeatures);
	GameBottomLayout *bottomLayout = new GameBottomLayout;

	m_gameModeWidget = new GameModeWidget;
	bottomLayout->addWidget(m_gameModeWidget);

	//This should be an object with custom paint method to make it interesting
	m_currentAngle = new AngleStatusWidget;
	m_currentAngle->setAngle(0);

	//This will be an object with custom paint method to make it interesting
	m_currentPower = new FirePowerWidget;
	m_currentPower->setPower(50);

	bottomLayout->addStretch();
	bottomLayout->addWidget(m_currentAngle);
	bottomLayout->setAlignment(m_currentAngle, Qt::AlignRight);
	bottomLayout->addWidget(m_currentPower);

	bottomWidget->setLayout(bottomLayout);
	informationPanel->setWidget(bottomWidget);

	this->addDockWidget(Qt::BottomDockWidgetArea, informationPanel);

	/****Menus****/
	m_menuBar = new QMenuBar;

	// File menu
	m_menuFichier = new QMenu("Fichier");
	m_actionQuit = new QAction("Quitter", this);
		m_actionQuit->setShortcut(QKeySequence("Q"));
	m_actionNewGame = new QAction("Nouvelle partie", this);
		m_actionNewGame->setShortcut(QKeySequence("N"));

	m_menuFichier->addAction(m_actionNewGame);
	m_menuFichier->addSeparator();
	m_menuFichier->addAction(m_actionQuit);
	m_menuBar->addMenu(m_menuFichier);

	// Game menu
	m_menuJeux = new QMenu("Jeux");
	m_actionPause = new QAction("Pause", this);
		m_actionPause->setShortcut(QKeySequence("P"));
	m_actionMuet = new QAction("Muet", this);
		m_actionMuet->setShortcut(QKeySequence("M"));

	m_menuJeux->addAction(m_actionPause);
	m_menuJeux->addSeparator();
	m_menuJeux->addAction(m_actionMuet);
	m_menuBar->addMenu(m_menuJeux);

	//Help menu
	m_menuAide = new QMenu("Aide");
	m_actionTutoriel = new QAction("Tutoriel", this);
	m_actionVersion = new QAction("Version", this);
	QAction* actionAboutQt = new QAction("A Propos de Qt", this);

	m_menuAide->addAction(m_actionTutoriel);
	m_menuAide->addSeparator();
	m_menuAide->addAction(m_actionVersion);
	m_menuAide->addSeparator();
	m_menuAide->addAction(actionAboutQt);
	m_menuBar->addMenu(m_menuAide);

	this->setMenuBar(m_menuBar);

	/****Connections****/
	// Connect Menu
	connect(m_actionQuit, &QAction::triggered, QApplication::instance(), &QApplication::quit);
	connect(actionAboutQt, &QAction::triggered, QApplication::instance(), &QApplication::aboutQt);
	connect(m_actionPause, &QAction::triggered, this, &GameWindow::pausedTriggered);
	connect(m_actionNewGame, SIGNAL(triggered()), this, SLOT(openNewGame()));
	connect(m_actionTutoriel, SIGNAL(triggered()), this, SLOT(openTutoriel()));
	connect(m_actionVersion, SIGNAL(triggered()), this, SLOT(openVersion()));

	// Connect Input
	connect(&m_fpga, &FPGAReceiver::fpgaError, this, &GameWindow::displayStatusMessage);

	// Connect Game
	connect(&m_game, &Game::playerChanged, this, &GameWindow::playerChanged);
	connect(&m_game, &Game::angleChanged, this, &GameWindow::angleChanged);
	connect(&m_game, &Game::powerChanged, this, &GameWindow::powerChanged);
	connect(&m_game, &Game::stateChanged, this, &GameWindow::stateChanged);

	// Connect Info Widgets
	connect(this, &GameWindow::changeAngle, m_currentAngle, &AngleStatusWidget::setAngle);
	connect(this, &GameWindow::changePlayer, m_gameModeWidget, &GameModeWidget::setCurrentPlayer);
	connect(this, &GameWindow::changePower, m_currentPower, &FirePowerWidget::setPower);
	connect(this, &GameWindow::changeState, m_gameModeWidget, &GameModeWidget::setCurrentMode);
}

GameWindow::~GameWindow()
{
}

void GameWindow::displayStatusMessage(QString message)
{
	statusBar()->showMessage(message);
}

void GameWindow::playerChanged(Player p_player)
{
	emit changePlayer(p_player);
}

void GameWindow::stateChanged(InputState p_state)
{
	emit changeState(p_state);
}

void GameWindow::angleChanged(float p_angle)
{
	emit changeAngle(p_angle);
}

void GameWindow::powerChanged(float p_power)
{
	emit changePower(p_power);
}

void GameWindow::pausedTriggered()
{
	if (m_game.pause()) {
		m_game.setPause(false);
		m_actionPause->setText("&Pause");
	}
	else {
		m_game.setPause(true);
		if(m_game.pause())
			m_actionPause->setText("&Play");
	}
}

void GameWindow::keyPressEvent(QKeyEvent * KeyEvent)
{
    //NOTE: Hack to simulate correctly the FPGA input
	if (m_game.getState() == InputState::Fire && KeyEvent->key() == Qt::Key_Space){
		QKeyEvent * key = new QKeyEvent(KeyEvent->type(), Qt::Key_Up, Qt::KeyboardModifier::NoModifier);

		m_fpga.handlePressEvent(key);
	}
	else if (m_game.getState() == InputState::Fire && (KeyEvent->key() == Qt::Key_Up || KeyEvent->key() == Qt::Key_Down))
		return;
	else
		m_fpga.handlePressEvent(KeyEvent);
}

void GameWindow::customEvent(QEvent *event)
{
    if(event->type() == FPGAEvent::customFPGAEvent) {
        FPGAEvent* fpgaEvent = static_cast<FPGAEvent *>(event);

        QCoreApplication::postEvent(&m_game, new FPGAEvent(*fpgaEvent));
    }
}

void GameWindow::openNewGame()
{
    FenetreNewGame fenNewGame;
    fenNewGame.exec();
	if (fenNewGame.result() == QDialog::Accepted)
		m_game.newGame();
}

void GameWindow::openTutoriel()
{
    FenetreTutoriel fenTutoriel;
    fenTutoriel.exec();
}

void GameWindow::openVersion()
{
    FenetreVersion fenVersion;
    fenVersion.exec();
}

void GameWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    m_game.getView()->fitInView(m_game.getView()->sceneRect(), Qt::KeepAspectRatio);
}
<|endoftext|>


<commit_before>#include "GlslParams.h"
#include "cinder/Utilities.h"

using namespace reza::glsl;
using namespace cinder;
using namespace std;

GlslParams::GlslParams()
{
}

GlslParams::GlslParams( const string &source )
{
	parseUniforms( source );
}

GlslParams::~GlslParams()
{
	clearUniforms();
}

GlslParams::GlslParams( const GlslParams &copy )
{
	for( auto &it : copy.mParamOrder ) {
		mParamOrder[it.first] = it.second;
	}

	for( auto &it : copy.mTypeMap ) {
		mTypeMap[it.first] = it.second;
	}
	for( auto &it : copy.mBoolParams ) {
		mBoolParams[it.first] = it.second;
	}

	for( auto &it : copy.mIntParams ) {
		mIntParams[it.first] = it.second;
	}
	for( auto &it : copy.mIntRanges ) {
		mIntRanges[it.first] = it.second;
	}

	for( auto &it : copy.mFloatParams ) {
		mFloatParams[it.first] = it.second;
	}
	for( auto &it : copy.mFloatRanges ) {
		mFloatRanges[it.first] = it.second;
	}

	for( auto &it : copy.mVec2Params ) {
		mVec2Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec2Ranges ) {
		mVec2Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mVec3Params ) {
		mVec3Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec3Ranges ) {
		mVec3Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mVec4Params ) {
		mVec4Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec4Ranges ) {
		mVec4Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mColorParams ) {
		mColorParams[it.first] = it.second;
	}
}

void GlslParams::clearUniforms()
{
	mParamOrder.clear();
	mTypeMap.clear();
	mBoolParams.clear();
	mIntParams.clear();
	mIntRanges.clear();
	mFloatParams.clear();
	mFloatRanges.clear();
	mVec2Params.clear();
	mVec2Ranges.clear();
	mVec3Params.clear();
	mVec3Ranges.clear();
	mVec4Params.clear();
	mVec4Ranges.clear();
	mColorParams.clear();
}

void GlslParams::applyUniforms( const ci::gl::GlslProgRef &glslRef )
{
	for( auto &it : mBoolParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mIntParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mFloatParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec2Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec3Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec4Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mColorParams ) {
		glslRef->uniform( it.first, it.second );
	}
}

void GlslParams::parseUniforms( const vector<string> &sources )
{
	clearUniforms();
	for( auto &it : sources ) {
		parse( it );
	}
}

void GlslParams::parseUniforms( const string &source )
{
	clearUniforms();
	parse( source );
}

void GlslParams::parse( const string &source )
{
	auto trim = []( const string &input, const string &key ) {
		string temp = input;
		size_t foundKey = temp.find( key );
		while( foundKey != string::npos ) {
			temp = temp.replace( foundKey, key.length(), "" );
			foundKey = temp.find( key );
		}
		return temp;
	};

	multimap<string, string> uiTypeMap = {
		{ "int", "slider" },
		{ "int", "dialer" },

		{ "float", "ui" },
		{ "float", "slider" },
		{ "float", "dialer" },

		{ "vec2", "pad" },
		{ "vec2", "range" },
		{ "vec2", "ui" },
		{ "vec2", "slider" },
		{ "vec2", "dialer" },

		{ "vec3", "ui" },
		{ "vec3", "slider" },
		{ "vec3", "dialer" },

		{ "vec4", "ui" },
		{ "vec4", "slider" },
		{ "vec4", "color" },
		{ "vec4", "dialer" },

		{ "bool", "button" },
		{ "bool", "toggle" }
	};
	bool ignore = false;
	vector<string> lines = split( source, '\n' );
	for( auto &it : lines ) {
		string original = it;
		string line = it;

		string ignoreStart( "/*" );
		string ignoreEnd( "*/" );
		if( !ignore && line.find( ignoreStart ) != string::npos ) {
			ignore = true;
		}

		if( ignore && line.find( ignoreEnd ) == string::npos ) {
			continue;
		}
		else {
			ignore = false;
		}

		std::transform( line.begin(), line.end(), line.begin(), ::tolower );
		string uniform( "uniform " );
		string semicolon( ";" );
		string colon( ":" );
		string space( " " );
		string comment( "//" );
		string comma( "," );
		string newLine( "/n" );

		size_t foundUniform = line.find( uniform );
		if( foundUniform == string::npos ) {
			continue;
		}
		size_t foundComment = line.find( comment );
		if( foundComment == string::npos || foundUniform > foundComment ) {
			continue;
		}
		size_t foundType = string::npos;
		size_t foundUIType = string::npos;
		string type;
		string uitype;
		string key;

		bool valid = false;
		for( auto &ui : uiTypeMap ) {
			foundType = line.find( ui.first );
			//			string tempkey = comment + ui.second + colon;
			string tempkey = comment + ui.second;
			foundUIType = line.find( tempkey );
			if( foundType != string::npos && foundUIType != string::npos ) {
				valid = true;
				type = ui.first;
				uitype = ui.second;
				key = tempkey;
				break;
			}
		}

		if( !valid ) {
			continue;
		}

		string uniformName = original;
		size_t foundSemicolon = uniformName.find( semicolon );
		uniformName = uniformName.substr( 0, foundSemicolon );
		uniformName = uniformName.replace( foundType, type.length(), "" );
		uniformName = uniformName.replace( foundUniform, uniform.length(), "" );
		uniformName = trim( uniformName, " " );

		string uiParams = line.substr( foundUIType + key.length() );
		uiParams = trim( uiParams, ":" );

		vector<string> params = split( uiParams, "," );
		if( params.size() == 1 ) {
			if( params[0].length() == 0 ) {
				params.clear();
			}
		}
		int size = params.size();

		vector<float> values;
		bool invalidParams = false;
		for( auto &it : params ) {
			try {
				values.emplace_back( stof( it ) );
			}
			catch( std::exception &exc ) {
				invalidParams = true;
				break;
			}
		}

		if( invalidParams ) {
			continue;
		}

		valid = false;

		if( type == "bool" ) {
			if( size == 1 ) {
				bool val = values[0] > 0.5 ? true : false;
				mBoolParams[uniformName] = val;
			}
			else {
				mBoolParams[uniformName] = true;
			}
			valid = true;
		}
		else if( type == "int" ) {
			if( size > 2 ) {
				mIntParams[uniformName] = values[2];
				mIntRanges[uniformName] = { values[0], values[1] };
			}
			else {
				mIntParams[uniformName] = 50;
				mIntRanges[uniformName] = { 0, 100 };
			}
			valid = true;
		}
		else if( type == "float" ) {
			if( size > 2 ) {
				mFloatParams[uniformName] = values[2];
				mFloatRanges[uniformName] = { values[0], values[1] };
			}
			else {
				mFloatParams[uniformName] = 0.5f;
				mFloatRanges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec2" ) {
			if( size > 2 ) {
				if( uitype == "range" && size > 3 ) {
					mVec2Params[uniformName] = vec2( values[2], values[3] );
				}
				else {
					mVec2Params[uniformName] = vec2( values[2] );
				}
				mVec2Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec2Params[uniformName] = vec2( 0.25f, 0.75f );
				mVec2Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec3" ) {
			if( size > 2 ) {
				mVec3Params[uniformName] = vec3( values[2] );
				mVec3Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec3Params[uniformName] = vec3( 0.5f );
				mVec3Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec4" && uitype == "color" ) {
			ColorA clr;
			if( size > 3 ) {
				clr.set( ColorModel::CM_RGB, vec4( values[0], values[1], values[2], values[3] ) );
				mColorParams[uniformName] = clr;
			}
			else {
				clr.set( ColorModel::CM_RGB, vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				mColorParams[uniformName] = clr;
			}
			valid = true;
		}
		else if( type == "vec4" ) {
			if( size > 2 ) {
				mVec4Params[uniformName] = vec4( values[2] );
				mVec4Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec4Params[uniformName] = vec4( 0.5f );
				mVec4Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}

		if( valid ) {
			mTypeMap.insert( { uniformName, { type, uitype } } );
			mParamOrder[mParamOrder.size()] = uniformName;
		}
	}
}

const map<int, string> &GlslParams::getParamOrder()
{
	return mParamOrder;
}

const map<string, pair<string, string>> &GlslParams::getTypeMap()
{
	return mTypeMap;
}

map<string, bool> &GlslParams::getBoolParams()
{
	return mBoolParams;
}

map<string, int> &GlslParams::getIntParams()
{
	return mIntParams;
}
map<string, pair<int, int>> &GlslParams::getIntRanges()
{
	return mIntRanges;
}

map<string, float> &GlslParams::getFloatParams()
{
	return mFloatParams;
}
map<string, pair<float, float>> &GlslParams::getFloatRanges()
{
	return mFloatRanges;
}

map<string, vec2> &GlslParams::getVec2Params()
{
	return mVec2Params;
}
map<string, pair<float, float>> &GlslParams::getVec2Ranges()
{
	return mVec2Ranges;
}

map<string, vec3> &GlslParams::getVec3Params()
{
	return mVec3Params;
}
map<string, pair<float, float>> &GlslParams::getVec3Ranges()
{
	return mVec3Ranges;
}

map<string, vec4> &GlslParams::getVec4Params()
{
	return mVec4Params;
}
map<string, pair<float, float>> &GlslParams::getVec4Ranges()
{
	return mVec4Ranges;
}

map<string, ColorA> &GlslParams::getColorParams()
{
	return mColorParams;
}<commit_msg>added proper casting to remove compilation warnings<commit_after>#include "GlslParams.h"
#include "cinder/Utilities.h"

using namespace reza::glsl;
using namespace cinder;
using namespace std;

GlslParams::GlslParams()
{
}

GlslParams::GlslParams( const string &source )
{
	parseUniforms( source );
}

GlslParams::~GlslParams()
{
	clearUniforms();
}

GlslParams::GlslParams( const GlslParams &copy )
{
	for( auto &it : copy.mParamOrder ) {
		mParamOrder[it.first] = it.second;
	}

	for( auto &it : copy.mTypeMap ) {
		mTypeMap[it.first] = it.second;
	}
	for( auto &it : copy.mBoolParams ) {
		mBoolParams[it.first] = it.second;
	}

	for( auto &it : copy.mIntParams ) {
		mIntParams[it.first] = it.second;
	}
	for( auto &it : copy.mIntRanges ) {
		mIntRanges[it.first] = it.second;
	}

	for( auto &it : copy.mFloatParams ) {
		mFloatParams[it.first] = it.second;
	}
	for( auto &it : copy.mFloatRanges ) {
		mFloatRanges[it.first] = it.second;
	}

	for( auto &it : copy.mVec2Params ) {
		mVec2Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec2Ranges ) {
		mVec2Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mVec3Params ) {
		mVec3Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec3Ranges ) {
		mVec3Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mVec4Params ) {
		mVec4Params[it.first] = it.second;
	}
	for( auto &it : copy.mVec4Ranges ) {
		mVec4Ranges[it.first] = it.second;
	}

	for( auto &it : copy.mColorParams ) {
		mColorParams[it.first] = it.second;
	}
}

void GlslParams::clearUniforms()
{
	mParamOrder.clear();
	mTypeMap.clear();
	mBoolParams.clear();
	mIntParams.clear();
	mIntRanges.clear();
	mFloatParams.clear();
	mFloatRanges.clear();
	mVec2Params.clear();
	mVec2Ranges.clear();
	mVec3Params.clear();
	mVec3Ranges.clear();
	mVec4Params.clear();
	mVec4Ranges.clear();
	mColorParams.clear();
}

void GlslParams::applyUniforms( const ci::gl::GlslProgRef &glslRef )
{
	for( auto &it : mBoolParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mIntParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mFloatParams ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec2Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec3Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mVec4Params ) {
		glslRef->uniform( it.first, it.second );
	}
	for( auto &it : mColorParams ) {
		glslRef->uniform( it.first, it.second );
	}
}

void GlslParams::parseUniforms( const vector<string> &sources )
{
	clearUniforms();
	for( auto &it : sources ) {
		parse( it );
	}
}

void GlslParams::parseUniforms( const string &source )
{
	clearUniforms();
	parse( source );
}

void GlslParams::parse( const string &source )
{
	auto trim = []( const string &input, const string &key ) {
		string temp = input;
		size_t foundKey = temp.find( key );
		while( foundKey != string::npos ) {
			temp = temp.replace( foundKey, key.length(), "" );
			foundKey = temp.find( key );
		}
		return temp;
	};

	multimap<string, string> uiTypeMap = {
		{ "int", "slider" },
		{ "int", "dialer" },

		{ "float", "ui" },
		{ "float", "slider" },
		{ "float", "dialer" },

		{ "vec2", "pad" },
		{ "vec2", "range" },
		{ "vec2", "ui" },
		{ "vec2", "slider" },
		{ "vec2", "dialer" },

		{ "vec3", "ui" },
		{ "vec3", "slider" },
		{ "vec3", "dialer" },

		{ "vec4", "ui" },
		{ "vec4", "slider" },
		{ "vec4", "color" },
		{ "vec4", "dialer" },

		{ "bool", "button" },
		{ "bool", "toggle" }
	};
	bool ignore = false;
	vector<string> lines = split( source, '\n' );
	for( auto &it : lines ) {
		string original = it;
		string line = it;

		string ignoreStart( "/*" );
		string ignoreEnd( "*/" );
		if( !ignore && line.find( ignoreStart ) != string::npos ) {
			ignore = true;
		}

		if( ignore && line.find( ignoreEnd ) == string::npos ) {
			continue;
		}
		else {
			ignore = false;
		}

		std::transform( line.begin(), line.end(), line.begin(), ::tolower );
		string uniform( "uniform " );
		string semicolon( ";" );
		string colon( ":" );
		string space( " " );
		string comment( "//" );
		string comma( "," );
		string newLine( "/n" );

		size_t foundUniform = line.find( uniform );
		if( foundUniform == string::npos ) {
			continue;
		}
		size_t foundComment = line.find( comment );
		if( foundComment == string::npos || foundUniform > foundComment ) {
			continue;
		}
		size_t foundType = string::npos;
		size_t foundUIType = string::npos;
		string type;
		string uitype;
		string key;

		bool valid = false;
		for( auto &ui : uiTypeMap ) {
			foundType = line.find( ui.first );
			//			string tempkey = comment + ui.second + colon;
			string tempkey = comment + ui.second;
			foundUIType = line.find( tempkey );
			if( foundType != string::npos && foundUIType != string::npos ) {
				valid = true;
				type = ui.first;
				uitype = ui.second;
				key = tempkey;
				break;
			}
		}

		if( !valid ) {
			continue;
		}

		string uniformName = original;
		size_t foundSemicolon = uniformName.find( semicolon );
		uniformName = uniformName.substr( 0, foundSemicolon );
		uniformName = uniformName.replace( foundType, type.length(), "" );
		uniformName = uniformName.replace( foundUniform, uniform.length(), "" );
		uniformName = trim( uniformName, " " );

		string uiParams = line.substr( foundUIType + key.length() );
		uiParams = trim( uiParams, ":" );

		vector<string> params = split( uiParams, "," );
		if( params.size() == 1 ) {
			if( params[0].length() == 0 ) {
				params.clear();
			}
		}
		int size = (int)params.size();

		vector<float> values;
		bool invalidParams = false;
		for( auto &it : params ) {
			try {
				values.emplace_back( stof( it ) );
			}
			catch( std::exception &exc ) {
				invalidParams = true;
				break;
			}
		}

		if( invalidParams ) {
			continue;
		}

		valid = false;

		if( type == "bool" ) {
			if( size == 1 ) {
				bool val = values[0] > 0.5 ? true : false;
				mBoolParams[uniformName] = val;
			}
			else {
				mBoolParams[uniformName] = true;
			}
			valid = true;
		}
		else if( type == "int" ) {
			if( size > 2 ) {
				mIntParams[uniformName] = values[2];
				mIntRanges[uniformName] = { values[0], values[1] };
			}
			else {
				mIntParams[uniformName] = 50;
				mIntRanges[uniformName] = { 0, 100 };
			}
			valid = true;
		}
		else if( type == "float" ) {
			if( size > 2 ) {
				mFloatParams[uniformName] = values[2];
				mFloatRanges[uniformName] = { values[0], values[1] };
			}
			else {
				mFloatParams[uniformName] = 0.5f;
				mFloatRanges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec2" ) {
			if( size > 2 ) {
				if( uitype == "range" && size > 3 ) {
					mVec2Params[uniformName] = vec2( values[2], values[3] );
				}
				else {
					mVec2Params[uniformName] = vec2( values[2] );
				}
				mVec2Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec2Params[uniformName] = vec2( 0.25f, 0.75f );
				mVec2Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec3" ) {
			if( size > 2 ) {
				mVec3Params[uniformName] = vec3( values[2] );
				mVec3Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec3Params[uniformName] = vec3( 0.5f );
				mVec3Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}
		else if( type == "vec4" && uitype == "color" ) {
			ColorA clr;
			if( size > 3 ) {
				clr.set( ColorModel::CM_RGB, vec4( values[0], values[1], values[2], values[3] ) );
				mColorParams[uniformName] = clr;
			}
			else {
				clr.set( ColorModel::CM_RGB, vec4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				mColorParams[uniformName] = clr;
			}
			valid = true;
		}
		else if( type == "vec4" ) {
			if( size > 2 ) {
				mVec4Params[uniformName] = vec4( values[2] );
				mVec4Ranges[uniformName] = { values[0], values[1] };
			}
			else {
				mVec4Params[uniformName] = vec4( 0.5f );
				mVec4Ranges[uniformName] = { 0.0f, 1.0f };
			}
			valid = true;
		}

		if( valid ) {
			mTypeMap.insert( { uniformName, { type, uitype } } );
			mParamOrder[(int)mParamOrder.size()] = uniformName;
		}
	}
}

const map<int, string> &GlslParams::getParamOrder()
{
	return mParamOrder;
}

const map<string, pair<string, string>> &GlslParams::getTypeMap()
{
	return mTypeMap;
}

map<string, bool> &GlslParams::getBoolParams()
{
	return mBoolParams;
}

map<string, int> &GlslParams::getIntParams()
{
	return mIntParams;
}
map<string, pair<int, int>> &GlslParams::getIntRanges()
{
	return mIntRanges;
}

map<string, float> &GlslParams::getFloatParams()
{
	return mFloatParams;
}
map<string, pair<float, float>> &GlslParams::getFloatRanges()
{
	return mFloatRanges;
}

map<string, vec2> &GlslParams::getVec2Params()
{
	return mVec2Params;
}
map<string, pair<float, float>> &GlslParams::getVec2Ranges()
{
	return mVec2Ranges;
}

map<string, vec3> &GlslParams::getVec3Params()
{
	return mVec3Params;
}
map<string, pair<float, float>> &GlslParams::getVec3Ranges()
{
	return mVec3Ranges;
}

map<string, vec4> &GlslParams::getVec4Params()
{
	return mVec4Params;
}
map<string, pair<float, float>> &GlslParams::getVec4Ranges()
{
	return mVec4Ranges;
}

map<string, ColorA> &GlslParams::getColorParams()
{
	return mColorParams;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "ifmap/ifmap_update_sender.h"
#include "base/task.h"
#include "ifmap/ifmap_client.h"
#include "ifmap/ifmap_server.h"
#include "ifmap/ifmap_encoder.h"
#include "ifmap/ifmap_exporter.h"
#include "ifmap/ifmap_log.h"
#include "ifmap/ifmap_log_types.h"
#include "ifmap/ifmap_update.h"
#include "ifmap/ifmap_update_queue.h"

using namespace std;

IFMapUpdateSender::IFMapUpdateSender(IFMapServer *server,
                                     IFMapUpdateQueue *queue)
    : server_(server), queue_(queue), message_(new IFMapMessage()),
      task_scheduled_(false), queue_active_(false) {
}

IFMapUpdateSender::~IFMapUpdateSender() {
    delete(message_);
}

class IFMapUpdateSender::SendTask : public Task {
public:
    explicit SendTask(IFMapUpdateSender *sender)
        : Task(TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), 0),
          sender_(sender) {
    }
    virtual bool Run() {
        BitSet send_scheduled;
        sender_->GetSendScheduled(&send_scheduled);
        sender_->send_blocked_.Reset(send_scheduled);
        for (size_t i = send_scheduled.find_first(); i != BitSet::npos;
             i = send_scheduled.find_next(i)) {
            // Dequeue from client marker (i).
            sender_->Send(sender_->queue_->GetMarker(i));
        }
        if (sender_->queue_active_) {
            // Dequeue from tail marker.
            // Reset queue_active_
            sender_->Send(sender_->queue_->tail_marker());
            sender_->queue_active_ = false;
        }
        return true;
    }

    std::string Description() const { return "IFMapUpdateSender::SendTask"; }
private:
    IFMapUpdateSender *sender_;
};

void IFMapUpdateSender::StartTask() {
    if (!task_scheduled_) {
        // create new task
        SendTask *send_task = new SendTask(this);
        TaskScheduler *scheduler = TaskScheduler::GetInstance();
        scheduler->Enqueue(send_task);
        task_scheduled_ = true;
    }
}

void IFMapUpdateSender::QueueActive() {
    if (queue_active_) {
        return;
    }
    queue_active_ = true;
    tbb::mutex::scoped_lock lock(mutex_);
    StartTask();
}

void IFMapUpdateSender::SendActive(int index) {
    tbb::mutex::scoped_lock lock(mutex_);
    send_scheduled_.set(index);
    StartTask();
}

void IFMapUpdateSender::GetSendScheduled(BitSet *current) {
    tbb::mutex::scoped_lock lock(mutex_);
    *current = send_scheduled_;
    send_scheduled_.clear();
    task_scheduled_ = false;
}

void IFMapUpdateSender::CleanupClient(int index) {
    tbb::mutex::scoped_lock lock(mutex_);
    send_scheduled_.reset(index);
    send_blocked_.reset(index);
}

// We return only under 2 conditions:
// 1. All the clients in the marker are blocked.
// 2. We have finished traversing the Q.
// Invariant: while we are traversing the Q, the marker that we are working
// with only has ready clients. As soon as a client blocks, we split it out and
// continue with the ready set.
void IFMapUpdateSender::Send(IFMapMarker *imarker) {
    IFMapMarker *marker = imarker;

    // Get the clients in this marker that are blocked. If all of the clients in
    // this marker are blocked, we are done.
    BitSet blocked_clients;
    blocked_clients = (marker->mask & send_blocked_);
    if (blocked_clients == marker->mask) {
        return;
    }

    // If any of the clients are blocked, create a new marker for the set of
    // blocked clients, insert it before marker and continue with the ready
    // set.
    if (!blocked_clients.empty()) {
        queue_->MarkerSplitBefore(marker, marker, blocked_clients);
    }

    IFMapListEntry *next = queue_->Next(marker);
    BitSet base_send_set;

    // Start with the node after the 'marker'
    for (IFMapListEntry *curr = next; curr != NULL; curr = next) {
        next = queue_->Next(curr);

        if (curr->IsMarker()) {
            IFMapMarker *next_marker = static_cast<IFMapMarker *>(curr);
            // Processing the next_marker can change the send_set and all
            // clients in the next_marker should have already seen the updates
            // currently sitting in the buffer. So, flush the buffer to the
            // existing client-set before processing the marker so that we dont
            // send duplicates.
            if (!message_->IsEmpty()) {
                BitSet blocked_set;
                SendUpdate(base_send_set, &blocked_set);
            }
            bool done;
            marker = ProcessMarker(marker, next_marker, &done);
            if (done) {
                // All the clients in this marker are blocked. We are done.
                return;
            }
            // marker has the ready clients. Continue as if we are starting
            // fresh.
            base_send_set.clear();
            continue;
        }

        // ...else its an update or delete

        IFMapUpdate *update = static_cast<IFMapUpdate *>(curr);
        BitSet send_set = update->advertise() & marker->mask;
        if (send_set.empty()) {
            continue;
        }

        if (base_send_set.empty()) {
            base_send_set = send_set;
        }

        // Flush the message to all possible clients if:
        // 1. The buffer is full OR
        // 2. The send_set is changing and buffer is filled.
        if (message_->IsFull() ||
            ((base_send_set != send_set) && !message_->IsEmpty())) {

            BitSet blocked_set;
            SendUpdate(base_send_set, &blocked_set);
            if (!blocked_set.empty()) {
                // All the clients in this marker are blocked. We are done.
                if (blocked_set == marker->mask) {
                    queue_->MoveMarkerBefore(marker, curr);
                    return;
                }
                // Only a subset of clients in this marker are blocked. Insert
                // a marker for them 'before' curr since they have seen
                // everything before curr. Let the ready clients continue the
                // traversal.
                queue_->MarkerSplitBefore(marker, curr, blocked_set);
                send_set.Reset(blocked_set);
            }

            // The send_set for this marker is changing. Pick up the new one.
            base_send_set = send_set;
        }

        // base_send_set is same as send_set at this point.
        ProcessUpdate(update, base_send_set);
    }

    // The buffer will be filled in the common case of updates being added
    // after the tail_marker.
    if (!message_->IsEmpty()) {
        BitSet blk_set;
        SendUpdate(base_send_set, &blk_set);
    }
    // If the last node in the Q was the tail_marker, we would have already
    // flushed the buffer and merged with it and we would be the last node in
    // the Q.
    IFMapListEntry *last = queue_->GetLast();
    if (marker != last) {
        // Since we have reached the end of the Q, we better be the tail_marker
        assert(marker == queue_->tail_marker());
        // If we have any blocked clients, splitting markers for them is not
        // useful at this point. Just move the marker to the end of the Q,
        // immediately after last, even if it has blocked clients. Being lazy
        // is advantageous since by the time we get the next trigger, a blocked
        // client could have become ready and splitting the marker now would be
        // useless.
        queue_->MoveMarkerAfter(marker, last);
    }
    return;
}

void IFMapUpdateSender::ProcessUpdate(IFMapUpdate *update,
                                      const BitSet &base_send_set) {
    LogAndCountSentUpdate(update, base_send_set);

    // Append the contents of the update-node to the message.
    message_->EncodeUpdate(update);

    // Clean up the node if everybody has seen it.
    update->AdvertiseReset(base_send_set);
    if (update->advertise().empty()) {
        queue_->Dequeue(update);
    }
    // Update may be freed.
    server_->exporter()->StateUpdateOnDequeue(update, base_send_set,
                                              update->IsDelete());
}

// blocked_set is a subset of send_set
void IFMapUpdateSender::SendUpdate(BitSet send_set, BitSet *blocked_set) {
    IFMapClient *client;
    bool send_result;

    assert(!message_->IsEmpty());

    for (size_t i = send_set.find_first(); i != BitSet::npos;
         i = send_set.find_next(i)) {
        assert(!send_blocked_.test(i));
        client = server_->GetClient(i);
        if (client == NULL) {
            continue;
        }
        message_->SetReceiverInMsg(client->identifier());
        // Close the message to save the document as string
        message_->Close();

        // Send the string version of the message to the client.
        send_result = client->SendUpdate(message_->c_str());

        // Keep track of all the clients whose buffers are full.
        if (!send_result) {
            blocked_set->set(i);
            send_blocked_.set(i);
        }
    }
    // Reset the message to init things for the next message
    message_->Reset();
}

// marker is before next_marker in the Q. next_marker could be the tail_marker.
// 'done' is set to true only if all the clients in the union of the
// client-sets of the 2 markers are blocked.
IFMapMarker* IFMapUpdateSender::ProcessMarker(IFMapMarker *marker,
                                              IFMapMarker *next_marker,
                                              bool *done) {
    // There should never be a marker beyond the tail_marker
    assert(marker != queue_->tail_marker());

    // Get the union (total_set) of the client-sets in the 2 markers. Then, get
    // the subset of clients in the union that are blocked (blocked_set). The
    // remaining subset of clients are ready (ready_set).
    BitSet total_set = (marker->mask | next_marker->mask);
    BitSet blocked_set = (total_set & send_blocked_);
    BitSet ready_set;
    ready_set.BuildComplement(total_set, blocked_set); // *this = lhs & ~rhs

    // If all the clients are ready or all are blocked, merge marker into
    // next_marker. marker will be deleted.
    if (blocked_set.empty() || ready_set.empty()) {
        queue_->MarkerMerge(next_marker, marker, marker->mask);
        assert(next_marker->mask == total_set);
    } else {
        // We have both, ready and blocked, clients. First, merge both the
        // markers into next_marker so that next_marker has the total_set. Then
        // split next_marker into 2 markers: first with the blocked_set and the
        // second with the ready_set, with first(blocked) preceding the
        // second(ready).
        queue_->MarkerMerge(next_marker, marker, marker->mask);
        assert(next_marker->mask == total_set);
        queue_->MarkerSplitBefore(next_marker, next_marker, blocked_set);
    }
    if (ready_set.empty()) {
        // If all the clients are blocked, we are done.
        *done = true;
    } else {
        // Atleast some clients are ready to continue.
        *done = false;
    }

    // next_marker has the ready_set if done is false
    return next_marker;
}

void IFMapUpdateSender::LogAndCountSentUpdate(IFMapUpdate *update,
                                              const BitSet &base_send_set) {
    size_t total = base_send_set.count();
    // Avoid dealing with return value of BitSet::npos
    if (total) {
        string name = update->ConfigName();
        string operation = update->TypeToString();
        size_t client_id = base_send_set.find_first();
        while (total--) {
            IFMapClient *client = server_->GetClient(client_id);
            if (client) {
                IFMAP_DEBUG_ONLY(IFMapClientSendInfo, operation, name,
                                 client->identifier(), client->name());
                if (update->IsNode()) {
                    client->incr_nodes_sent();
                } else if (update->IsLink()) {
                    client->incr_links_sent();
                }
            }
            client_id = base_send_set.find_next(client_id);
        }
    }
}

<commit_msg>Do not ignore clients that are not found by IFMapUpdateSender::SendUpdate<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "ifmap/ifmap_update_sender.h"
#include "base/task.h"
#include "ifmap/ifmap_client.h"
#include "ifmap/ifmap_server.h"
#include "ifmap/ifmap_encoder.h"
#include "ifmap/ifmap_exporter.h"
#include "ifmap/ifmap_log.h"
#include "ifmap/ifmap_log_types.h"
#include "ifmap/ifmap_update.h"
#include "ifmap/ifmap_update_queue.h"

using namespace std;

IFMapUpdateSender::IFMapUpdateSender(IFMapServer *server,
                                     IFMapUpdateQueue *queue)
    : server_(server), queue_(queue), message_(new IFMapMessage()),
      task_scheduled_(false), queue_active_(false) {
}

IFMapUpdateSender::~IFMapUpdateSender() {
    delete(message_);
}

class IFMapUpdateSender::SendTask : public Task {
public:
    explicit SendTask(IFMapUpdateSender *sender)
        : Task(TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), 0),
          sender_(sender) {
    }
    virtual bool Run() {
        BitSet send_scheduled;
        sender_->GetSendScheduled(&send_scheduled);
        sender_->send_blocked_.Reset(send_scheduled);
        for (size_t i = send_scheduled.find_first(); i != BitSet::npos;
             i = send_scheduled.find_next(i)) {
            // Dequeue from client marker (i).
            sender_->Send(sender_->queue_->GetMarker(i));
        }
        if (sender_->queue_active_) {
            // Dequeue from tail marker.
            // Reset queue_active_
            sender_->Send(sender_->queue_->tail_marker());
            sender_->queue_active_ = false;
        }
        return true;
    }

    std::string Description() const { return "IFMapUpdateSender::SendTask"; }
private:
    IFMapUpdateSender *sender_;
};

void IFMapUpdateSender::StartTask() {
    if (!task_scheduled_) {
        // create new task
        SendTask *send_task = new SendTask(this);
        TaskScheduler *scheduler = TaskScheduler::GetInstance();
        scheduler->Enqueue(send_task);
        task_scheduled_ = true;
    }
}

void IFMapUpdateSender::QueueActive() {
    if (queue_active_) {
        return;
    }
    queue_active_ = true;
    tbb::mutex::scoped_lock lock(mutex_);
    StartTask();
}

void IFMapUpdateSender::SendActive(int index) {
    tbb::mutex::scoped_lock lock(mutex_);
    send_scheduled_.set(index);
    StartTask();
}

void IFMapUpdateSender::GetSendScheduled(BitSet *current) {
    tbb::mutex::scoped_lock lock(mutex_);
    *current = send_scheduled_;
    send_scheduled_.clear();
    task_scheduled_ = false;
}

void IFMapUpdateSender::CleanupClient(int index) {
    tbb::mutex::scoped_lock lock(mutex_);
    send_scheduled_.reset(index);
    send_blocked_.reset(index);
}

// We return only under 2 conditions:
// 1. All the clients in the marker are blocked.
// 2. We have finished traversing the Q.
// Invariant: while we are traversing the Q, the marker that we are working
// with only has ready clients. As soon as a client blocks, we split it out and
// continue with the ready set.
void IFMapUpdateSender::Send(IFMapMarker *imarker) {
    IFMapMarker *marker = imarker;

    // Get the clients in this marker that are blocked. If all of the clients in
    // this marker are blocked, we are done.
    BitSet blocked_clients;
    blocked_clients = (marker->mask & send_blocked_);
    if (blocked_clients == marker->mask) {
        return;
    }

    // If any of the clients are blocked, create a new marker for the set of
    // blocked clients, insert it before marker and continue with the ready
    // set.
    if (!blocked_clients.empty()) {
        queue_->MarkerSplitBefore(marker, marker, blocked_clients);
    }

    IFMapListEntry *next = queue_->Next(marker);
    BitSet base_send_set;

    // Start with the node after the 'marker'
    for (IFMapListEntry *curr = next; curr != NULL; curr = next) {
        next = queue_->Next(curr);

        if (curr->IsMarker()) {
            IFMapMarker *next_marker = static_cast<IFMapMarker *>(curr);
            // Processing the next_marker can change the send_set and all
            // clients in the next_marker should have already seen the updates
            // currently sitting in the buffer. So, flush the buffer to the
            // existing client-set before processing the marker so that we dont
            // send duplicates.
            if (!message_->IsEmpty()) {
                BitSet blocked_set;
                SendUpdate(base_send_set, &blocked_set);
            }
            bool done;
            marker = ProcessMarker(marker, next_marker, &done);
            if (done) {
                // All the clients in this marker are blocked. We are done.
                return;
            }
            // marker has the ready clients. Continue as if we are starting
            // fresh.
            base_send_set.clear();
            continue;
        }

        // ...else its an update or delete

        IFMapUpdate *update = static_cast<IFMapUpdate *>(curr);
        BitSet send_set = update->advertise() & marker->mask;
        if (send_set.empty()) {
            continue;
        }

        if (base_send_set.empty()) {
            base_send_set = send_set;
        }

        // Flush the message to all possible clients if:
        // 1. The buffer is full OR
        // 2. The send_set is changing and buffer is filled.
        if (message_->IsFull() ||
            ((base_send_set != send_set) && !message_->IsEmpty())) {

            BitSet blocked_set;
            SendUpdate(base_send_set, &blocked_set);
            if (!blocked_set.empty()) {
                // All the clients in this marker are blocked. We are done.
                if (blocked_set == marker->mask) {
                    queue_->MoveMarkerBefore(marker, curr);
                    return;
                }
                // Only a subset of clients in this marker are blocked. Insert
                // a marker for them 'before' curr since they have seen
                // everything before curr. Let the ready clients continue the
                // traversal.
                queue_->MarkerSplitBefore(marker, curr, blocked_set);
                send_set.Reset(blocked_set);
            }

            // The send_set for this marker is changing. Pick up the new one.
            base_send_set = send_set;
        }

        // base_send_set is same as send_set at this point.
        ProcessUpdate(update, base_send_set);
    }

    // The buffer will be filled in the common case of updates being added
    // after the tail_marker.
    if (!message_->IsEmpty()) {
        BitSet blk_set;
        SendUpdate(base_send_set, &blk_set);
    }
    // If the last node in the Q was the tail_marker, we would have already
    // flushed the buffer and merged with it and we would be the last node in
    // the Q.
    IFMapListEntry *last = queue_->GetLast();
    if (marker != last) {
        // Since we have reached the end of the Q, we better be the tail_marker
        assert(marker == queue_->tail_marker());
        // If we have any blocked clients, splitting markers for them is not
        // useful at this point. Just move the marker to the end of the Q,
        // immediately after last, even if it has blocked clients. Being lazy
        // is advantageous since by the time we get the next trigger, a blocked
        // client could have become ready and splitting the marker now would be
        // useless.
        queue_->MoveMarkerAfter(marker, last);
    }
    return;
}

void IFMapUpdateSender::ProcessUpdate(IFMapUpdate *update,
                                      const BitSet &base_send_set) {
    LogAndCountSentUpdate(update, base_send_set);

    // Append the contents of the update-node to the message.
    message_->EncodeUpdate(update);

    // Clean up the node if everybody has seen it.
    update->AdvertiseReset(base_send_set);
    if (update->advertise().empty()) {
        queue_->Dequeue(update);
    }
    // Update may be freed.
    server_->exporter()->StateUpdateOnDequeue(update, base_send_set,
                                              update->IsDelete());
}

// blocked_set is a subset of send_set
void IFMapUpdateSender::SendUpdate(BitSet send_set, BitSet *blocked_set) {
    IFMapClient *client;
    bool send_result;

    assert(!message_->IsEmpty());

    for (size_t i = send_set.find_first(); i != BitSet::npos;
         i = send_set.find_next(i)) {
        assert(!send_blocked_.test(i));
        client = server_->GetClient(i);
        assert(client);

        message_->SetReceiverInMsg(client->identifier());
        // Close the message to save the document as string
        message_->Close();

        // Send the string version of the message to the client.
        send_result = client->SendUpdate(message_->c_str());

        // Keep track of all the clients whose buffers are full.
        if (!send_result) {
            blocked_set->set(i);
            send_blocked_.set(i);
        }
    }
    // Reset the message to init things for the next message
    message_->Reset();
}

// marker is before next_marker in the Q. next_marker could be the tail_marker.
// 'done' is set to true only if all the clients in the union of the
// client-sets of the 2 markers are blocked.
IFMapMarker* IFMapUpdateSender::ProcessMarker(IFMapMarker *marker,
                                              IFMapMarker *next_marker,
                                              bool *done) {
    // There should never be a marker beyond the tail_marker
    assert(marker != queue_->tail_marker());

    // Get the union (total_set) of the client-sets in the 2 markers. Then, get
    // the subset of clients in the union that are blocked (blocked_set). The
    // remaining subset of clients are ready (ready_set).
    BitSet total_set = (marker->mask | next_marker->mask);
    BitSet blocked_set = (total_set & send_blocked_);
    BitSet ready_set;
    ready_set.BuildComplement(total_set, blocked_set); // *this = lhs & ~rhs

    // If all the clients are ready or all are blocked, merge marker into
    // next_marker. marker will be deleted.
    if (blocked_set.empty() || ready_set.empty()) {
        queue_->MarkerMerge(next_marker, marker, marker->mask);
        assert(next_marker->mask == total_set);
    } else {
        // We have both, ready and blocked, clients. First, merge both the
        // markers into next_marker so that next_marker has the total_set. Then
        // split next_marker into 2 markers: first with the blocked_set and the
        // second with the ready_set, with first(blocked) preceding the
        // second(ready).
        queue_->MarkerMerge(next_marker, marker, marker->mask);
        assert(next_marker->mask == total_set);
        queue_->MarkerSplitBefore(next_marker, next_marker, blocked_set);
    }
    if (ready_set.empty()) {
        // If all the clients are blocked, we are done.
        *done = true;
    } else {
        // Atleast some clients are ready to continue.
        *done = false;
    }

    // next_marker has the ready_set if done is false
    return next_marker;
}

void IFMapUpdateSender::LogAndCountSentUpdate(IFMapUpdate *update,
                                              const BitSet &base_send_set) {
    size_t total = base_send_set.count();
    // Avoid dealing with return value of BitSet::npos
    if (total) {
        string name = update->ConfigName();
        string operation = update->TypeToString();
        size_t client_id = base_send_set.find_first();
        while (total--) {
            IFMapClient *client = server_->GetClient(client_id);
            if (client) {
                IFMAP_DEBUG_ONLY(IFMapClientSendInfo, operation, name,
                                 client->identifier(), client->name());
                if (update->IsNode()) {
                    client->incr_nodes_sent();
                } else if (update->IsLink()) {
                    client->incr_links_sent();
                }
            }
            client_id = base_send_set.find_next(client_id);
        }
    }
}

<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/imageio/EmptyImageLoader.h>
#include <tev/ThreadPool.h>

#include <istream>

using namespace Eigen;
using namespace filesystem;
using namespace std;

TEV_NAMESPACE_BEGIN

bool EmptyImageLoader::canLoadFile(istream& iStream) const {
    char b[5];
    iStream.read(b, sizeof(b));

    bool result = !!iStream && iStream.gcount() == sizeof(b) && string(b, sizeof(b)) == "empty";

    iStream.clear();
    iStream.seekg(0);
    return result;
}

ImageData EmptyImageLoader::load(istream& iStream, const path& path, const string& channelSelector) const {
    ImageData result;

    string magic;
    Vector2i size;
    int nChannels;
    iStream >> magic >> size.x() >> size.y() >> nChannels;

    if (magic != "empty") {
        throw invalid_argument{tfm::format("Invalid magic empty string %s", magic)};
    }

    auto numPixels = (DenseIndex)size.x() * size.y();
    if (numPixels == 0) {
        throw invalid_argument{"Image has zero pixels."};
    }

    set<string> layerNames;
    for (int i = 0; i < nChannels; ++i) {
        // The following lines decode strings by prefix length.
        // The reason for using sthis encoding is to allow arbitrary characters,
        // including whitespaces, in the channel names.
        std::vector<char> channelNameData;
        int length;
        iStream >> length;
        channelNameData.resize(length+1, 0);
        iStream.read(channelNameData.data(), length);

        string channelName = channelNameData.data();

        result.channels.emplace_back(Channel{channelName, size});
        result.channels.back().setZero();
        layerNames.insert(Channel::head(channelName));
    }

    for (const string& layer : layerNames) {
        result.layers.emplace_back(layer);
    }

    return result;
}

TEV_NAMESPACE_END
<commit_msg>Get rid of Windows compiler warnings<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/imageio/EmptyImageLoader.h>
#include <tev/ThreadPool.h>

#include <istream>

using namespace Eigen;
using namespace filesystem;
using namespace std;

TEV_NAMESPACE_BEGIN

bool EmptyImageLoader::canLoadFile(istream& iStream) const {
    char b[5];
    iStream.read(b, sizeof(b));

    bool result = !!iStream && iStream.gcount() == sizeof(b) && string(b, sizeof(b)) == "empty";

    iStream.clear();
    iStream.seekg(0);
    return result;
}

ImageData EmptyImageLoader::load(istream& iStream, const path&, const string&) const {
    ImageData result;

    string magic;
    Vector2i size;
    int nChannels;
    iStream >> magic >> size.x() >> size.y() >> nChannels;

    if (magic != "empty") {
        throw invalid_argument{tfm::format("Invalid magic empty string %s", magic)};
    }

    auto numPixels = (DenseIndex)size.x() * size.y();
    if (numPixels == 0) {
        throw invalid_argument{"Image has zero pixels."};
    }

    set<string> layerNames;
    for (int i = 0; i < nChannels; ++i) {
        // The following lines decode strings by prefix length.
        // The reason for using sthis encoding is to allow arbitrary characters,
        // including whitespaces, in the channel names.
        std::vector<char> channelNameData;
        int length;
        iStream >> length;
        channelNameData.resize(length+1, 0);
        iStream.read(channelNameData.data(), length);

        string channelName = channelNameData.data();

        result.channels.emplace_back(Channel{channelName, size});
        result.channels.back().setZero();
        layerNames.insert(Channel::head(channelName));
    }

    for (const string& layer : layerNames) {
        result.layers.emplace_back(layer);
    }

    return result;
}

TEV_NAMESPACE_END
<|endoftext|>


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

// The program demonstrates basic shader compilation using the Shaderc C++ API.
// For clarity, each method is deliberately self-contained.
//
// Techniques demonstrated:
//  - Preprocessing GLSL source text
//  - Compiling a shader to SPIR-V assembly text
//  - Compliing a shader to a SPIR-V binary module
//  - Setting basic options: setting a preprocessor symbol.
//  - Checking compilation status and extracting an error message.

#include <iostream>
#include <string>
#include <vector>

#include <shaderc/shaderc.hpp>

// Returns GLSL shader source text after preprocessing.
std::string preprocess_shader(const std::string& source_name,
                              shaderc_shader_kind kind,
                              const std::string& source) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");

  shaderc::PreprocessedSourceCompilationResult result = compiler.PreprocessGlsl(
      source.c_str(), source.size(), kind, source_name.c_str(), options);

  if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << result.GetErrorMessage();
    return "";
  }

  return std::string(result.cbegin(), result.cend());
}

// Compiles a shader to SPIR-V assembly. Returns the assembly text
// as a string.
std::string compile_file_to_assembly(const std::string& source_name,
                                     shaderc_shader_kind kind,
                                     const std::string& source) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");

  shaderc::AssemblyCompilationResult result = compiler.CompileGlslToSpvAssembly(
      source.c_str(), source.size(), kind, source_name.c_str(), options);

  if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << result.GetErrorMessage();
    return "";
  }

  return std::string(result.cbegin(), result.cend());
}

// Compiles a shader to a SPIR-V binary. Returns the binary as
// a vector of 32-bit words.
std::vector<uint32_t> compile_file(const std::string& source_name,
                                   shaderc_shader_kind kind,
                                   const std::string& source) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");

  shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(
      source.c_str(), source.size(), kind, source_name.c_str(), options);

  if (module.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << module.GetErrorMessage();
    return std::vector<uint32_t>();
  }

  std::vector<uint32_t> result(module.cbegin(), module.cend());
  return result;
}

int main() {
  const char kShaderSource[] =
      "#version 310 es\nvoid main() {int x = MY_DEFINE; }\n";

  auto preprocessed = preprocess_shader(
      "shader_src", shaderc_glsl_vertex_shader, kShaderSource);
  std::cout << "Compiled a vertex shader resulting in preprocessed text:"
            << std::endl
            << preprocessed << std::endl;

  auto assembly = compile_file_to_assembly(
      "shader_src", shaderc_glsl_vertex_shader, kShaderSource);
  std::cout << "SPIR-V assembly:" << std::endl << assembly << std::endl;

  auto spirv =
      compile_file("shader_src", shaderc_glsl_vertex_shader, kShaderSource);
  std::cout << "Compiled to a binary module with " << spirv.size() << " words."
            << std::endl;

  const char kBadShaderSource[] =
      "#version 310 es\nint main() { int main_should_be_void; }\n";

  std::cout << std::endl << "Compiling a bad shader:" << std::endl;
  compile_file("bad_src", shaderc_glsl_vertex_shader, kBadShaderSource);

  return 0;
}
<commit_msg>Add cases in examples to show optimization.<commit_after>// Copyright 2016 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// The program demonstrates basic shader compilation using the Shaderc C++ API.
// For clarity, each method is deliberately self-contained.
//
// Techniques demonstrated:
//  - Preprocessing GLSL source text
//  - Compiling a shader to SPIR-V assembly text
//  - Compliing a shader to a SPIR-V binary module
//  - Performing optimization with compilation
//  - Setting basic options: setting a preprocessor symbol.
//  - Checking compilation status and extracting an error message.

#include <iostream>
#include <string>
#include <vector>

#include <shaderc/shaderc.hpp>

// Returns GLSL shader source text after preprocessing.
std::string preprocess_shader(const std::string& source_name,
                              shaderc_shader_kind kind,
                              const std::string& source) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");

  shaderc::PreprocessedSourceCompilationResult result =
      compiler.PreprocessGlsl(source, kind, source_name.c_str(), options);

  if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << result.GetErrorMessage();
    return "";
  }

  return {result.cbegin(), result.cend()};
}

// Compiles a shader to SPIR-V assembly. Returns the assembly text
// as a string.
std::string compile_file_to_assembly(const std::string& source_name,
                                     shaderc_shader_kind kind,
                                     const std::string& source,
                                     bool optimize = false) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");
  if (optimize) options.SetOptimizationLevel(shaderc_optimization_level_size);

  shaderc::AssemblyCompilationResult result = compiler.CompileGlslToSpvAssembly(
      source, kind, source_name.c_str(), options);

  if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << result.GetErrorMessage();
    return "";
  }

  return {result.cbegin(), result.cend()};
}

// Compiles a shader to a SPIR-V binary. Returns the binary as
// a vector of 32-bit words.
std::vector<uint32_t> compile_file(const std::string& source_name,
                                   shaderc_shader_kind kind,
                                   const std::string& source,
                                   bool optimize = false) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");
  if (optimize) options.SetOptimizationLevel(shaderc_optimization_level_size);

  shaderc::SpvCompilationResult module =
      compiler.CompileGlslToSpv(source, kind, source_name.c_str(), options);

  if (module.GetCompilationStatus() != shaderc_compilation_status_success) {
    std::cerr << module.GetErrorMessage();
    return std::vector<uint32_t>();
  }

  return {module.cbegin(), module.cend()};
}

int main() {
  const char kShaderSource[] =
      "#version 310 es\n"
      "void main() { int x = MY_DEFINE; }\n";

  {  // Preprocessing
    auto preprocessed = preprocess_shader(
        "shader_src", shaderc_glsl_vertex_shader, kShaderSource);
    std::cout << "Compiled a vertex shader resulting in preprocessed text:"
              << std::endl
              << preprocessed << std::endl;
  }

  {  // Compiling
    auto assembly = compile_file_to_assembly(
        "shader_src", shaderc_glsl_vertex_shader, kShaderSource);
    std::cout << "SPIR-V assembly:" << std::endl << assembly << std::endl;

    auto spirv =
        compile_file("shader_src", shaderc_glsl_vertex_shader, kShaderSource);
    std::cout << "Compiled to a binary module with " << spirv.size()
              << " words." << std::endl;
  }

  {  // Compiling with optimizing
    auto assembly =
        compile_file_to_assembly("shader_src", shaderc_glsl_vertex_shader,
                                 kShaderSource, /* optimize = */ true);
    std::cout << "Optimized SPIR-V assembly:" << std::endl
              << assembly << std::endl;

    auto spirv = compile_file("shader_src", shaderc_glsl_vertex_shader,
                              kShaderSource, /* optimize = */ true);
    std::cout << "Compiled to an optimized binary module with " << spirv.size()
              << " words." << std::endl;
  }

  {  // Error case
    const char kBadShaderSource[] =
        "#version 310 es\nint main() { int main_should_be_void; }\n";

    std::cout << std::endl << "Compiling a bad shader:" << std::endl;
    compile_file("bad_src", shaderc_glsl_vertex_shader, kBadShaderSource);
  }

  return 0;
}
<|endoftext|>