<commit_before>#pragma once

#include <cassert>
#include <iostream>
#include <string>

#include "fixfmt/math.hh"

//------------------------------------------------------------------------------

namespace {

inline bool
within(
  unsigned char min,
  unsigned char val,
  unsigned char max)
  noexcept
{
  return min <= val && val <= max;
}

}  // anonymous namespace

//------------------------------------------------------------------------------

namespace fixfmt {

using std::string;

constexpr char const* ELLIPSIS = "\u2026";
constexpr char ANSI_ESCAPE = '\x1b';

/*
 * Advances an iterator on a UTF-8 string by one code point.
 *
 * FIXME: Take an end parameter.
 */
inline bool
next_utf8(
  string::const_iterator& i)
  noexcept
{
  unsigned char c = *i++;
  if ((c & 0xc0) == 0xc0) {
    // It's multibyte.  The number of bytes is the number of MSB's before
    // the first zero.
    // FIXME: Improve this.
    ++i;
    if ((c & 0xe0) == 0xe0) {
      ++i;
      if ((c & 0xf0) == 0xf0) {
        ++i;
        if ((c & 0xf8) == 0xf8) {
          ++i;
          if ((c & 0xfc) == 0xfc)
            ++i;
        }
      }
    }
  }
  return true;
}

/*
 * Returns the number of code points in a UTF-8-encoded string.
 */
inline size_t
utf8_length(
  string const& str)
  noexcept
{
  size_t length = 0;
  // FIXME: Problem if the last code point is malformed.
  for (auto i = str.begin(); i != str.end(); next_utf8(i))
    ++length;
  return length;
}

/*
 * Advances an iterator past an ANSI escape sequence, if at one.
 */
inline bool
skip_ansi_escape(
  string::const_iterator& i,
  string::const_iterator const& end)
  noexcept
{
  assert(i != end);
  if (*i == ANSI_ESCAPE) {
    ++i;
    if (i != end && *i++ == '[')
      // Got CSI.  Read until we pass a final byte.
      while (i != end && !within(64, *i++, 126))
        ;
    else
      // Assume single-character escape.
      ;
    return true;
  }
  else
    return false;
}

/*
 * Returns the number of code points in a UTF-8-encoded string, skipping
 * escape sequences.
 */
inline size_t
string_length(
  string const& str)
  noexcept
{
  size_t length = 0;
  auto const& end = str.end();
  // FIXME: Problem if the last code point is malformed.
  // Count characters.
  for (auto i = str.begin(); i != end; )
    if (skip_ansi_escape(i, end))
      ;
    else {
      ++length;
      next_utf8(i);
    }
  return length;
}

/*
 * Truncates a string to `length` code points, skipping escape sequences.
 */
inline void
string_truncate(
  string& str,
  size_t const length)
{
  auto const& begin = str.cbegin();
  auto const& end = str.cend();
  for (auto i = begin; i != end; !skip_ansi_escape(i, end) && next_utf8(i))
    if (i - begin == (int) length) {
      str.resize(i - begin);
      break;
    }
}

/*
 * Concatenates copies of `str` up to `length`.  If `length` is not divisible
 * by the length of `str`, the last copy is partial.
 */
inline string
fill(
  string const& str,
  size_t const length)
{
  size_t const str_len = string_length(str);
  assert(str_len > 0);
  if (str.length() == 1)
    return string(length, str[0]);
  else {
    string result;
    result.reserve(length);
    // Concatenate whole copies.
    size_t l = length;
    while (l >= str_len) {
      result += str;
      l -= str_len;
    }
    if (l > 0) {
      // Concatenate a partial copy.
      auto i = str.begin();
      for (; l > 0; --l)
        next_utf8(i);
      result.append(str.begin(), i);
    }
    assert(string_length(result) == length);
    return result;
  }
}

float constexpr PAD_POSITION_LEFT_JUSTIFY   = 1;
float constexpr PAD_POSITION_RIGHT_JUSTIFY  = 0;
float constexpr PAD_POSITION_CENTER         = 0.5;

/**
 * Pads a string in to fixed length on one or both sides.
 *
 * If position=1, the string is padded at the right, thus left-justified.  If
 * position=0, the string is padded at the left, thus right-justified.  If
 * position=0.5, the string is padded equally on both sides, thus centered.
 */
inline string
pad(
  string const& str,
  size_t const length,
  string const& pad=" ",
  float position=PAD_POSITION_LEFT_JUSTIFY)
{
  assert(string_length(pad) > 0);
  assert(0 <= position);
  assert(position <= 1);
  size_t const str_len = string_length(str);
  if (str_len < length) {
    size_t const pad_len = length - str_len;
    size_t const left_len = (size_t) round((1 - position) * pad_len);
    string const result =
      fill(pad, left_len) + str + fill(pad, pad_len - left_len);
    assert(string_length(result) == length);
    return result;
  }
  else
    return str;
}

inline string
center(
  string const& str,
  size_t const length,
  string const& pad=" ")
{
  return fixfmt::pad(str, length, pad, PAD_POSITION_CENTER);
}

/**
 * Trims a string to a fixed length by eliding characters and replacing them
 * with an ellipsis.
 */
inline string
elide(
  string const& str,
  size_t const max_length,
  string const& ellipsis=ELLIPSIS,
  float const position=1)
{
  size_t const ellipsis_len = string_length(ellipsis);
  assert(max_length >= ellipsis_len);
  assert(0 <= position);
  assert(position <= 1);

  size_t const length = string_length(str);
  if (length <= max_length)
    return str;
  else {
    size_t const keep   = max_length - ellipsis_len;
    size_t const nleft  = (size_t) round(position * keep);
    size_t const nright = keep - nleft;
    string elided;
    if (nleft > 0)
      elided += str.substr(0, nleft);
    elided += ellipsis;
    if (nright > 0)
      elided += str.substr(length - nright);
    assert(string_length(elided) == max_length);
    return elided;
  }
}

/**
 * Either pads or elides a string to achieve a fixed length.
 */
inline string
palide(
  string const& str,
  size_t const length,
  string const& ellipsis=ELLIPSIS,
  string const& pad=" ",
  float const elide_position=1,
  float pad_position=1)
{
  return fixfmt::pad(
    elide(str, length, ellipsis, elide_position), length, pad, pad_position);
}

//------------------------------------------------------------------------------

}  // namespace fixfmt

<commit_msg>Deprecate center().<commit_after>#pragma once

#include <cassert>
#include <iostream>
#include <string>

#include "fixfmt/math.hh"

//------------------------------------------------------------------------------

namespace {

inline bool
within(
  unsigned char min,
  unsigned char val,
  unsigned char max)
  noexcept
{
  return min <= val && val <= max;
}

}  // anonymous namespace

//------------------------------------------------------------------------------

namespace fixfmt {

using std::string;

constexpr char const* ELLIPSIS = "\u2026";
constexpr char ANSI_ESCAPE = '\x1b';

/*
 * Advances an iterator on a UTF-8 string by one code point.
 *
 * FIXME: Take an end parameter.
 */
inline bool
next_utf8(
  string::const_iterator& i)
  noexcept
{
  unsigned char c = *i++;
  if ((c & 0xc0) == 0xc0) {
    // It's multibyte.  The number of bytes is the number of MSB's before
    // the first zero.
    // FIXME: Improve this.
    ++i;
    if ((c & 0xe0) == 0xe0) {
      ++i;
      if ((c & 0xf0) == 0xf0) {
        ++i;
        if ((c & 0xf8) == 0xf8) {
          ++i;
          if ((c & 0xfc) == 0xfc)
            ++i;
        }
      }
    }
  }
  return true;
}

/*
 * Returns the number of code points in a UTF-8-encoded string.
 */
inline size_t
utf8_length(
  string const& str)
  noexcept
{
  size_t length = 0;
  // FIXME: Problem if the last code point is malformed.
  for (auto i = str.begin(); i != str.end(); next_utf8(i))
    ++length;
  return length;
}

/*
 * Advances an iterator past an ANSI escape sequence, if at one.
 */
inline bool
skip_ansi_escape(
  string::const_iterator& i,
  string::const_iterator const& end)
  noexcept
{
  assert(i != end);
  if (*i == ANSI_ESCAPE) {
    ++i;
    if (i != end && *i++ == '[')
      // Got CSI.  Read until we pass a final byte.
      while (i != end && !within(64, *i++, 126))
        ;
    else
      // Assume single-character escape.
      ;
    return true;
  }
  else
    return false;
}

/*
 * Returns the number of code points in a UTF-8-encoded string, skipping
 * escape sequences.
 */
inline size_t
string_length(
  string const& str)
  noexcept
{
  size_t length = 0;
  auto const& end = str.end();
  // FIXME: Problem if the last code point is malformed.
  // Count characters.
  for (auto i = str.begin(); i != end; )
    if (skip_ansi_escape(i, end))
      ;
    else {
      ++length;
      next_utf8(i);
    }
  return length;
}

/*
 * Truncates a string to `length` code points, skipping escape sequences.
 */
inline void
string_truncate(
  string& str,
  size_t const length)
{
  auto const& begin = str.cbegin();
  auto const& end = str.cend();
  for (auto i = begin; i != end; !skip_ansi_escape(i, end) && next_utf8(i))
    if (i - begin == (int) length) {
      str.resize(i - begin);
      break;
    }
}

/*
 * Concatenates copies of `str` up to `length`.  If `length` is not divisible
 * by the length of `str`, the last copy is partial.
 */
inline string
fill(
  string const& str,
  size_t const length)
{
  size_t const str_len = string_length(str);
  assert(str_len > 0);
  if (str.length() == 1)
    return string(length, str[0]);
  else {
    string result;
    result.reserve(length);
    // Concatenate whole copies.
    size_t l = length;
    while (l >= str_len) {
      result += str;
      l -= str_len;
    }
    if (l > 0) {
      // Concatenate a partial copy.
      auto i = str.begin();
      for (; l > 0; --l)
        next_utf8(i);
      result.append(str.begin(), i);
    }
    assert(string_length(result) == length);
    return result;
  }
}

float constexpr PAD_POSITION_LEFT_JUSTIFY   = 1;
float constexpr PAD_POSITION_RIGHT_JUSTIFY  = 0;
float constexpr PAD_POSITION_CENTER         = 0.5;

/**
 * Pads a string in to fixed length on one or both sides.
 *
 * If position=1, the string is padded at the right, thus left-justified.  If
 * position=0, the string is padded at the left, thus right-justified.  If
 * position=0.5, the string is padded equally on both sides, thus centered.
 */
inline string
pad(
  string const& str,
  size_t const length,
  string const& pad=" ",
  float position=PAD_POSITION_LEFT_JUSTIFY)
{
  assert(string_length(pad) > 0);
  assert(0 <= position);
  assert(position <= 1);
  size_t const str_len = string_length(str);
  if (str_len < length) {
    size_t const pad_len = length - str_len;
    size_t const left_len = (size_t) round((1 - position) * pad_len);
    string const result =
      fill(pad, left_len) + str + fill(pad, pad_len - left_len);
    assert(string_length(result) == length);
    return result;
  }
  else
    return str;
}

/*
 * Deprecated.  Use `pad(str, len, pad, PAD_POSITION_CENTER)` instead.
 */
inline string
center(
  string const& str,
  size_t const length,
  string const& pad=" ")
{
  return fixfmt::pad(str, length, pad, PAD_POSITION_CENTER);
}

/**
 * Trims a string to a fixed length by eliding characters and replacing them
 * with an ellipsis.
 */
inline string
elide(
  string const& str,
  size_t const max_length,
  string const& ellipsis=ELLIPSIS,
  float const position=1)
{
  size_t const ellipsis_len = string_length(ellipsis);
  assert(max_length >= ellipsis_len);
  assert(0 <= position);
  assert(position <= 1);

  size_t const length = string_length(str);
  if (length <= max_length)
    return str;
  else {
    size_t const keep   = max_length - ellipsis_len;
    size_t const nleft  = (size_t) round(position * keep);
    size_t const nright = keep - nleft;
    string elided;
    if (nleft > 0)
      elided += str.substr(0, nleft);
    elided += ellipsis;
    if (nright > 0)
      elided += str.substr(length - nright);
    assert(string_length(elided) == max_length);
    return elided;
  }
}

/**
 * Either pads or elides a string to achieve a fixed length.
 */
inline string
palide(
  string const& str,
  size_t const length,
  string const& ellipsis=ELLIPSIS,
  string const& pad=" ",
  float const elide_position=1,
  float pad_position=1)
{
  return fixfmt::pad(
    elide(str, length, ellipsis, elide_position), length, pad, pad_position);
}

//------------------------------------------------------------------------------

}  // namespace fixfmt

<|endoftext|>


<commit_before>#include "script.hpp"
#include "filesystem.hpp"
#include "logger.hpp"

class LuaScript
{
public:
    LuaScript()
    {
        InitLua();
    }

    ~LuaScript()
    {
        HaltLua();
    }

    // call a lua function.
    // you must specify the quantity of of params and returns.
    int CallLua(std::string func, int num_params, int num_returns)
    {
        // on error, execute lua function debug.traceback
        // debug is a table, put it on the stack
        lua_getglobal(mLuaState, "debug");

        // -1 is the top of the stack
        lua_getfield(mLuaState, -1, "traceback");

        // traceback is on top, remove debug from 2nd spot
        lua_remove(mLuaState, -2);

        mErrorHandlerStackIndex = lua_gettop(mLuaState);

        // get the lua function and execute it
        lua_getglobal(mLuaState, func.c_str());
        const int ret = lua_pcall(mLuaState, num_params, num_returns, mErrorHandlerStackIndex);
        if (ret)
        {
            LOG_ERROR("Lua call failed (" << ErrorToString(ret) << ": " << lua_tostring(mLuaState, -1));
        }

        // remove the error handler from the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    bool FunctionExists(std::string func)
    {
        // try to put the function on top of the stack
        lua_getglobal(mLuaState, func.c_str());

        // check that value on top of stack is not nil
        bool ret = !lua_isnil(mLuaState, -1);

        // get rid of the value we put on the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    lua_State* State()
    {
        return mLuaState;
    }

private:
    void InitLua()
    {
        mLuaState = luaL_newstate();
        luaL_openlibs(mLuaState);

        set_redirected_print();
    }

    void HaltLua()
    {
        lua_close(mLuaState);
    }

    static std::string LuaTypeToString(int index)
    {
        switch (index)
        {
        case LUA_TNIL:            return "nil";
        case LUA_TNUMBER:         return "number";
        case LUA_TBOOLEAN:        return "boolean";
        case LUA_TSTRING:         return "string";
        case LUA_TTABLE:          return "table";
        case LUA_TFUNCTION:       return "function";
        case LUA_TUSERDATA:       return "userdata";
        case LUA_TTHREAD:         return "thread";
        case LUA_TLIGHTUSERDATA:  return "light userdata";
        default:                  return "unknown type";
        }
    }

    static std::string ErrorToString(int resultcode)
    {
        switch (resultcode)
        {
        case 0:             return "Success";
        case LUA_ERRRUN:    return "Runtime error";
        case LUA_ERRSYNTAX: return "Syntax error";
        case LUA_ERRERR:    return "Error with error alert mechanism.";
        case LUA_ERRFILE:   return "Couldn't open or read file";
        default:            return "Unknown error: " + std::to_string(resultcode);
        }
    }

    static int script_log(lua_State* L)
    {
        const int nargs = lua_gettop(L);
        for (int i = 1; i <= nargs; ++i)
        {
            if (lua_isstring(L, i))
            {
                LOG_INFO(lua_tostring(L, i));
            }
            else
            {
                LOG_ERROR("TODO: Print this type");
            }
        }
        return 0;
    }

    int set_redirected_print()
    {
        lua_getglobal(mLuaState, "_G");
        lua_register(mLuaState, "print", script_log);
        lua_pop(mLuaState, 1); // global table
        return 0;
    }

private:
    lua_State* mLuaState = nullptr;
    int mErrorHandlerStackIndex = 0;
};

Script::Script()
{

}

Script::~Script()
{

}

bool Script::Init(FileSystem& fs)
{
    const std::string myfile = fs.GameData().BasePath() + "data/scripts/main.lua";

    mScript = std::make_unique<LuaScript>();

    luaL_dofile(mScript->State(), myfile.c_str());

    return true;
}

void Script::Update()
{
    const std::string myfn = "Update";
    const int res = mScript->CallLua(myfn, 0, 0);
    if (res)
    {

    }
}
<commit_msg>don't create a string per call<commit_after>#include "script.hpp"
#include "filesystem.hpp"
#include "logger.hpp"

class LuaScript
{
public:
    LuaScript()
    {
        InitLua();
    }

    ~LuaScript()
    {
        HaltLua();
    }

    // call a lua function.
    // you must specify the quantity of of params and returns.
    int ScriptCall(const char* func, int num_params, int num_returns)
    {
        // on error, execute lua function debug.traceback
        // debug is a table, put it on the stack
        lua_getglobal(mLuaState, "debug");

        // -1 is the top of the stack
        lua_getfield(mLuaState, -1, "traceback");

        // traceback is on top, remove debug from 2nd spot
        lua_remove(mLuaState, -2);

        mErrorHandlerStackIndex = lua_gettop(mLuaState);

        // get the lua function and execute it
        lua_getglobal(mLuaState, func);
        const int ret = lua_pcall(mLuaState, num_params, num_returns, mErrorHandlerStackIndex);
        if (ret)
        {
            LOG_ERROR("Lua call failed (" << ErrorToString(ret) << ": " << lua_tostring(mLuaState, -1));
        }

        // remove the error handler from the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    bool FunctionExists(std::string func)
    {
        // try to put the function on top of the stack
        lua_getglobal(mLuaState, func.c_str());

        // check that value on top of stack is not nil
        bool ret = !lua_isnil(mLuaState, -1);

        // get rid of the value we put on the stack
        lua_pop(mLuaState, 1);

        return ret;
    }

    lua_State* State()
    {
        return mLuaState;
    }

private:
    void InitLua()
    {
        mLuaState = luaL_newstate();
        luaL_openlibs(mLuaState);

        set_redirected_print();
    }

    void HaltLua()
    {
        lua_close(mLuaState);
    }

    static std::string LuaTypeToString(int index)
    {
        switch (index)
        {
        case LUA_TNIL:            return "nil";
        case LUA_TNUMBER:         return "number";
        case LUA_TBOOLEAN:        return "boolean";
        case LUA_TSTRING:         return "string";
        case LUA_TTABLE:          return "table";
        case LUA_TFUNCTION:       return "function";
        case LUA_TUSERDATA:       return "userdata";
        case LUA_TTHREAD:         return "thread";
        case LUA_TLIGHTUSERDATA:  return "light userdata";
        default:                  return "unknown type";
        }
    }

    static std::string ErrorToString(int resultcode)
    {
        switch (resultcode)
        {
        case 0:             return "Success";
        case LUA_ERRRUN:    return "Runtime error";
        case LUA_ERRSYNTAX: return "Syntax error";
        case LUA_ERRERR:    return "Error with error alert mechanism.";
        case LUA_ERRFILE:   return "Couldn't open or read file";
        default:            return "Unknown error: " + std::to_string(resultcode);
        }
    }

    static int script_log(lua_State* L)
    {
        const int nargs = lua_gettop(L);
        for (int i = 1; i <= nargs; ++i)
        {
            if (lua_isstring(L, i))
            {
                LOG_INFO(lua_tostring(L, i));
            }
            else
            {
                LOG_ERROR("TODO: Print this type");
            }
        }
        return 0;
    }

    int set_redirected_print()
    {
        lua_getglobal(mLuaState, "_G");
        lua_register(mLuaState, "print", script_log);
        lua_pop(mLuaState, 1); // global table
        return 0;
    }

private:
    lua_State* mLuaState = nullptr;
    int mErrorHandlerStackIndex = 0;
};

Script::Script()
{

}

Script::~Script()
{

}

bool Script::Init(FileSystem& fs)
{
    const std::string myfile = fs.GameData().BasePath() + "data/scripts/main.lua";

    mScript = std::make_unique<LuaScript>();

    luaL_dofile(mScript->State(), myfile.c_str());

    return true;
}

void Script::Update()
{
    const int res = mScript->ScriptCall("Update", 0, 0);
    if (res)
    {

    }
}
<|endoftext|>


<commit_before>#include "GraphEventSubscriber.hpp"
#include "GraphEventPublisher.hpp"
#include <cassert>

using namespace envire::core;

GraphEventSubscriber::GraphEventSubscriber(envire::core::GraphEventPublisher* pPublisher) :
    pPublisher(pPublisher)
{
    subscribe(pPublisher);
}

GraphEventSubscriber::GraphEventSubscriber() : pPublisher(nullptr)
{
}

void GraphEventSubscriber::subscribe(GraphEventPublisher* pPublisher)
{
    assert(pPublisher != nullptr);
    pPublisher->subscribe(this);
}

GraphEventSubscriber::~GraphEventSubscriber()
{
    if(nullptr != pPublisher)
    {
      pPublisher->unsubscribe(this);
      pPublisher = nullptr;
    }
}
<commit_msg>events: it can happen that the subscriber is deleted but never unsubscribed<commit_after>#include "GraphEventSubscriber.hpp"
#include "GraphEventPublisher.hpp"
#include <cassert>

using namespace envire::core;

GraphEventSubscriber::GraphEventSubscriber(envire::core::GraphEventPublisher* pPublisher) :
    pPublisher(nullptr)
{
    subscribe(pPublisher);
}

GraphEventSubscriber::GraphEventSubscriber() : pPublisher(nullptr)
{
}

void GraphEventSubscriber::subscribe(GraphEventPublisher* pPublisher)
{
    assert(pPublisher != nullptr);
    // unsubscribe if already subscribed
    if(this->pPublisher != nullptr)
        this->pPublisher->unsubscribe(this);
    // subscribe to new publisher
    this->pPublisher = pPublisher;
    this->pPublisher->subscribe(this);
}

GraphEventSubscriber::~GraphEventSubscriber()
{
    if(nullptr != pPublisher)
    {
      pPublisher->unsubscribe(this);
      pPublisher = nullptr;
    }
}
<|endoftext|>


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

#include <folly/init/Init.h>
#include <folly/logging/Init.h>
#include <folly/logging/xlog.h>

#include <folly/logging/example/lib.h>

using namespace example;

// Invoking code that uses XLOG() statements before main() is safe.
// This will use default log settings defined by folly::initializeLoggerDB().
static ExampleObject staticInitialized("static");

// Configure folly to enable INFO+ messages, and everything else to
// enable WARNING+.
//
// Set the default log handler to log asynchronously by default
// (except log messages with level WARNING and above synchronously)
FOLLY_INIT_LOGGING_CONFIG(
    ".=WARNING,folly=INFO; default:async=true,sync_level=WARNING");

int main(int argc, char* argv[]) {
  // Using log macros before calling folly::initLogging() will use the default
  // log settings defined by folly::initializeLoggerDB().  The default behavior
  // is to log WARNING+ messages to stderr.
  XLOG(INFO) << "log messages less than WARNING will be ignored";
  XLOG(ERR) << "error messages before initLogging() will be logged to stderr";

  // folly::Init() will automatically initialize the logging settings based on
  // the FOLLY_INIT_LOGGING_CONFIG declaration above and the --logging command
  // line flag.
  folly::Init init(&argc, &argv);

  // All XLOG() statements in this file will log to the category
  // folly.logging.example.main
  XLOG(INFO, "now the normal log settings have been applied");

  XLOG(DBG1, "log arguments are concatenated: ", 12345, ", ", 92.0);
  XLOGF(DBG1, "XLOGF supports {}-style formatting: {:.3f}", "python", 1.0 / 3);
  XLOG(DBG2) << "streaming syntax is also supported: " << 1234;
  XLOG(DBG2, "if you really want, ", "you can even")
      << " mix function-style and streaming syntax: " << 42;
  XLOGF(DBG3, "and {} can mix {} style", "you", "format") << " and streaming";

  ExampleObject("foo");
  XLOG(INFO) << "main returning";
  return 0;
}
<commit_msg>update the logging example to reflect the current default level<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/init/Init.h>
#include <folly/logging/Init.h>
#include <folly/logging/xlog.h>

#include <folly/logging/example/lib.h>

using namespace example;

// Invoking code that uses XLOG() statements before main() is safe.
// This will use default log settings defined by folly::initializeLoggerDB().
static ExampleObject staticInitialized("static");

// Configure folly to enable INFO+ messages, and everything else to
// enable WARNING+.
//
// Set the default log handler to log asynchronously by default
// (except log messages with level WARNING and above synchronously)
FOLLY_INIT_LOGGING_CONFIG(
    ".=WARNING,folly=INFO; default:async=true,sync_level=WARNING");

int main(int argc, char* argv[]) {
  // Using log macros before calling folly::initLogging() will use the default
  // log settings defined by folly::initializeLoggerDB().  The default behavior
  // is to log INFO+ messages to stderr.
  XLOG(DBG) << "log messages less than INFO will be ignored before initLogging";
  XLOG(ERR) << "error messages before initLogging() will be logged to stderr";

  // folly::Init() will automatically initialize the logging settings based on
  // the FOLLY_INIT_LOGGING_CONFIG declaration above and the --logging command
  // line flag.
  folly::Init init(&argc, &argv);

  // All XLOG() statements in this file will log to the category
  // folly.logging.example.main
  XLOG(INFO, "now the normal log settings have been applied");

  XLOG(DBG1, "log arguments are concatenated: ", 12345, ", ", 92.0);
  XLOGF(DBG1, "XLOGF supports {}-style formatting: {:.3f}", "python", 1.0 / 3);
  XLOG(DBG2) << "streaming syntax is also supported: " << 1234;
  XLOG(DBG2, "if you really want, ", "you can even")
      << " mix function-style and streaming syntax: " << 42;
  XLOGF(DBG3, "and {} can mix {} style", "you", "format") << " and streaming";

  ExampleObject("foo");
  XLOG(INFO) << "main returning";
  return 0;
}
<|endoftext|>


<commit_before>/*
 * main.cpp (Tutorial11_PostProcessing)
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "../tutorial.h"

class Tutorial11 : public Tutorial
{

    const LLGL::ColorRGBAf  glowColor           = { 0.9f, 0.7f, 0.3f, 1.0f };

    LLGL::ShaderProgram*    shaderProgramScene  = nullptr;
    LLGL::ShaderProgram*    shaderProgramBlur   = nullptr;
    LLGL::ShaderProgram*    shaderProgramFinal  = nullptr;

    LLGL::GraphicsPipeline* pipelineScene       = nullptr;
    LLGL::GraphicsPipeline* pipelineBlur        = nullptr;
    LLGL::GraphicsPipeline* pipelineFinal       = nullptr;

    LLGL::VertexFormat      vertexFormatScene;

    unsigned int            numSceneVertices    = 0;

    LLGL::Buffer*           vertexBufferScene   = nullptr;
    LLGL::Buffer*           vertexBufferNull    = nullptr;

    LLGL::Buffer*           constantBufferScene = nullptr;
    LLGL::Buffer*           constantBufferBlur  = nullptr;

    LLGL::Sampler*          colorMapSampler     = nullptr;
    LLGL::Sampler*          glossMapSampler     = nullptr;

    LLGL::Texture*          colorMap            = nullptr;
    LLGL::Texture*          glossMap            = nullptr;
    LLGL::Texture*          glossMapBlurX       = nullptr;
    LLGL::Texture*          glossMapBlurY       = nullptr;

    LLGL::RenderTarget*     renderTargetScene   = nullptr;
    LLGL::RenderTarget*     renderTargetBlurX   = nullptr;
    LLGL::RenderTarget*     renderTargetBlurY   = nullptr;

    struct SceneSettings
    {
        Gs::Matrix4f        wvpMatrix;
        Gs::Matrix4f        wMatrix;
        LLGL::ColorRGBAf    diffuse;
        LLGL::ColorRGBAf    glossiness;
        float               intensity           = 1.0f;
        float               _pad0[3];
    }
    sceneSettings;

    struct BlurSettings
    {
        Gs::Vector2f        blurShift;
        float               _pad0[2];
    }
    blurSettings;

public:

    Tutorial11() :
        Tutorial( L"LLGL Tutorial 11: PostProcessing", { 800, 600 }, 0 )
    {
        // Create all graphics objects
        CreateBuffers();
        LoadShaders();
        CreatePipelines();
        CreateSamplers();
        CreateTextures();
        CreateRenderTargets();

        // Show some information
        std::cout << "press LEFT MOUSE BUTTON and move the mouse to rotate the outer box" << std::endl;
        std::cout << "press RIGHT MOUSE BUTTON and move the mouse on the X-axis to change the glow intensity" << std::endl;
    }

    void CreateBuffers()
    {
        // Specify vertex format for scene
        vertexFormatScene.AppendAttribute({ "position", LLGL::VectorType::Float3 });
        vertexFormatScene.AppendAttribute({ "normal", LLGL::VectorType::Float3 });

        // Create scene buffers
        auto sceneVertices = LoadObjModel("../Media/Models/WiredBox.obj");
        numSceneVertices = static_cast<unsigned int>(sceneVertices.size());

        vertexBufferScene = CreateVertexBuffer(sceneVertices, vertexFormatScene);
        constantBufferScene = CreateConstantBuffer(sceneSettings);

        // Create empty vertex buffer for post-processors,
        // because to draw meshes a vertex buffer is always required, even if it's empty
        LLGL::BufferDescriptor vertexBufferDesc;
        {
            vertexBufferDesc.type   = LLGL::BufferType::Vertex;
            vertexBufferDesc.size   = 1;
        }
        vertexBufferNull = renderer->CreateBuffer(vertexBufferDesc);

        // Create post-processing buffers
        constantBufferBlur = CreateConstantBuffer(blurSettings);
    }

    void LoadShaders()
    {
        if (renderer->GetRenderingCaps().shadingLanguage >= LLGL::ShadingLanguage::HLSL_2_0)
        {
            // Load scene shader program
            shaderProgramScene = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VScene", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PScene", "ps_5_0" }
                },
                vertexFormatScene
            );

            // Load blur shader program
            shaderProgramBlur = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VPP", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PBlur", "ps_5_0" }
                },
                {} // empty vertex format
            );

            // Load final shader program
            shaderProgramFinal = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VPP", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PFinal", "ps_5_0" }
                },
                {} // empty vertex format
            );
        }
        else
        {
            //todo...
        }
    }

    void CreatePipelines()
    {
        // Create graphics pipeline for scene rendering
        LLGL::GraphicsPipelineDescriptor pipelineDescScene;
        {
            pipelineDescScene.shaderProgram             = shaderProgramScene;

            pipelineDescScene.depth.testEnabled         = true;
            pipelineDescScene.depth.writeEnabled        = true;

            pipelineDescScene.rasterizer.cullMode       = LLGL::CullMode::Back;
            pipelineDescScene.rasterizer.multiSampling  = LLGL::MultiSamplingDescriptor(8);
        }
        pipelineScene = renderer->CreateGraphicsPipeline(pipelineDescScene);

        // Create graphics pipeline for blur post-processor
        LLGL::GraphicsPipelineDescriptor pipelineDescPP;
        {
            pipelineDescPP.shaderProgram = shaderProgramBlur;
        }
        pipelineBlur = renderer->CreateGraphicsPipeline(pipelineDescPP);

        // Create graphics pipeline for final post-processor
        LLGL::GraphicsPipelineDescriptor pipelineDescFinal;
        {
            pipelineDescFinal.shaderProgram = shaderProgramFinal;
        }
        pipelineFinal = renderer->CreateGraphicsPipeline(pipelineDescFinal);
    }

    void CreateSamplers()
    {
        // Create sampler states for all textures
        LLGL::SamplerDescriptor samplerDesc;
        {
            samplerDesc.mipMapping = false;
        }
        colorMapSampler = renderer->CreateSampler(samplerDesc);
        glossMapSampler = renderer->CreateSampler(samplerDesc);
    }

    void CreateTextures()
    {
        // Create empty color and gloss map
        auto resolution = context->GetVideoMode().resolution.Cast<unsigned int>();
        colorMap        = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
        glossMap        = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));

        // Create empty blur pass maps (in quarter resolution)
        resolution /= 4;
        glossMapBlurX   = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
        glossMapBlurY   = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
    }

    void CreateRenderTargets()
    {
        auto resolution = context->GetVideoMode().resolution.Cast<unsigned int>();

        LLGL::RenderTargetDescriptor renderTargetDesc;
        renderTargetDesc.multiSampling = LLGL::MultiSamplingDescriptor(8);

        // Create render-target for scene rendering
        if (renderTargetScene)
            renderTargetScene->DetachAll();
        else
            renderTargetScene = renderer->CreateRenderTarget(renderTargetDesc);

        renderTargetScene->AttachDepthBuffer(resolution);
        renderTargetScene->AttachTexture(*colorMap, {});
        renderTargetScene->AttachTexture(*glossMap, {});

        // Create render-target for horizontal blur pass (no depth buffer needed)
        if (renderTargetBlurX)
            renderTargetBlurX->DetachAll();
        else
            renderTargetBlurX = renderer->CreateRenderTarget(renderTargetDesc);

        renderTargetBlurX->AttachTexture(*glossMapBlurX, {});

        // Create render-target for vertical blur pass (no depth buffer needed)
        if (renderTargetBlurY)
            renderTargetBlurY->DetachAll();
        else
            renderTargetBlurY = renderer->CreateRenderTarget(renderTargetDesc);

        renderTargetBlurY->AttachTexture(*glossMapBlurY, {});
    }

    void UpdateScreenSize()
    {
        // Release previous textures
        renderer->Release(*colorMap);
        renderer->Release(*glossMap);
        renderer->Release(*glossMapBlurX);
        renderer->Release(*glossMapBlurY);

        // Recreate objects
        CreateTextures();
        CreateRenderTargets();
    }

private:

    void SetSceneSettings(float pitch, float yaw, bool innerModel)
    {
        // Transform scene mesh
        sceneSettings.wMatrix.LoadIdentity();
        Gs::Translate(sceneSettings.wMatrix, { 0, 0, 5 });

        if (innerModel)
        {
            // Rotate model around the (1, 1, 1) axis
            static float rotAnim;
            rotAnim += 0.01f;
            Gs::RotateFree(sceneSettings.wMatrix, Gs::Vector3f(1).Normalized(), rotAnim);
            Gs::Scale(sceneSettings.wMatrix, Gs::Vector3f(0.5f));

            // Set colors
            sceneSettings.diffuse       = glowColor;
            sceneSettings.glossiness    = glowColor;
        }
        else
        {
            // Rotate model around X and Y axes
            Gs::RotateFree(sceneSettings.wMatrix, { 1, 0, 0 }, -pitch);
            Gs::RotateFree(sceneSettings.wMatrix, { 0, 1, 0 }, yaw);

            // Set colors
            sceneSettings.diffuse       = { 0.6f, 0.6f, 0.6f, 1.0f };
            sceneSettings.glossiness    = { 0, 0, 0, 0 };
        }

        sceneSettings.wvpMatrix = projection;
        sceneSettings.wvpMatrix *= sceneSettings.wMatrix;

        // Update constant buffer for scene settings
        UpdateBuffer(constantBufferScene, sceneSettings);
    }

    void SetBlurSettings(const Gs::Vector2f& blurShift)
    {
        // Update constant buffer for blur pass
        blurSettings.blurShift = blurShift;
        UpdateBuffer(constantBufferBlur, blurSettings);
    }

    void OnDrawFrame() override
    {
        static const auto shaderStages = LLGL::ShaderStageFlags::VertexStage | LLGL::ShaderStageFlags::FragmentStage;

        // Update scene animation (simple rotation)
        static float pitch, yaw;

        auto mouseMotion = input->GetMouseMotion().Cast<float>();

        if (input->KeyPressed(LLGL::Key::LButton))
        {
            auto rot = mouseMotion*0.005f;
            pitch   += rot.y;
            yaw     += rot.x;
        }

        // Update effect intensity animation
        if (input->KeyPressed(LLGL::Key::RButton))
        {
            float delta = mouseMotion.x*0.01f;
            sceneSettings.intensity = std::max(0.0f, std::min(sceneSettings.intensity + delta, 3.0f));
            std::cout << "glow intensity: " << static_cast<int>(sceneSettings.intensity*100.0f) << "%    \r";
            std::flush(std::cout);
        }

        // Check if screen size has changed (this could also be done with an event listener)
        static LLGL::Size screenSize { 800, 600 };

        if (screenSize != context->GetVideoMode().resolution)
        {
            screenSize = context->GetVideoMode().resolution;
            UpdateScreenSize();
        }

        // Initialize viewports
        auto resolution = screenSize.Cast<float>();

        const LLGL::Viewport viewportFull(0.0f, 0.0f, resolution.x, resolution.y);
        const LLGL::Viewport viewportQuarter(0.0f, 0.0f, resolution.x / 4.0f, resolution.y / 4.0f);

        // Set common buffers and sampler states
        commands->SetConstantBuffer(*constantBufferScene, 0, shaderStages);
        commands->SetConstantBuffer(*constantBufferBlur, 1, LLGL::ShaderStageFlags::FragmentStage);

        commands->SetSampler(*colorMapSampler, 0, LLGL::ShaderStageFlags::FragmentStage);
        commands->SetSampler(*glossMapSampler, 1, LLGL::ShaderStageFlags::FragmentStage);

        // Set graphics pipeline, vertex buffer, and render target for scene rendering
        commands->SetGraphicsPipeline(*pipelineScene);
        commands->SetVertexBuffer(*vertexBufferScene);
        commands->SetRenderTarget(*renderTargetScene);
        {
            // Clear color and depth buffers of active framebuffer (i.e. the render target)
            commands->SetClearColor({ 0, 0, 0, 0 });
            commands->Clear(LLGL::ClearFlags::ColorDepth);

            // Draw outer scene model
            SetSceneSettings(pitch, yaw, false);
            commands->Draw(numSceneVertices, 0);

            // Draw inner scene model
            SetSceneSettings(pitch, yaw, true);
            commands->Draw(numSceneVertices, 0);
        }

        // Draw blur passes in quarter resolution
        commands->SetViewport(viewportQuarter);
        {
            // Set graphics pipeline and vertex buffer for post-processors
            commands->SetGraphicsPipeline(*pipelineBlur);
            commands->SetVertexBuffer(*vertexBufferNull);

            // Draw horizontal blur pass
            commands->SetRenderTarget(*renderTargetBlurX);
            {
                // Set gloss map from scene rendering
                commands->SetTexture(*glossMap, 1, LLGL::ShaderStageFlags::FragmentStage);

                // Draw fullscreen triangle (triangle is spanned in the vertex shader)
                SetBlurSettings({ 4.0f / resolution.x, 0.0f });
                commands->Draw(3, 0);
            }

            // Draw vertical blur pass
            commands->SetRenderTarget(*renderTargetBlurY);
            {
                // Set gloss map from previous blur pass (Blur X)
                commands->SetTexture(*glossMapBlurX, 1, LLGL::ShaderStageFlags::FragmentStage);

                // Draw fullscreen triangle (triangle is spanned in the vertex shader)
                SetBlurSettings({ 0.0f, 4.0f / resolution.y });
                commands->Draw(3, 0);
            }
        }
        commands->SetViewport(viewportFull);

        // Draw final post-processing pass
        commands->SetGraphicsPipeline(*pipelineFinal);
        commands->SetRenderTarget(*context);
        {
            // Set color map and gloss map from previous blur pass (Blur Y)
            commands->SetTexture(*colorMap, 0, LLGL::ShaderStageFlags::FragmentStage);
            commands->SetTexture(*glossMapBlurY, 1, LLGL::ShaderStageFlags::FragmentStage);

            // Draw fullscreen triangle (triangle is spanned in the vertex shader)
            commands->Draw(3, 0);
        }

        // Present result on the screen
        context->Present();
    }

};

LLGL_IMPLEMENT_TUTORIAL(Tutorial11);

<commit_msg>Minor optimization in Tutorial11.<commit_after>/*
 * main.cpp (Tutorial11_PostProcessing)
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "../tutorial.h"

class Tutorial11 : public Tutorial
{

    const LLGL::ColorRGBAf  glowColor           = { 0.9f, 0.7f, 0.3f, 1.0f };

    LLGL::ShaderProgram*    shaderProgramScene  = nullptr;
    LLGL::ShaderProgram*    shaderProgramBlur   = nullptr;
    LLGL::ShaderProgram*    shaderProgramFinal  = nullptr;

    LLGL::GraphicsPipeline* pipelineScene       = nullptr;
    LLGL::GraphicsPipeline* pipelineBlur        = nullptr;
    LLGL::GraphicsPipeline* pipelineFinal       = nullptr;

    LLGL::VertexFormat      vertexFormatScene;

    unsigned int            numSceneVertices    = 0;

    LLGL::Buffer*           vertexBufferScene   = nullptr;
    LLGL::Buffer*           vertexBufferNull    = nullptr;

    LLGL::Buffer*           constantBufferScene = nullptr;
    LLGL::Buffer*           constantBufferBlur  = nullptr;

    LLGL::Sampler*          colorMapSampler     = nullptr;
    LLGL::Sampler*          glossMapSampler     = nullptr;

    LLGL::Texture*          colorMap            = nullptr;
    LLGL::Texture*          glossMap            = nullptr;
    LLGL::Texture*          glossMapBlurX       = nullptr;
    LLGL::Texture*          glossMapBlurY       = nullptr;

    LLGL::RenderTarget*     renderTargetScene   = nullptr;
    LLGL::RenderTarget*     renderTargetBlurX   = nullptr;
    LLGL::RenderTarget*     renderTargetBlurY   = nullptr;

    struct SceneSettings
    {
        Gs::Matrix4f        wvpMatrix;
        Gs::Matrix4f        wMatrix;
        LLGL::ColorRGBAf    diffuse;
        LLGL::ColorRGBAf    glossiness;
        float               intensity           = 1.0f;
        float               _pad0[3];
    }
    sceneSettings;

    struct BlurSettings
    {
        Gs::Vector2f        blurShift;
        float               _pad0[2];
    }
    blurSettings;

public:

    Tutorial11() :
        Tutorial( L"LLGL Tutorial 11: PostProcessing", { 800, 600 }, 0 )
    {
        // Create all graphics objects
        CreateBuffers();
        LoadShaders();
        CreatePipelines();
        CreateSamplers();
        CreateTextures();
        CreateRenderTargets();

        // Show some information
        std::cout << "press LEFT MOUSE BUTTON and move the mouse to rotate the outer box" << std::endl;
        std::cout << "press RIGHT MOUSE BUTTON and move the mouse on the X-axis to change the glow intensity" << std::endl;
    }

    void CreateBuffers()
    {
        // Specify vertex format for scene
        vertexFormatScene.AppendAttribute({ "position", LLGL::VectorType::Float3 });
        vertexFormatScene.AppendAttribute({ "normal", LLGL::VectorType::Float3 });

        // Create scene buffers
        auto sceneVertices = LoadObjModel("../Media/Models/WiredBox.obj");
        numSceneVertices = static_cast<unsigned int>(sceneVertices.size());

        vertexBufferScene = CreateVertexBuffer(sceneVertices, vertexFormatScene);
        constantBufferScene = CreateConstantBuffer(sceneSettings);

        // Create empty vertex buffer for post-processors,
        // because to draw meshes a vertex buffer is always required, even if it's empty
        LLGL::BufferDescriptor vertexBufferDesc;
        {
            vertexBufferDesc.type   = LLGL::BufferType::Vertex;
            vertexBufferDesc.size   = 1;
        }
        vertexBufferNull = renderer->CreateBuffer(vertexBufferDesc);

        // Create post-processing buffers
        constantBufferBlur = CreateConstantBuffer(blurSettings);
    }

    void LoadShaders()
    {
        if (renderer->GetRenderingCaps().shadingLanguage >= LLGL::ShadingLanguage::HLSL_2_0)
        {
            // Load scene shader program
            shaderProgramScene = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VScene", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PScene", "ps_5_0" }
                },
                vertexFormatScene
            );

            // Load blur shader program
            shaderProgramBlur = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VPP", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PBlur", "ps_5_0" }
                },
                {} // empty vertex format
            );

            // Load final shader program
            shaderProgramFinal = LoadShaderProgram(
                {
                    { LLGL::ShaderType::Vertex, "shader.hlsl", "VPP", "vs_5_0" },
                    { LLGL::ShaderType::Fragment, "shader.hlsl", "PFinal", "ps_5_0" }
                },
                {} // empty vertex format
            );
        }
        else
        {
            //todo...
        }
    }

    void CreatePipelines()
    {
        // Create graphics pipeline for scene rendering
        LLGL::GraphicsPipelineDescriptor pipelineDescScene;
        {
            pipelineDescScene.shaderProgram             = shaderProgramScene;

            pipelineDescScene.depth.testEnabled         = true;
            pipelineDescScene.depth.writeEnabled        = true;

            pipelineDescScene.rasterizer.cullMode       = LLGL::CullMode::Back;
            pipelineDescScene.rasterizer.multiSampling  = LLGL::MultiSamplingDescriptor(8);
        }
        pipelineScene = renderer->CreateGraphicsPipeline(pipelineDescScene);

        // Create graphics pipeline for blur post-processor
        LLGL::GraphicsPipelineDescriptor pipelineDescPP;
        {
            pipelineDescPP.shaderProgram = shaderProgramBlur;
        }
        pipelineBlur = renderer->CreateGraphicsPipeline(pipelineDescPP);

        // Create graphics pipeline for final post-processor
        LLGL::GraphicsPipelineDescriptor pipelineDescFinal;
        {
            pipelineDescFinal.shaderProgram = shaderProgramFinal;
        }
        pipelineFinal = renderer->CreateGraphicsPipeline(pipelineDescFinal);
    }

    void CreateSamplers()
    {
        // Create sampler states for all textures
        LLGL::SamplerDescriptor samplerDesc;
        {
            samplerDesc.mipMapping = false;
        }
        colorMapSampler = renderer->CreateSampler(samplerDesc);
        glossMapSampler = renderer->CreateSampler(samplerDesc);
    }

    void CreateTextures()
    {
        // Create empty color and gloss map
        auto resolution = context->GetVideoMode().resolution.Cast<unsigned int>();
        colorMap        = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
        glossMap        = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));

        // Create empty blur pass maps (in quarter resolution)
        resolution /= 4;
        glossMapBlurX   = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
        glossMapBlurY   = renderer->CreateTexture(LLGL::Texture2DDesc(LLGL::TextureFormat::RGBA, resolution.x, resolution.y));
    }

    void CreateRenderTargets()
    {
        auto resolution = context->GetVideoMode().resolution.Cast<unsigned int>();

        // Create render-target for scene rendering
        if (renderTargetScene)
            renderTargetScene->DetachAll();
        else
        {
            LLGL::RenderTargetDescriptor renderTargetDesc;
            {
                renderTargetDesc.multiSampling = LLGL::MultiSamplingDescriptor(8);
            }
            renderTargetScene = renderer->CreateRenderTarget(renderTargetDesc);
        }

        renderTargetScene->AttachDepthBuffer(resolution);
        renderTargetScene->AttachTexture(*colorMap, {});
        renderTargetScene->AttachTexture(*glossMap, {});

        // Create render-target for horizontal blur pass (no depth buffer needed)
        if (renderTargetBlurX)
            renderTargetBlurX->DetachAll();
        else
            renderTargetBlurX = renderer->CreateRenderTarget({});

        renderTargetBlurX->AttachTexture(*glossMapBlurX, {});

        // Create render-target for vertical blur pass (no depth buffer needed)
        if (renderTargetBlurY)
            renderTargetBlurY->DetachAll();
        else
            renderTargetBlurY = renderer->CreateRenderTarget({});

        renderTargetBlurY->AttachTexture(*glossMapBlurY, {});
    }

    void UpdateScreenSize()
    {
        // Release previous textures
        renderer->Release(*colorMap);
        renderer->Release(*glossMap);
        renderer->Release(*glossMapBlurX);
        renderer->Release(*glossMapBlurY);

        // Recreate objects
        CreateTextures();
        CreateRenderTargets();
    }

private:

    void SetSceneSettings(float pitch, float yaw, bool innerModel)
    {
        // Transform scene mesh
        sceneSettings.wMatrix.LoadIdentity();
        Gs::Translate(sceneSettings.wMatrix, { 0, 0, 5 });

        if (innerModel)
        {
            // Rotate model around the (1, 1, 1) axis
            static float rotAnim;
            rotAnim += 0.01f;
            Gs::RotateFree(sceneSettings.wMatrix, Gs::Vector3f(1).Normalized(), rotAnim);
            Gs::Scale(sceneSettings.wMatrix, Gs::Vector3f(0.5f));

            // Set colors
            sceneSettings.diffuse       = glowColor;
            sceneSettings.glossiness    = glowColor;
        }
        else
        {
            // Rotate model around X and Y axes
            Gs::RotateFree(sceneSettings.wMatrix, { 1, 0, 0 }, -pitch);
            Gs::RotateFree(sceneSettings.wMatrix, { 0, 1, 0 }, yaw);

            // Set colors
            sceneSettings.diffuse       = { 0.6f, 0.6f, 0.6f, 1.0f };
            sceneSettings.glossiness    = { 0, 0, 0, 0 };
        }

        sceneSettings.wvpMatrix = projection;
        sceneSettings.wvpMatrix *= sceneSettings.wMatrix;

        // Update constant buffer for scene settings
        UpdateBuffer(constantBufferScene, sceneSettings);
    }

    void SetBlurSettings(const Gs::Vector2f& blurShift)
    {
        // Update constant buffer for blur pass
        blurSettings.blurShift = blurShift;
        UpdateBuffer(constantBufferBlur, blurSettings);
    }

    void OnDrawFrame() override
    {
        static const auto shaderStages = LLGL::ShaderStageFlags::VertexStage | LLGL::ShaderStageFlags::FragmentStage;

        // Update scene animation (simple rotation)
        static float pitch, yaw;

        auto mouseMotion = input->GetMouseMotion().Cast<float>();

        if (input->KeyPressed(LLGL::Key::LButton))
        {
            auto rot = mouseMotion*0.005f;
            pitch   += rot.y;
            yaw     += rot.x;
        }

        // Update effect intensity animation
        if (input->KeyPressed(LLGL::Key::RButton))
        {
            float delta = mouseMotion.x*0.01f;
            sceneSettings.intensity = std::max(0.0f, std::min(sceneSettings.intensity + delta, 3.0f));
            std::cout << "glow intensity: " << static_cast<int>(sceneSettings.intensity*100.0f) << "%    \r";
            std::flush(std::cout);
        }

        // Check if screen size has changed (this could also be done with an event listener)
        static LLGL::Size screenSize { 800, 600 };

        if (screenSize != context->GetVideoMode().resolution)
        {
            screenSize = context->GetVideoMode().resolution;
            UpdateScreenSize();
        }

        // Initialize viewports
        auto resolution = screenSize.Cast<float>();

        const LLGL::Viewport viewportFull(0.0f, 0.0f, resolution.x, resolution.y);
        const LLGL::Viewport viewportQuarter(0.0f, 0.0f, resolution.x / 4.0f, resolution.y / 4.0f);

        // Set common buffers and sampler states
        commands->SetConstantBuffer(*constantBufferScene, 0, shaderStages);
        commands->SetConstantBuffer(*constantBufferBlur, 1, LLGL::ShaderStageFlags::FragmentStage);

        commands->SetSampler(*colorMapSampler, 0, LLGL::ShaderStageFlags::FragmentStage);
        commands->SetSampler(*glossMapSampler, 1, LLGL::ShaderStageFlags::FragmentStage);

        // Set graphics pipeline, vertex buffer, and render target for scene rendering
        commands->SetGraphicsPipeline(*pipelineScene);
        commands->SetVertexBuffer(*vertexBufferScene);
        commands->SetRenderTarget(*renderTargetScene);
        {
            // Clear color and depth buffers of active framebuffer (i.e. the render target)
            commands->SetClearColor({ 0, 0, 0, 0 });
            commands->Clear(LLGL::ClearFlags::ColorDepth);

            // Draw outer scene model
            SetSceneSettings(pitch, yaw, false);
            commands->Draw(numSceneVertices, 0);

            // Draw inner scene model
            SetSceneSettings(pitch, yaw, true);
            commands->Draw(numSceneVertices, 0);
        }

        // Draw blur passes in quarter resolution
        commands->SetViewport(viewportQuarter);
        {
            // Set graphics pipeline and vertex buffer for post-processors
            commands->SetGraphicsPipeline(*pipelineBlur);
            commands->SetVertexBuffer(*vertexBufferNull);

            // Draw horizontal blur pass
            commands->SetRenderTarget(*renderTargetBlurX);
            {
                // Set gloss map from scene rendering
                commands->SetTexture(*glossMap, 1, LLGL::ShaderStageFlags::FragmentStage);

                // Draw fullscreen triangle (triangle is spanned in the vertex shader)
                SetBlurSettings({ 4.0f / resolution.x, 0.0f });
                commands->Draw(3, 0);
            }

            // Draw vertical blur pass
            commands->SetRenderTarget(*renderTargetBlurY);
            {
                // Set gloss map from previous blur pass (Blur X)
                commands->SetTexture(*glossMapBlurX, 1, LLGL::ShaderStageFlags::FragmentStage);

                // Draw fullscreen triangle (triangle is spanned in the vertex shader)
                SetBlurSettings({ 0.0f, 4.0f / resolution.y });
                commands->Draw(3, 0);
            }
        }
        commands->SetViewport(viewportFull);

        // Draw final post-processing pass
        commands->SetGraphicsPipeline(*pipelineFinal);
        commands->SetRenderTarget(*context);
        {
            // Set color map and gloss map from previous blur pass (Blur Y)
            commands->SetTexture(*colorMap, 0, LLGL::ShaderStageFlags::FragmentStage);
            commands->SetTexture(*glossMapBlurY, 1, LLGL::ShaderStageFlags::FragmentStage);

            // Draw fullscreen triangle (triangle is spanned in the vertex shader)
            commands->Draw(3, 0);
        }

        // Present result on the screen
        context->Present();
    }

};

LLGL_IMPLEMENT_TUTORIAL(Tutorial11);

<|endoftext|>


<commit_before>#ifndef UTENSOR_FULLY_CONNECTED_OPS
#define UTENSOR_FULLY_CONNECTED_OPS
#include "uTensor/core/tensor.hpp"
#include "uTensor/core/uTensorBase.hpp"
#include "arm_math.h"
#include "arm_nnfunctions.h"

/***
 * Here we have two types of kernel functions. The basic function implements the function using regular GEMV approach. The opt functions operates with weights in interleaved formats.
 *
 * http://www.keil.com/pack/doc/CMSIS/NN/html/group__FC.html#gae3857bb6375692e81dde8cbd70adec08
 */

template<typename T1, typename T2, typename T3>
void cmsis_fc_selector(const T1* iV, const T2* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const T3* bias,
                       T1* pOut, q15_t* scratch_data);
template<>
void cmsis_fc_selector<q7_t, q7_t, q7_t>(const q7_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q7_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q7(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector<q15_t, q15_t, q15_t>(const q15_t* iV, const q15_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q15_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q15(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector<q15_t, q7_t, q7_t>(const q15_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_mat_q7_vec_q15(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<typename T1, typename T2, typename T3>
void cmsis_fc_selector_opt(const T1* iV, const T2* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const T3* bias,
                       T1* pOut, q15_t* scratch_data);
template<>
void cmsis_fc_selector_opt<q7_t, q7_t, q7_t>(const q7_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q7_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q7_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector_opt<q15_t, q15_t, q15_t>(const q15_t* iV, const q15_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q15_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q15_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector_opt<q15_t, q7_t, q7_t>(const q15_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_mat_q7_vec_q15_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

/**
 * @param [in] iV input vector
 * @param [in] mW matrix weights
 * @param [in] b bias
 * @param [in] scratch scrath computation space
 * @param [out] pOut output
 */
template<typename T1, typename T2, typename T3>
void FullyConnectedLayerCmsis(S_TENSOR iV, S_TENSOR mW, S_TENSOR b,
                         S_TENSOR bShift, S_TENSOR oShift,
                         S_TENSOR pOut, S_TENSOR scratch,
                         T1 byteme1, T2 byteme2, T3 byteme3)
{
    const T1* iV_data  = iV->read<T1>(0, sizeof(T1)); //Read one byte
    const T2* mW_data  = mW->read<T2>(0, sizeof(T2)); //Read one byte
    const T3* bias_data = b->read<T3>(0, sizeof(T3)); //Read one byte
    const uint16_t dim_vec = iV->getShape()[0];
    const uint16_t num_of_rows = mW->getShape()[0];
    const uint16_t bias_shift = *(bShift->read<uint16_t>(0,0));
    const uint16_t out_shift = *(oShift->read<uint16_t>(0,0));
    pOut->resize(b->getShape());
    T1* pOut_data = pOut->write<T1>(0, sizeof(T1));
    q15_t* scratch_data = scratch->write<q15_t>(0, sizeof(q15_t));

    cmsis_fc_selector(iV_data, mW_data, dim_vec, num_of_rows,
            bias_shift, out_shift, bias_data, pOut_data, scratch_data);

    //Error checking
}

/***
 * Here we have two types of kernel functions. The basic function implements the function using regular GEMV approach. The opt functions operates with weights in interleaved formats.
 *
 * http://www.keil.com/pack/doc/CMSIS/NN/html/group__FC.html#gae3857bb6375692e81dde8cbd70adec08
 */

/**
 * @param [in] iV input vector
 * @param [in] mW matrix weights
 * @param [in] b bias
 * @param [in] scratch scrath computation space
 * @param [out] pOut output
 */
template<typename T1, typename T2, typename T3>
void FullyConnectedLayerOptCmsis(S_TENSOR iV, S_TENSOR mW, S_TENSOR b,
                         S_TENSOR bShift, S_TENSOR oShift,
                         S_TENSOR pOut, S_TENSOR scratch,
                         T1 byteme1, T2 byteme2, T3 byteme3)
{
    const T1* iV_data  = iV->read<T1>(0, sizeof(T1)); //Read one byte
    const T2* mW_data  = mW->read<T2>(0, sizeof(T2)); //Read one byte
    const T3* bias_data = b->read<T3>(0, sizeof(T3)); //Read one byte
    const uint16_t dim_vec = iV->getShape()[0];
    const uint16_t num_of_rows = mW->getShape()[0];
    const uint16_t bias_shift = *(bShift->read<uint16_t>(0,0));
    const uint16_t out_shift = *(oShift->read<uint16_t>(0,0));
    pOut->resize(b->getShape());
    T1* pOut_data = pOut->write<T1>(0, sizeof(T1));
    q15_t* scratch_data = scratch->write<q15_t>(0, sizeof(q15_t));

    cmsis_fc_selector_opt(iV_data, mW_data, dim_vec, num_of_rows,
            bias_shift, out_shift, bias_data, pOut_data, scratch_data);

    //Error checking
}

template <class T1, class T2, class T3>
class FullyConnectedLayerCmsisOp : public Operator {
  public:
  FullyConnectedLayerCmsisOp() {
    n_inputs = 6;
    n_outputs = 1;
  }
  virtual void compute() override {
    T1 x;
    T2 y;
    T3 byteme;
    FullyConnectedLayerCmsis(inputs[0], inputs[1], inputs[2], inputs[3],
      inputs[4], outputs[0], inputs[5], x, y, byteme);
  }
};

template <class T1, class T2, class T3>
class FullyConnectedLayerOptCmsisOp : public Operator {
  public:
  FullyConnectedLayerOptCmsisOp() {
    n_inputs = 6;
    n_outputs = 1;
  }
  virtual void compute() override {
    T1 x;
    T2 y;
    T3 byteme;
    FullyConnectedLayerOptCmsis(inputs[0], inputs[1], inputs[2], inputs[3],
      inputs[4], outputs[0], inputs[5], x, y, byteme);
  }
};

#endif /*UTENSOR_FULLY_CONNECTED_OPS*/
<commit_msg>Simplify FC for code gen<commit_after>#ifndef UTENSOR_FULLY_CONNECTED_OPS
#define UTENSOR_FULLY_CONNECTED_OPS
#include "uTensor/core/tensor.hpp"
#include "uTensor/core/uTensorBase.hpp"
#include "arm_math.h"
#include "arm_nnfunctions.h"

/***
 * Here we have two types of kernel functions. The basic function implements the function using regular GEMV approach. The opt functions operates with weights in interleaved formats.
 *
 * http://www.keil.com/pack/doc/CMSIS/NN/html/group__FC.html#gae3857bb6375692e81dde8cbd70adec08
 */

template<typename T1, typename T2, typename T3>
void cmsis_fc_selector(const T1* iV, const T2* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const T3* bias,
                       T1* pOut, q15_t* scratch_data);
template<>
void cmsis_fc_selector<q7_t, q7_t, q7_t>(const q7_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q7_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q7(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector<q15_t, q15_t, q15_t>(const q15_t* iV, const q15_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q15_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q15(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector<q15_t, q7_t, q7_t>(const q15_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_mat_q7_vec_q15(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<typename T1, typename T2, typename T3>
void cmsis_fc_selector_opt(const T1* iV, const T2* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const T3* bias,
                       T1* pOut, q15_t* scratch_data);
template<>
void cmsis_fc_selector_opt<q7_t, q7_t, q7_t>(const q7_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q7_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q7_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector_opt<q15_t, q15_t, q15_t>(const q15_t* iV, const q15_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q15_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_q15_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

template<>
void cmsis_fc_selector_opt<q15_t, q7_t, q7_t>(const q15_t* iV, const q7_t* mW, const uint16_t dim_vec, const uint16_t num_of_rows,
                       const uint16_t bias_shift, const uint16_t out_shift, const q7_t* bias,
                       q15_t* pOut, q15_t* scratch_data)
{
    arm_fully_connected_mat_q7_vec_q15_opt(iV, mW, dim_vec, num_of_rows,
            bias_shift, out_shift, bias, pOut, scratch_data);
}

/**
 * @param [in] iV input vector
 * @param [in] mW matrix weights
 * @param [in] b bias
 * @param [in] scratch scrath computation space
 * @param [out] pOut output
 */
struct FullyConnectedLayerCmsis {
    template<typename T1, typename T2, typename T3>
    void operator() (S_TENSOR iV, S_TENSOR mW, S_TENSOR b,
                             S_TENSOR bShift, S_TENSOR oShift,
                             S_TENSOR pOut, S_TENSOR scratch,
                             T1 byteme1, T2 byteme2, T3 byteme3)
    {
        const T1* iV_data  = iV->read<T1>(0, sizeof(T1)); //Read one byte
        const T2* mW_data  = mW->read<T2>(0, sizeof(T2)); //Read one byte
        const T3* bias_data = b->read<T3>(0, sizeof(T3)); //Read one byte
        const uint16_t dim_vec = iV->getShape()[0];
        const uint16_t num_of_rows = mW->getShape()[0];
        const uint16_t bias_shift = *(bShift->read<uint16_t>(0,0));
        const uint16_t out_shift = *(oShift->read<uint16_t>(0,0));
        pOut->resize(b->getShape());
        T1* pOut_data = pOut->write<T1>(0, sizeof(T1));
        q15_t* scratch_data = scratch->write<q15_t>(0, sizeof(q15_t));

        cmsis_fc_selector(iV_data, mW_data, dim_vec, num_of_rows,
                bias_shift, out_shift, bias_data, pOut_data, scratch_data);

        //Error checking
    }
};

/***
 * Here we have two types of kernel functions. The basic function implements the function using regular GEMV approach. The opt functions operates with weights in interleaved formats.
 *
 * http://www.keil.com/pack/doc/CMSIS/NN/html/group__FC.html#gae3857bb6375692e81dde8cbd70adec08
 */

/**
 * @param [in] iV input vector
 * @param [in] mW matrix weights
 * @param [in] b bias
 * @param [in] scratch scrath computation space
 * @param [out] pOut output
 */
struct FullyConnectedLayerOptCmsis{
    template<typename T1, typename T2, typename T3>
    void operator() (S_TENSOR iV, S_TENSOR mW, S_TENSOR b,
                             S_TENSOR bShift, S_TENSOR oShift,
                             S_TENSOR pOut, S_TENSOR scratch,
                             T1 byteme1, T2 byteme2, T3 byteme3)
    {
        const T1* iV_data  = iV->read<T1>(0, sizeof(T1)); //Read one byte
        const T2* mW_data  = mW->read<T2>(0, sizeof(T2)); //Read one byte
        const T3* bias_data = b->read<T3>(0, sizeof(T3)); //Read one byte
        const uint16_t dim_vec = iV->getShape()[0];
        const uint16_t num_of_rows = mW->getShape()[0];
        const uint16_t bias_shift = *(bShift->read<uint16_t>(0,0));
        const uint16_t out_shift = *(oShift->read<uint16_t>(0,0));
        pOut->resize(b->getShape());
        T1* pOut_data = pOut->write<T1>(0, sizeof(T1));
        q15_t* scratch_data = scratch->write<q15_t>(0, sizeof(q15_t));

        cmsis_fc_selector_opt(iV_data, mW_data, dim_vec, num_of_rows,
                bias_shift, out_shift, bias_data, pOut_data, scratch_data);

        //Error checking
    }
};

//TARGET_OP={FullyConnectedLayerCmsis, FullyConnectedLayerOptCmsis}
template <class T1, class T2, class T3, class TARGET_OP=FullyConnectedLayerCmsis>
class FullyConnectedLayerCmsisOp : public Operator {
  public:
  FullyConnectedLayerCmsisOp() {
    n_inputs = 6;
    n_outputs = 1;
  }
  virtual void compute() override {
    T1 x;
    T2 y;
    T3 byteme;
    TARGET_OP()(inputs[0], inputs[1], inputs[2], inputs[3],
      inputs[4], outputs[0], inputs[5], x, y, byteme);
  }
};

#endif /*UTENSOR_FULLY_CONNECTED_OPS*/
<|endoftext|>


<commit_before>//===-- StripDeadPrototypes.cpp - Removed unused function declarations ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for
// dead declarations and removes them.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include <vector>
using namespace llvm;

STATISTIC(NumDeadPrototypes, "Number of dead prototypes removed");

namespace {

/// @brief Pass to remove unused function declarations.
class StripDeadPrototypesPass : public ModulePass {
public:
  StripDeadPrototypesPass() { }
  virtual bool runOnModule(Module &M);
};
RegisterPass<StripDeadPrototypesPass> X("strip-dead-prototypes",
                                        "Strip Unused Function Prototypes");

bool StripDeadPrototypesPass::runOnModule(Module &M) {
  // Collect all the functions we want to erase
  std::vector<Function*> FuncsToErase;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (I->isDeclaration() &&         // Function must be only a prototype
        I->use_empty()) {             // Function must not be used
      FuncsToErase.push_back(&(*I));
    }

  // Erase the functions
  for (std::vector<Function*>::iterator I = FuncsToErase.begin(),
       E = FuncsToErase.end(); I != E; ++I )
    (*I)->eraseFromParent();

  // Increment the statistic
  NumDeadPrototypes += FuncsToErase.size();

  // Return an indication of whether we changed anything or not.
  return !FuncsToErase.empty();
}

} // end anonymous namespace

ModulePass *llvm::createStripDeadPrototypesPass() {
  return new StripDeadPrototypesPass();
}
<commit_msg>Make the class VISIBILITY_HIDDEN. Reduce lexical size of the anonymous namespace.<commit_after>//===-- StripDeadPrototypes.cpp - Removed unused function declarations ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions in the input module, looking for
// dead declarations and removes them.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include <vector>
using namespace llvm;

STATISTIC(NumDeadPrototypes, "Number of dead prototypes removed");

namespace {

/// @brief Pass to remove unused function declarations.
class VISIBILITY_HIDDEN StripDeadPrototypesPass : public ModulePass {
public:
  StripDeadPrototypesPass() { }
  virtual bool runOnModule(Module &M);
};
RegisterPass<StripDeadPrototypesPass> X("strip-dead-prototypes",
                                        "Strip Unused Function Prototypes");

} // end anonymous namespace

bool StripDeadPrototypesPass::runOnModule(Module &M) {
  // Collect all the functions we want to erase
  std::vector<Function*> FuncsToErase;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (I->isDeclaration() &&         // Function must be only a prototype
        I->use_empty()) {             // Function must not be used
      FuncsToErase.push_back(&(*I));
    }

  // Erase the functions
  for (std::vector<Function*>::iterator I = FuncsToErase.begin(),
       E = FuncsToErase.end(); I != E; ++I )
    (*I)->eraseFromParent();

  // Increment the statistic
  NumDeadPrototypes += FuncsToErase.size();

  // Return an indication of whether we changed anything or not.
  return !FuncsToErase.empty();
}

ModulePass *llvm::createStripDeadPrototypesPass() {
  return new StripDeadPrototypesPass();
}
<|endoftext|>


<commit_before>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "device.hpp"
#include "renderdoc_app.h"
#include <mutex>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif

namespace Vulkan
{
static std::mutex module_lock;
#ifdef _WIN32
static HMODULE renderdoc_module;
#else
static void *renderdoc_module;
#endif

static RENDERDOC_API_1_0_0 *renderdoc_api;

bool Device::init_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (renderdoc_module)
		return true;

#ifdef _WIN32
	renderdoc_module = GetModuleHandleA("renderdoc.dll");
#elif defined(ANDROID)
	renderdoc_module = dlopen("libVkLayer_GLES_RenderDoc.so", RTLD_NOW | RTLD_NOLOAD);
#else
	renderdoc_module = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
#endif

	if (!renderdoc_module)
	{
		LOGE("Failed to load RenderDoc, make sure RenderDoc started the application in capture mode.\n");
		return false;
	}

#ifdef _WIN32
	// Workaround GCC warning about FARPROC mismatch.
	auto *gpa = GetProcAddress(renderdoc_module, "RENDERDOC_GetAPI");
	pRENDERDOC_GetAPI func;
	memcpy(&func, &gpa, sizeof(func));

	if (!func)
	{
		LOGE("Failed to load RENDERDOC_GetAPI function.\n");
		return;
	}
#else
	auto *func = reinterpret_cast<pRENDERDOC_GetAPI>(dlsym(renderdoc_module, "RENDERDOC_GetAPI"));
	if (!func)
	{
		LOGE("Failed to load RENDERDOC_GetAPI function.\n");
		return false;
	}
#endif

	if (!func(eRENDERDOC_API_Version_1_0_0, reinterpret_cast<void **>(&renderdoc_api)))
	{
		LOGE("Failed to obtain RenderDoc 1.0.0 API.\n");
		return false;
	}
	else
	{
		int major, minor, patch;
		renderdoc_api->GetAPIVersion(&major, &minor, &patch);
		LOGI("Initialized RenderDoc API %d.%d.%d.\n", major, minor, patch);
	}

	return true;
}

void Device::begin_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (!renderdoc_api)
	{
		LOGE("RenderDoc API is not loaded, cannot trigger capture.\n");
		return;
	}
	next_frame_context();

	LOGI("Starting RenderDoc frame capture.\n");
	renderdoc_api->StartFrameCapture(nullptr, nullptr);
}

void Device::end_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (!renderdoc_api)
	{
		LOGE("RenderDoc API is not loaded, cannot trigger capture.\n");
		return;
	}
	next_frame_context();
	renderdoc_api->EndFrameCapture(nullptr, nullptr);
	LOGI("Ended RenderDoc frame capture.\n");
}

}
<commit_msg>Fixup Windows build.<commit_after>/* Copyright (c) 2017-2020 Hans-Kristian Arntzen
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "device.hpp"
#include "renderdoc_app.h"
#include <mutex>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif

namespace Vulkan
{
static std::mutex module_lock;
#ifdef _WIN32
static HMODULE renderdoc_module;
#else
static void *renderdoc_module;
#endif

static RENDERDOC_API_1_0_0 *renderdoc_api;

bool Device::init_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (renderdoc_module)
		return true;

#ifdef _WIN32
	renderdoc_module = GetModuleHandleA("renderdoc.dll");
#elif defined(ANDROID)
	renderdoc_module = dlopen("libVkLayer_GLES_RenderDoc.so", RTLD_NOW | RTLD_NOLOAD);
#else
	renderdoc_module = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
#endif

	if (!renderdoc_module)
	{
		LOGE("Failed to load RenderDoc, make sure RenderDoc started the application in capture mode.\n");
		return false;
	}

#ifdef _WIN32
	// Workaround GCC warning about FARPROC mismatch.
	auto *gpa = GetProcAddress(renderdoc_module, "RENDERDOC_GetAPI");
	pRENDERDOC_GetAPI func;
	memcpy(&func, &gpa, sizeof(func));

	if (!func)
	{
		LOGE("Failed to load RENDERDOC_GetAPI function.\n");
		return false;
	}
#else
	auto *func = reinterpret_cast<pRENDERDOC_GetAPI>(dlsym(renderdoc_module, "RENDERDOC_GetAPI"));
	if (!func)
	{
		LOGE("Failed to load RENDERDOC_GetAPI function.\n");
		return false;
	}
#endif

	if (!func(eRENDERDOC_API_Version_1_0_0, reinterpret_cast<void **>(&renderdoc_api)))
	{
		LOGE("Failed to obtain RenderDoc 1.0.0 API.\n");
		return false;
	}
	else
	{
		int major, minor, patch;
		renderdoc_api->GetAPIVersion(&major, &minor, &patch);
		LOGI("Initialized RenderDoc API %d.%d.%d.\n", major, minor, patch);
	}

	return true;
}

void Device::begin_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (!renderdoc_api)
	{
		LOGE("RenderDoc API is not loaded, cannot trigger capture.\n");
		return;
	}
	next_frame_context();

	LOGI("Starting RenderDoc frame capture.\n");
	renderdoc_api->StartFrameCapture(nullptr, nullptr);
}

void Device::end_renderdoc_capture()
{
	std::lock_guard<std::mutex> holder{module_lock};
	if (!renderdoc_api)
	{
		LOGE("RenderDoc API is not loaded, cannot trigger capture.\n");
		return;
	}
	next_frame_context();
	renderdoc_api->EndFrameCapture(nullptr, nullptr);
	LOGI("Ended RenderDoc frame capture.\n");
}

}
<|endoftext|>


<commit_before>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>
#include <thread>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::setfill(' ');
    std::cout << std::dec;
    std::cout << std::endl;
    std::cout << std::endl;
}

int sendData(int sockfd, const char * data, size_t size, bool verbose)
{
    if (verbose)
    {
        std::cout << "Send: ";
        outputBinaryData(data, size);
    }

    int res = send(sockfd, data, size, 0);
    if (res == -1)
        perror("send");

    return res;
}

int sendBadRequest(int sockfd, bool verbose)
{
    static const char badRequest[] = "HTTP/1.0 400 Bad Request\r\n"
                                     "Content-Length:43\r\n"
                                     "\r\n"
                                     "400 Bad Request\r\n";

    return sendData(sockfd, badRequest, sizeof(badRequest) - 1, verbose);
}

int sendNotFound(int sockfd, bool verbose)
{
    static const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                   "Content-Length:41\r\n"
                                   "\r\n"
                                   "404 Not Found\r\n";

    return sendData(sockfd, notFound, sizeof(notFound) - 1, verbose);
}

int sendAnswer(int sockfd, const std::string& data, bool verbose)
{
    std::ostringstream os;
    os << "HTTP/1.0 200 OK\r\n"
       << "Content-Length:" << data.length() << "\r\n"
       << "\r\n"
       << data;

    return sendData(sockfd, os.str().c_str(), os.str().length(), verbose);
}

void clientWorker(aux::UniqueFd&& sockfd,
                  const sockaddr_in peerAddr,
                  const http_server::Options& options)
{
    aux::UniqueFd clientfd(std::move(sockfd));
    if (options.verbose()) {
        std::cout << "Connection with: "
                  << inet_ntoa(peerAddr.sin_addr)
                  << ":" << ntohs(peerAddr.sin_port)
                  << std::endl;
    }
    char buf[1024];
    ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
    switch (received)
    {
        case -1:
            perror("recv");
            break;
        case 0:
            break;
        default:
            if (options.verbose()) {
                std::cout << "Received: ";
                outputBinaryData(buf, received);
            }

            const char* getLine = std::strtok(buf, "\r\n");

            if ((getLine == NULL) || (strncmp(getLine, "GET ", 4) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            const char* protocolStr = std::strrchr(getLine, 'H');
            if ((protocolStr == NULL) || (std::strncmp(protocolStr, "HTTP/", 5) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            std::string filename(getLine + 4, protocolStr - getLine - 5);

            std::filebuf file;
            if (file.open(options.directory() + filename, std::ios_base::in) == nullptr)
            {
                sendNotFound(clientfd, options.verbose());
                return;
            }

            using std::ios_base;
            auto posEnd = file.pubseekoff(0, ios_base::end);
            file.pubseekpos(0);

            //sendAnswer(clientfd, filename, options.verbose());

            if (options.verbose())
                std::cout << "Sending header..." << std::endl;

            std::ostringstream os;
            os << "HTTP/1.0 200 OK\r\n"
               << "Content-Length:" << posEnd << "\r\n"
               << "\r\n";

            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                os << std::string(buf, read);
            } while(read == sizeof(buf));

            os << "\r\n";

            if (sendData(clientfd, os.str().c_str(), os.str().length(), options.verbose()) == -1)
                return;
/*
            if (options.verbose())
                std::cout << "Sending content..." << std::endl;
            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                if (sendData(clientfd, buf, read, options.verbose()) == -1)
                    return;
            } while(read == sizeof(buf));
*/
            break;
    }
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            //clientWorker(std::move(clientfd), peerAddr, options);
            std::thread t(clientWorker, std::move(clientfd), peerAddr, options);
            t.detach();
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    return 0;
}

<commit_msg>filelog<commit_after>#include "server.h"
#include "unique_fd.h"

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <sstream>
#include <fstream>
#include <thread>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

namespace
{

const int fail = -1;
const int inet_aton_fail = 0;

static bool terminated = false;

void termination(int signum)
{
    terminated = true;
}

bool setSignalsHandlers()
{
    struct sigaction sa;
    sa.sa_handler = termination;
    sigaddset(&sa.sa_mask, SIGTERM);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    if (sigaction(SIGINT, &sa, nullptr) == fail) {
        perror("sigaction");
        return false;
    }
    return true;
}

bool init(const http_server::Options& options)
{

    if (options.daemon()) {
        if (daemon(0, 1) == fail) {
            perror("daemon");
            return false;
        }
    }

    if (options.verbose()) {
        std::cout << "The server started as "
                  << (options.daemon()? "daemon": "application")
                  << std::endl;
        std::cout << "pid = " << getpid() << std::endl;
    }

    return setSignalsHandlers();
}

aux::UniqueFd makeListeningSocket()
{
    //aux::UniqueFd sd {socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)};
    aux::UniqueFd sockfd {socket(AF_INET, SOCK_STREAM, 0)};
    if (!sockfd) {
        perror("socket");
        return aux::UniqueFd();
    }

    const int yes = 1;
    if (setsockopt(sockfd, SOL_SOCKET,
                   SO_REUSEADDR, &yes, sizeof(yes)) == fail) {
        perror("setsockopt");
        return aux::UniqueFd();
    }

    return sockfd;
}

bool startListen(const aux::UniqueFd& sockfd, const http_server::Options& options)
{
    struct sockaddr_in addr_in;
    addr_in.sin_family = AF_INET;
    addr_in.sin_port = htons(options.port());
    if (inet_aton(options.ip(), &addr_in.sin_addr) == inet_aton_fail) {
        std::cerr << "inet_aton: " << "The address '"
                  << options.ip() << "' is wrong" << std::endl;
        return false;
    }

    if (options.verbose()) {
        std::cout << "Listening: "
                  << inet_ntoa(addr_in.sin_addr) << ":" << ntohs(addr_in.sin_port)
                  << std::endl;
    }

    if (bind(sockfd,
             reinterpret_cast<struct sockaddr*>(&addr_in),
             sizeof(addr_in)) == fail) {
        perror("bind");
        return false;
    }

    if (listen(sockfd, SOMAXCONN) == fail) {
        perror("listen");
        return false;
    }

    return true;
}

void outputBinaryData(const char * data, size_t size)
{
    std::cout << std::setfill('0');
    for(size_t i = 0; i < size; ++i)
        std::cout << std::setw(2) << std::hex
                  << static_cast<int>(data[i]) << " ";
    std::cout << std::setfill(' ');
    std::cout << std::dec;
    std::cout << std::endl;
    std::cout << std::endl;
}

int sendData(int sockfd, const char * data, size_t size, bool verbose)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    std::ostringstream os;
    os << "/tmp/" << tv.tv_sec << "_" << tv.tv_usec << ".log";
    std::string logName = os.str();
    os.str("");

    std::ofstream log(logName);
    log << std::string(data, size);
    log.close();

    if (verbose)
    {
        std::cout << "Send: ";
        outputBinaryData(data, size);
    }

    int res = send(sockfd, data, size, 0);
    if (res == -1)
        perror("send");

    return res;
}

int sendBadRequest(int sockfd, bool verbose)
{
    static const char badRequest[] = "HTTP/1.0 400 Bad Request\r\n"
                                     "Content-Length:43\r\n"
                                     "\r\n"
                                     "400 Bad Request\r\n";

    return sendData(sockfd, badRequest, sizeof(badRequest) - 1, verbose);
}

int sendNotFound(int sockfd, bool verbose)
{
    static const char notFound[] = "HTTP/1.0 404 Not Found\r\n"
                                   "Content-Length:41\r\n"
                                   "\r\n"
                                   "404 Not Found\r\n";

    return sendData(sockfd, notFound, sizeof(notFound) - 1, verbose);
}

int sendAnswer(int sockfd, const std::string& data, bool verbose)
{
    std::ostringstream os;
    os << "HTTP/1.0 200 OK\r\n"
       << "Content-Length:" << data.length() << "\r\n"
       << "\r\n"
       << data;

    return sendData(sockfd, os.str().c_str(), os.str().length(), verbose);
}

void clientWorker(aux::UniqueFd&& sockfd,
                  const sockaddr_in peerAddr,
                  const http_server::Options& options)
{
    aux::UniqueFd clientfd(std::move(sockfd));
    if (options.verbose()) {
        std::cout << "Connection with: "
                  << inet_ntoa(peerAddr.sin_addr)
                  << ":" << ntohs(peerAddr.sin_port)
                  << std::endl;
    }
    char buf[1024];
    ssize_t received = recv(clientfd, &buf, sizeof(buf), 0);
    switch (received)
    {
        case -1:
            perror("recv");
            break;
        case 0:
            break;
        default:
            if (options.verbose()) {
                std::cout << "Received: ";
                outputBinaryData(buf, received);
            }

            const char* getLine = std::strtok(buf, "\r\n");

            if ((getLine == NULL) || (strncmp(getLine, "GET ", 4) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            const char* protocolStr = std::strrchr(getLine, 'H');
            if ((protocolStr == NULL) || (std::strncmp(protocolStr, "HTTP/", 5) != 0))
            {
                sendBadRequest(clientfd, options.verbose());
                return;
            }

            std::string filename(getLine + 4, protocolStr - getLine - 5);

            std::filebuf file;
            if (file.open(options.directory() + filename, std::ios_base::in) == nullptr)
            {
                sendNotFound(clientfd, options.verbose());
                return;
            }

            using std::ios_base;
            auto posEnd = file.pubseekoff(0, ios_base::end);
            file.pubseekpos(0);

            //sendAnswer(clientfd, filename, options.verbose());

            if (options.verbose())
                std::cout << "Sending header..." << std::endl;

            std::ostringstream os;
            os << "HTTP/1.0 200 OK\r\n"
               << "Content-Length:" << posEnd << "\r\n"
               << "\r\n";

            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                os << std::string(buf, read);
            } while(read == sizeof(buf));

            os << "\r\n";

            if (sendData(clientfd, os.str().c_str(), os.str().length(), options.verbose()) == -1)
                return;
/*
            if (options.verbose())
                std::cout << "Sending content..." << std::endl;
            int read = 0;
            do
            {
                read = file.sgetn(buf, sizeof(buf));
                if (sendData(clientfd, buf, read, options.verbose()) == -1)
                    return;
            } while(read == sizeof(buf));
*/
            break;
    }
}

} /* anonymous namespace */

int http_server::run(const http_server::Options& options)
{
    if (!init(options))
        return EXIT_FAILURE;

    aux::UniqueFd sockfd { makeListeningSocket() };
    if (!sockfd)
        return EXIT_FAILURE;

    if (!startListen(sockfd, options))
        return EXIT_FAILURE;

    while(!terminated) {
        struct sockaddr_in peerAddr;
        socklen_t peerAddrSize = sizeof(peerAddr);
        aux::UniqueFd clientfd {
            accept(sockfd,
                   reinterpret_cast<sockaddr*>(&peerAddr),
                   &peerAddrSize)
            };

        if (clientfd) {
            //clientWorker(std::move(clientfd), peerAddr, options);
            std::thread t(clientWorker, std::move(clientfd), peerAddr, options);
            t.detach();
        } else {
            perror("accept");
        }
    }

    if (options.verbose())
        std::cout << "The server stoped" << std::endl;

    return 0;
}

<|endoftext|>