<commit_before>#include "x_client_chooser.hpp"

#include <algorithm>
#include <sstream>
#include <X11/keysym.h>

x_client_chooser::x_client_chooser(x_connection & c,
                                   x::xrm & xrm,
                                   chooser_t * chooser)
  : _c(c), _xrm(xrm), _chooser(chooser)
{
  _c.attach(0, XCB_KEY_PRESS, this);
  _c.attach(0, XCB_KEY_RELEASE, this);
  _c.attach(0, XCB_BUTTON_PRESS, this);
  _c.attach(0, XCB_MOTION_NOTIFY, this);
  _xrm.attach(this);
  load_config();
  _modifier_map = _c.modifier_mapping();
}

x_client_chooser::~x_client_chooser(void)
{
  _c.detach(XCB_KEY_PRESS, this);
  _c.detach(XCB_KEY_RELEASE, this);
  _c.detach(XCB_BUTTON_PRESS, this);
  _c.detach(XCB_MOTION_NOTIFY, this);
  _xrm.detach(this);
}

bool
x_client_chooser::handle(xcb_generic_event_t * ge)
{
  bool result = false;

  if (XCB_KEY_PRESS == (ge->response_type & ~0x80)) {
    result = true;
    _ignore_release = false;
    xcb_key_press_event_t * e = (xcb_key_press_event_t *)ge;

    if (e->detail == _action_keycode
        && (e->state == _action_modmask
          || e->state == (_action_modmask | XCB_MOD_MASK_SHIFT))) {
      if (_active) {
        if (e->state == _action_modmask) {
          _chooser->next();
        } else {
          _chooser->prev();
        }

      } else {
        _active = true;
        _last_motion = XCB_NONE;
        _c.grab_keyboard();
        _c.grab_pointer(_c.root_window(),
                        XCB_EVENT_MASK_POINTER_MOTION
                        | XCB_EVENT_MASK_BUTTON_PRESS);
        _chooser->show();
        _chooser->next();
      }

    } else if (e->detail == _east_keycode) {
      _chooser->east();

    } else if (e->detail == _west_keycode) {
      _chooser->west();

    } else if (e->detail == _north_keycode) {
      _chooser->north();

    } else if (e->detail == _south_keycode) {
      _chooser->south();

    } else if (e->detail == _quit_keycode) {
      quit();
    }

  } else if (XCB_KEY_RELEASE == (ge->response_type & ~0x80)) {
    result = true;
    if (_ignore_release) return result;

    xcb_key_release_event_t * e = (xcb_key_release_event_t *)ge;
    for (auto & item : _modifier_map) {
      if (item.first == XCB_MOD_MASK_SHIFT) continue;

      for (auto & keycode : item.second) {
        if (e->detail == keycode) {
          quit();
          _chooser->select();
          break;
        }
      }
    }

  } else if (XCB_BUTTON_PRESS == (ge->response_type & ~0x80)) {
    result = true;
    xcb_button_press_event_t * e = (xcb_button_press_event_t *)ge;
    quit();
    _chooser->select(e->child);

  } else if (XCB_MOTION_NOTIFY == (ge->response_type & ~0x80)) {
    result = true;
    xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ge;

    if (e->event == _c.root_window()) {
      _ignore_release = true;
    }

    if (_last_motion != e->child) {
      _last_motion = e->child;
      _ignore_release = true;
      _chooser->highlight(e->child);
    }

  }

  return result;
}

void
x_client_chooser::notify(x::xrm *)
{
  load_config();
}

void
x_client_chooser::quit(void)
{
  _active = false;
  _c.ungrab_pointer();
  _c.ungrab_keyboard();
  _chooser->hide();
}

void
x_client_chooser::load_config(void)
{
  _c.ungrab_key(_action_modmask, _action_keysym);

  _north_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["north"].v.str->c_str()));
  _south_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["south"].v.str->c_str()));
  _east_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["east"].v.str->c_str()));
  _west_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["west"].v.str->c_str()));
  _quit_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["escape"].v.str->c_str()));

  _action_keysym = XStringToKeysym(_xrm["action"].v.str->c_str());
  _action_keycode = _c.keysym_to_keycode(_action_keysym);

  int mask = 0;
  std::stringstream ss(*_xrm["mod"].v.str);
  std::string m;
  while (std::getline(ss, m, '+')) {

    m.erase(std::find_if_not(m.begin(), m.end(), ::isalnum), m.end());

         if ("mod1"    == m) mask |= XCB_MOD_MASK_1;
    else if ("mod2"    == m) mask |= XCB_MOD_MASK_2;
    else if ("mod3"    == m) mask |= XCB_MOD_MASK_3;
    else if ("mod4"    == m) mask |= XCB_MOD_MASK_4;
    else if ("mod5"    == m) mask |= XCB_MOD_MASK_5;
    else if ("shift"   == m) mask |= XCB_MOD_MASK_SHIFT;
    else if ("control" == m) mask |= XCB_MOD_MASK_CONTROL;
  }

  _action_modmask = (xcb_mod_mask_t)mask;

  _c.grab_key(_action_modmask, _action_keysym);
}
<commit_msg>Shift is used reverse switching, hence not available as modifier<commit_after>#include "x_client_chooser.hpp"

#include <algorithm>
#include <sstream>
#include <X11/keysym.h>

x_client_chooser::x_client_chooser(x_connection & c,
                                   x::xrm & xrm,
                                   chooser_t * chooser)
  : _c(c), _xrm(xrm), _chooser(chooser)
{
  _c.attach(0, XCB_KEY_PRESS, this);
  _c.attach(0, XCB_KEY_RELEASE, this);
  _c.attach(0, XCB_BUTTON_PRESS, this);
  _c.attach(0, XCB_MOTION_NOTIFY, this);
  _xrm.attach(this);
  load_config();
  _modifier_map = _c.modifier_mapping();
}

x_client_chooser::~x_client_chooser(void)
{
  _c.detach(XCB_KEY_PRESS, this);
  _c.detach(XCB_KEY_RELEASE, this);
  _c.detach(XCB_BUTTON_PRESS, this);
  _c.detach(XCB_MOTION_NOTIFY, this);
  _xrm.detach(this);
}

bool
x_client_chooser::handle(xcb_generic_event_t * ge)
{
  bool result = false;

  if (XCB_KEY_PRESS == (ge->response_type & ~0x80)) {
    result = true;
    _ignore_release = false;
    xcb_key_press_event_t * e = (xcb_key_press_event_t *)ge;

    if (e->detail == _action_keycode
        && (e->state == _action_modmask
          || e->state == (_action_modmask | XCB_MOD_MASK_SHIFT))) {
      if (_active) {
        if (e->state == _action_modmask) {
          _chooser->next();
        } else {
          _chooser->prev();
        }

      } else {
        _active = true;
        _last_motion = XCB_NONE;
        _c.grab_keyboard();
        _c.grab_pointer(_c.root_window(),
                        XCB_EVENT_MASK_POINTER_MOTION
                        | XCB_EVENT_MASK_BUTTON_PRESS);
        _chooser->show();
        _chooser->next();
      }

    } else if (e->detail == _east_keycode) {
      _chooser->east();

    } else if (e->detail == _west_keycode) {
      _chooser->west();

    } else if (e->detail == _north_keycode) {
      _chooser->north();

    } else if (e->detail == _south_keycode) {
      _chooser->south();

    } else if (e->detail == _quit_keycode) {
      quit();
    }

  } else if (XCB_KEY_RELEASE == (ge->response_type & ~0x80)) {
    result = true;
    if (_ignore_release) return result;

    xcb_key_release_event_t * e = (xcb_key_release_event_t *)ge;
    for (auto & item : _modifier_map) {
      if (item.first == XCB_MOD_MASK_SHIFT) continue;

      for (auto & keycode : item.second) {
        if (e->detail == keycode) {
          quit();
          _chooser->select();
          break;
        }
      }
    }

  } else if (XCB_BUTTON_PRESS == (ge->response_type & ~0x80)) {
    result = true;
    xcb_button_press_event_t * e = (xcb_button_press_event_t *)ge;
    quit();
    _chooser->select(e->child);

  } else if (XCB_MOTION_NOTIFY == (ge->response_type & ~0x80)) {
    result = true;
    xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ge;

    if (e->event == _c.root_window()) {
      _ignore_release = true;
    }

    if (_last_motion != e->child) {
      _last_motion = e->child;
      _ignore_release = true;
      _chooser->highlight(e->child);
    }

  }

  return result;
}

void
x_client_chooser::notify(x::xrm *)
{
  load_config();
}

void
x_client_chooser::quit(void)
{
  _active = false;
  _c.ungrab_pointer();
  _c.ungrab_keyboard();
  _chooser->hide();
}

void
x_client_chooser::load_config(void)
{
  _c.ungrab_key(_action_modmask, _action_keysym);

  _north_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["north"].v.str->c_str()));
  _south_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["south"].v.str->c_str()));
  _east_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["east"].v.str->c_str()));
  _west_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["west"].v.str->c_str()));
  _quit_keycode =
    _c.keysym_to_keycode(XStringToKeysym(_xrm["escape"].v.str->c_str()));

  _action_keysym = XStringToKeysym(_xrm["action"].v.str->c_str());
  _action_keycode = _c.keysym_to_keycode(_action_keysym);

  int mask = 0;
  std::stringstream ss(*_xrm["mod"].v.str);
  std::string m;
  while (std::getline(ss, m, '+')) {

    m.erase(std::find_if_not(m.begin(), m.end(), ::isalnum), m.end());

         if ("mod1"    == m) mask |= XCB_MOD_MASK_1;
    else if ("mod2"    == m) mask |= XCB_MOD_MASK_2;
    else if ("mod3"    == m) mask |= XCB_MOD_MASK_3;
    else if ("mod4"    == m) mask |= XCB_MOD_MASK_4;
    else if ("mod5"    == m) mask |= XCB_MOD_MASK_5;
    else if ("control" == m) mask |= XCB_MOD_MASK_CONTROL;
  }

  _action_modmask = (xcb_mod_mask_t)mask;

  _c.grab_key(_action_modmask, _action_keysym);
}
<|endoftext|>


<commit_before>#include "xchainer/backprop.h"

#include <functional>
#include <memory>
#include <queue>
#include <set>
#include <unordered_map>

#include <gsl/gsl>
#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/op_node.h"

namespace xchainer {
namespace {

class BackwardImpl {
    using Comparer = bool (*)(const std::shared_ptr<OpNode>&, const std::shared_ptr<OpNode>&);
    // TODO(takgi): Using raw pointers to OpNode as the keys is more efficient as far as it is safe
    using CandidateOpNodes = std::priority_queue<std::shared_ptr<OpNode>, std::vector<std::shared_ptr<OpNode>>, Comparer>;
    using PreviousArrayNodeMap = std::unordered_map<std::shared_ptr<OpNode>, std::shared_ptr<ArrayNode>>;
    using SeenOpNodeSet = std::set<std::shared_ptr<OpNode>>;

public:
    BackwardImpl(const Array& output, const GraphId& graph_id, bool enable_double_backprop)
        : output_(output),
          output_array_node_(internal::GetMutableArrayNode(output, graph_id)),
          candidate_op_nodes_(BackwardImpl::Compare),
          double_backprop_enabled_(enable_double_backprop){};

    void run() {
        if (!output_array_node_->grad()) {
            output_array_node_->set_grad(Array::OnesLike(output_));
        }

        PushNextOpNode(output_array_node_);

        while (!candidate_op_nodes_.empty()) {
            std::shared_ptr<OpNode> op_node = candidate_op_nodes_.top();
            candidate_op_nodes_.pop();

            std::vector<Array> gxs = ComputeNextGradients(op_node);
            AccumulateNextGradients(op_node, gxs);

            for (const auto& next_array_node : op_node->next_nodes()) {
                PushNextOpNode(next_array_node);
            }

            if (!double_backprop_enabled_) {
                op_node->Unchain();
            }
        }
    };

private:
    std::vector<Array> ComputeNextGradients(const std::shared_ptr<OpNode>& op_node) {
        const std::shared_ptr<ArrayNode>& previous_array_node = previous_array_node_map_.at(op_node);

        const nonstd::optional<Array>& gy = previous_array_node->grad();
        assert(gy);

        std::vector<Array> gxs;
        for (const auto& backward_function : op_node->backward_functions()) {
            gxs.emplace_back(backward_function(*gy));
        }

        if (previous_array_node != output_array_node_) {
            previous_array_node->ClearGrad();
        }

        return gxs;
    }

    void AccumulateNextGradients(const std::shared_ptr<OpNode>& op_node, const std::vector<Array>& gxs) {
        gsl::span<const std::shared_ptr<ArrayNode>> next_array_nodes = op_node->next_nodes();
        assert(next_array_nodes.size() == gxs.size());
        for (decltype(next_array_nodes)::index_type i = 0; i < next_array_nodes.size(); ++i) {
            const Array& gx = gxs[i];
            const std::shared_ptr<ArrayNode>& next_array_node = next_array_nodes[i];
            const nonstd::optional<Array>& grad = next_array_node->grad();
            if (grad) {
                next_array_node->set_grad(*grad + gx);
            } else {
                next_array_node->set_grad(std::move(gx));
            }
        }
    }

    void PushNextOpNode(const std::shared_ptr<ArrayNode>& array_node) {
        // TODO(beam2d): Reduce the number of ref counting
        std::shared_ptr<OpNode> next_op_node = double_backprop_enabled_ ? array_node->next_node() : array_node->move_next_node();
        if (next_op_node) {
            if (seen_op_node_set_.find(next_op_node) == seen_op_node_set_.end()) {
                candidate_op_nodes_.push(next_op_node);
                previous_array_node_map_.emplace(next_op_node, array_node);
                seen_op_node_set_.insert(next_op_node);
            }
        }
    }

    static bool Compare(const std::shared_ptr<OpNode>& lhs, const std::shared_ptr<OpNode>& rhs) { return lhs->rank() < rhs->rank(); };

    const Array& output_;
    const std::shared_ptr<ArrayNode>& output_array_node_;
    CandidateOpNodes candidate_op_nodes_;
    PreviousArrayNodeMap previous_array_node_map_;
    SeenOpNodeSet seen_op_node_set_;
    bool double_backprop_enabled_;
};

}  // namespace

void Backward(Array& output, const GraphId& graph_id, DoubleBackpropOption double_backprop) {
    // TODO(takagi): Operations that have multiple outputs
    // TODO(takagi): Begin backprop from multiple outputs
    // BackwardImpl{output, graph_id, leave_graph}.run();
    BackwardImpl{output, graph_id, double_backprop == DoubleBackpropOption::kEnable}.run();
}

}  // namespace xchainer
<commit_msg>Align the variable and argument names<commit_after>#include "xchainer/backprop.h"

#include <functional>
#include <memory>
#include <queue>
#include <set>
#include <unordered_map>

#include <gsl/gsl>
#include <nonstd/optional.hpp>

#include "xchainer/array.h"
#include "xchainer/array_node.h"
#include "xchainer/op_node.h"

namespace xchainer {
namespace {

class BackwardImpl {
    using Comparer = bool (*)(const std::shared_ptr<OpNode>&, const std::shared_ptr<OpNode>&);
    // TODO(takgi): Using raw pointers to OpNode as the keys is more efficient as far as it is safe
    using CandidateOpNodes = std::priority_queue<std::shared_ptr<OpNode>, std::vector<std::shared_ptr<OpNode>>, Comparer>;
    using PreviousArrayNodeMap = std::unordered_map<std::shared_ptr<OpNode>, std::shared_ptr<ArrayNode>>;
    using SeenOpNodeSet = std::set<std::shared_ptr<OpNode>>;

public:
    BackwardImpl(const Array& output, const GraphId& graph_id, bool enable_double_backprop)
        : output_(output),
          output_array_node_(internal::GetMutableArrayNode(output, graph_id)),
          candidate_op_nodes_(BackwardImpl::Compare),
          enable_double_backprop_(enable_double_backprop){};

    void run() {
        if (!output_array_node_->grad()) {
            output_array_node_->set_grad(Array::OnesLike(output_));
        }

        PushNextOpNode(output_array_node_);

        while (!candidate_op_nodes_.empty()) {
            std::shared_ptr<OpNode> op_node = candidate_op_nodes_.top();
            candidate_op_nodes_.pop();

            std::vector<Array> gxs = ComputeNextGradients(op_node);
            AccumulateNextGradients(op_node, gxs);

            for (const auto& next_array_node : op_node->next_nodes()) {
                PushNextOpNode(next_array_node);
            }

            if (!enable_double_backprop_) {
                op_node->Unchain();
            }
        }
    };

private:
    std::vector<Array> ComputeNextGradients(const std::shared_ptr<OpNode>& op_node) {
        const std::shared_ptr<ArrayNode>& previous_array_node = previous_array_node_map_.at(op_node);

        const nonstd::optional<Array>& gy = previous_array_node->grad();
        assert(gy);

        std::vector<Array> gxs;
        for (const auto& backward_function : op_node->backward_functions()) {
            gxs.emplace_back(backward_function(*gy));
        }

        if (previous_array_node != output_array_node_) {
            previous_array_node->ClearGrad();
        }

        return gxs;
    }

    void AccumulateNextGradients(const std::shared_ptr<OpNode>& op_node, const std::vector<Array>& gxs) {
        gsl::span<const std::shared_ptr<ArrayNode>> next_array_nodes = op_node->next_nodes();
        assert(next_array_nodes.size() == gxs.size());
        for (decltype(next_array_nodes)::index_type i = 0; i < next_array_nodes.size(); ++i) {
            const Array& gx = gxs[i];
            const std::shared_ptr<ArrayNode>& next_array_node = next_array_nodes[i];
            const nonstd::optional<Array>& grad = next_array_node->grad();
            if (grad) {
                next_array_node->set_grad(*grad + gx);
            } else {
                next_array_node->set_grad(std::move(gx));
            }
        }
    }

    void PushNextOpNode(const std::shared_ptr<ArrayNode>& array_node) {
        // TODO(beam2d): Reduce the number of ref counting
        std::shared_ptr<OpNode> next_op_node = enable_double_backprop_ ? array_node->next_node() : array_node->move_next_node();
        if (next_op_node) {
            if (seen_op_node_set_.find(next_op_node) == seen_op_node_set_.end()) {
                candidate_op_nodes_.push(next_op_node);
                previous_array_node_map_.emplace(next_op_node, array_node);
                seen_op_node_set_.insert(next_op_node);
            }
        }
    }

    static bool Compare(const std::shared_ptr<OpNode>& lhs, const std::shared_ptr<OpNode>& rhs) { return lhs->rank() < rhs->rank(); };

    const Array& output_;
    const std::shared_ptr<ArrayNode>& output_array_node_;
    CandidateOpNodes candidate_op_nodes_;
    PreviousArrayNodeMap previous_array_node_map_;
    SeenOpNodeSet seen_op_node_set_;
    bool enable_double_backprop_;
};

}  // namespace

void Backward(Array& output, const GraphId& graph_id, DoubleBackpropOption double_backprop) {
    // TODO(takagi): Operations that have multiple outputs
    // TODO(takagi): Begin backprop from multiple outputs
    // BackwardImpl{output, graph_id, leave_graph}.run();
    BackwardImpl{output, graph_id, double_backprop == DoubleBackpropOption::kEnable}.run();
}

}  // namespace xchainer
<|endoftext|>


<commit_before>
#ifdef WIN32
#include <windows.h>
#endif
#include <algorithm>
#include "saiga/util/timer.h"
#include "saiga/util/glm.h"
#include "saiga/util/assert.h"

Timer::Timer()
{

}

void Timer::start()
{

#ifdef HAS_HIGH_RESOLUTION_CLOCK
    startTime = std::chrono::high_resolution_clock::now();
#else
    //Since VS2015 the standard high resolution clock is implemented with queryperformanceCounters,
    //so this special windows code is not needed anymore.
    LARGE_INTEGER li;
    if (!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";

//    cout << "QueryPerformanceFrequency " << double(li.QuadPart) << endl;
//    PCFreqPerMicrSecond = double(li.QuadPart) / 1000000.0;

    ticksPerSecond = li.QuadPart;

    //assert(ticksPerSecond >= gameTime.base.count());

    freq = (double)ticksPerSecond / gameTime.base.count();

    QueryPerformanceCounter(&li);
    startTime = li.QuadPart;
#endif
}

tick_t Timer::stop()
{
#ifdef HAS_HIGH_RESOLUTION_CLOCK
    auto endTime = std::chrono::high_resolution_clock::now();
    auto elapsed = endTime - startTime;
    tick_t T = std::chrono::duration_cast<tick_t>(elapsed);
    addMeassurment(T);
    return T;
#else
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    double dt = (li.QuadPart - startTime) / freq;
    std::chrono::duration<double,game_ratio_t> dtc(dt);
    auto T = std::chrono::duration_cast<tick_t>(dtc);
    addMeassurment( T );
    return T;
#endif
}

double Timer::getTimeMicrS()
{
   return std::chrono::duration_cast<std::chrono::duration<double,std::micro>> (getCurrentTime()).count();
}

double Timer::getTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (getCurrentTime()).count();
}

void Timer::addMeassurment(tick_t time)
{
    lastTime = time;
}

//============================================================================================

ExponentialTimer::ExponentialTimer(double alpha) : alpha(alpha)
{

}

void ExponentialTimer::addMeassurment(tick_t time)
{
    lastTime = time;
    currentTime = std::chrono::duration_cast<tick_t> (alpha*currentTime + (1-alpha)*time);
}

//============================================================================================

AverageTimer::AverageTimer(int number) :  lastTimes(number,tick_t(0)), number(number)
{

}

void AverageTimer::addMeassurment(tick_t time)
{
    lastTime = time;
    lastTimes[currentTimeId] = time;
    currentTimeId = (currentTimeId+1) % lastTimes.size();

    currentTime = tick_t(0);
    minimum = lastTimes[0];
    maximum = lastTimes[0];
    for(auto &d : lastTimes){
        currentTime += d;
        minimum = std::min(minimum,d);
        maximum = std::max(maximum,d);
    }
    currentTime /= lastTimes.size();
}

double AverageTimer::getMinimumTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (minimum).count();
}

double AverageTimer::getMaximumTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (maximum).count();
}
<commit_msg>windows include<commit_after>
#ifdef WIN32
#include <windows.h>
#endif
#include <algorithm>
#include "saiga/util/timer.h"
#include "saiga/util/glm.h"
#include "saiga/util/assert.h"
#include "saiga/util/gameTime.h"

Timer::Timer()
{

}

void Timer::start()
{

#ifdef HAS_HIGH_RESOLUTION_CLOCK
    startTime = std::chrono::high_resolution_clock::now();
#else
    //Since VS2015 the standard high resolution clock is implemented with queryperformanceCounters,
    //so this special windows code is not needed anymore.
    LARGE_INTEGER li;
    if (!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";

//    cout << "QueryPerformanceFrequency " << double(li.QuadPart) << endl;
//    PCFreqPerMicrSecond = double(li.QuadPart) / 1000000.0;

    ticksPerSecond = li.QuadPart;

    //assert(ticksPerSecond >= gameTime.base.count());

    freq = (double)ticksPerSecond / gameTime.base.count();

    QueryPerformanceCounter(&li);
    startTime = li.QuadPart;
#endif
}

tick_t Timer::stop()
{
#ifdef HAS_HIGH_RESOLUTION_CLOCK
    auto endTime = std::chrono::high_resolution_clock::now();
    auto elapsed = endTime - startTime;
    tick_t T = std::chrono::duration_cast<tick_t>(elapsed);
    addMeassurment(T);
    return T;
#else
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    double dt = (li.QuadPart - startTime) / freq;
    std::chrono::duration<double,game_ratio_t> dtc(dt);
    auto T = std::chrono::duration_cast<tick_t>(dtc);
    addMeassurment( T );
    return T;
#endif
}

double Timer::getTimeMicrS()
{
   return std::chrono::duration_cast<std::chrono::duration<double,std::micro>> (getCurrentTime()).count();
}

double Timer::getTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (getCurrentTime()).count();
}

void Timer::addMeassurment(tick_t time)
{
    lastTime = time;
}

//============================================================================================

ExponentialTimer::ExponentialTimer(double alpha) : alpha(alpha)
{

}

void ExponentialTimer::addMeassurment(tick_t time)
{
    lastTime = time;
    currentTime = std::chrono::duration_cast<tick_t> (alpha*currentTime + (1-alpha)*time);
}

//============================================================================================

AverageTimer::AverageTimer(int number) :  lastTimes(number,tick_t(0)), number(number)
{

}

void AverageTimer::addMeassurment(tick_t time)
{
    lastTime = time;
    lastTimes[currentTimeId] = time;
    currentTimeId = (currentTimeId+1) % lastTimes.size();

    currentTime = tick_t(0);
    minimum = lastTimes[0];
    maximum = lastTimes[0];
    for(auto &d : lastTimes){
        currentTime += d;
        minimum = std::min(minimum,d);
        maximum = std::max(maximum,d);
    }
    currentTime /= lastTimes.size();
}

double AverageTimer::getMinimumTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (minimum).count();
}

double AverageTimer::getMaximumTimeMS()
{
    return std::chrono::duration_cast<std::chrono::duration<double,std::milli>> (maximum).count();
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include "arrobj.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <assert.h>
using namespace std;

arrObj::arrObj(int s): arrSize(s)
{
    arrBubble = new int[arrSize];
    arrQuick = new int[arrSize];
    arrInsertion = new int[arrSize];
}

arrObj::~arrObj()
{
    delete [] arrBubble;
    delete [] arrQuick;
    delete [] arrInsertion;
}

void arrObj::bubbleSort()
{
    int swap;
    do{
        swap = 0;
        for (int n = 1; n < arrSize; n++) {
            if (arrBubble[n-1] > arrBubble[n]) {
                swap = 1;
                int temp = arrBubble[n-1];
                arrBubble[n-1] = arrBubble[n];
                arrBubble[n] = temp;
            }
        }
    }while(swap == 1);
    assert(isSorted(arrBubble));

}

void arrObj::do_quickSort()
{
  quickSort(0, arrSize - 1);
  //printList(arrQuick);
  //assert(isSorted(arrQuick));
}

void arrObj::quickSort(int left, int right) {
  int pivot;
  int left_index = left;
  int right_index = right;
  if ((right - left) > 0) {
    pivot = (left + right) / 2;
    while ((left_index <= pivot) && (right_index >= pivot)) {
      while ((arrQuick[left_index] < arrQuick[pivot]) && (left_index <= pivot)) {
	++left_index;
      }
      while ((arrQuick[right_index] > arrQuick[pivot]) && (right_index >= pivot)) {
	--right_index;
      }
      int tmp = arrQuick[left_index];
      arrQuick[left_index] = arrQuick[right_index];
      arrQuick[right_index] = tmp;
      ++left_index;
      --right_index;
      if (left_index - 1 == pivot) {
	pivot = right_index = right_index + 1;
      } else if (right_index + 1 == pivot) {
	pivot = left_index = left_index - 1;
      }
    }
    quickSort(left, pivot - 1);
    quickSort(pivot + 1, right);
  }
}

void arrObj::getList(int listNum)
{
    stringstream ss;
    ss << arrSize;
    string strSize = ss.str();
    ss.str("");
    ss << listNum;
    string strNum = ss.str();
    ss.str("");

    string filename = "../../lists/size" + strSize + "/list" + strNum;
    ifstream f(filename.c_str(), ifstream::in);
    string line;
    if (f) {
        int i = 0;
        while (getline(f, line) != 0) {
        arrBubble[i] = atoi(line.c_str());
        arrQuick[i] = atoi(line.c_str());
        arrInsertion[i] = atoi(line.c_str());
        mergeList.push_front(atoi(line.c_str()));
        i++;
        }
    f.close();
    }
    else {
        cerr << "Unable to open file\n"; //if the file is not open output
        exit(0);
    }
}

void arrObj::printList(int *array)
{
    cout << arrSize << endl;
    cout << "{";
    for (int n = 0; n < arrSize; n++) {
        cout << array[n] << ", ";
    }
    cout << "}\n";
}

void arrObj::insertionSort()
{
    int i, j, tmp;
    for (i = 1; i < arrSize; i++) {
        j = i;
        while (j > 0 && arrInsertion[j - 1] > arrInsertion[j]) {
            tmp = arrInsertion[j];
            arrInsertion[j] = arrInsertion[j - 1];
            arrInsertion[j - 1] = tmp;
            j--;
        }
    }
    assert(isSorted(arrInsertion));
}

void arrObj::do_mergeSort()
{
  list<int> dummy = mergeSort(mergeList);
  //assert(isMergeSorted(dummy));
}

list<int> arrObj::mergeSort(list<int> a)
{
  int n = a.size();
  if (n <= 1)
    return a;
  int middle = n / 2;
  list<int> right = a;
  list<int> left;
  list<int> result;
  for(int i = 0; i < middle; i++) {
    left.push_back(right.front());
    right.pop_front();
  }
  assert(left.size() + right.size() == a.size());
  left = mergeSort(left);
  right = mergeSort(right);
  result = merge(left, right);
  return result;
}

list<int> arrObj::merge(list<int> a, list<int> b)
{
  list<int> result;
  while ((a.size() > 0) || (b.size() > 0)) {
    if ((a.size() > 0) && (b.size() > 0)) {
      if (a.front() <= b.front()) {
        result.push_back(a.front());
        a.pop_front();
      } else {
        result.push_back(b.front());
        b.pop_front();
      }
    } else if (a.size() > 0) {
      result.push_back(a.front());
      a.pop_front();
    } else if (b.size() > 0) {
      result.push_back(b.front());
      b.pop_front();
    }
  }
  return result;
}

bool arrObj::isMergeSorted(list<int> a)
{
  list<int> testList = a;
    testList.sort();
    return (testList == a);
}

bool arrObj::isSorted(int *a)
{
    int i;
    for(i = 0; i < (arrSize-1); i++)
        if (a[i] > a[i+1])
            return false;
    return true;
}
<commit_msg>taking out assertions..<commit_after>#include <stdlib.h>
#include "arrobj.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <assert.h>
using namespace std;

arrObj::arrObj(int s): arrSize(s)
{
    arrBubble = new int[arrSize];
    arrQuick = new int[arrSize];
    arrInsertion = new int[arrSize];
}

arrObj::~arrObj()
{
    delete [] arrBubble;
    delete [] arrQuick;
    delete [] arrInsertion;
}

void arrObj::bubbleSort()
{
    int swap;
    do{
        swap = 0;
        for (int n = 1; n < arrSize; n++) {
            if (arrBubble[n-1] > arrBubble[n]) {
                swap = 1;
                int temp = arrBubble[n-1];
                arrBubble[n-1] = arrBubble[n];
                arrBubble[n] = temp;
            }
        }
    }while(swap == 1);
    //assert(isSorted(arrBubble));

}

void arrObj::do_quickSort()
{
  quickSort(0, arrSize - 1);
  //printList(arrQuick);
  //assert(isSorted(arrQuick));
}

void arrObj::quickSort(int left, int right) {
  int pivot;
  int left_index = left;
  int right_index = right;
  if ((right - left) > 0) {
    pivot = (left + right) / 2;
    while ((left_index <= pivot) && (right_index >= pivot)) {
      while ((arrQuick[left_index] < arrQuick[pivot]) && (left_index <= pivot)) {
	++left_index;
      }
      while ((arrQuick[right_index] > arrQuick[pivot]) && (right_index >= pivot)) {
	--right_index;
      }
      int tmp = arrQuick[left_index];
      arrQuick[left_index] = arrQuick[right_index];
      arrQuick[right_index] = tmp;
      ++left_index;
      --right_index;
      if (left_index - 1 == pivot) {
	pivot = right_index = right_index + 1;
      } else if (right_index + 1 == pivot) {
	pivot = left_index = left_index - 1;
      }
    }
    quickSort(left, pivot - 1);
    quickSort(pivot + 1, right);
  }
}

void arrObj::getList(int listNum)
{
    stringstream ss;
    ss << arrSize;
    string strSize = ss.str();
    ss.str("");
    ss << listNum;
    string strNum = ss.str();
    ss.str("");

    string filename = "../../lists/size" + strSize + "/list" + strNum;
    ifstream f(filename.c_str(), ifstream::in);
    string line;
    if (f) {
        int i = 0;
        while (getline(f, line) != 0) {
        arrBubble[i] = atoi(line.c_str());
        arrQuick[i] = atoi(line.c_str());
        arrInsertion[i] = atoi(line.c_str());
        mergeList.push_front(atoi(line.c_str()));
        i++;
        }
    f.close();
    }
    else {
        cerr << "Unable to open file\n"; //if the file is not open output
        exit(0);
    }
}

void arrObj::printList(int *array)
{
    cout << arrSize << endl;
    cout << "{";
    for (int n = 0; n < arrSize; n++) {
        cout << array[n] << ", ";
    }
    cout << "}\n";
}

void arrObj::insertionSort()
{
    int i, j, tmp;
    for (i = 1; i < arrSize; i++) {
        j = i;
        while (j > 0 && arrInsertion[j - 1] > arrInsertion[j]) {
            tmp = arrInsertion[j];
            arrInsertion[j] = arrInsertion[j - 1];
            arrInsertion[j - 1] = tmp;
            j--;
        }
    }
    //assert(isSorted(arrInsertion));
}

void arrObj::do_mergeSort()
{
  list<int> dummy = mergeSort(mergeList);
  //assert(isMergeSorted(dummy));
}

list<int> arrObj::mergeSort(list<int> a)
{
  int n = a.size();
  if (n <= 1)
    return a;
  int middle = n / 2;
  list<int> right = a;
  list<int> left;
  list<int> result;
  for(int i = 0; i < middle; i++) {
    left.push_back(right.front());
    right.pop_front();
  }
  //assert(left.size() + right.size() == a.size());
  left = mergeSort(left);
  right = mergeSort(right);
  result = merge(left, right);
  return result;
}

list<int> arrObj::merge(list<int> a, list<int> b)
{
  list<int> result;
  while ((a.size() > 0) || (b.size() > 0)) {
    if ((a.size() > 0) && (b.size() > 0)) {
      if (a.front() <= b.front()) {
        result.push_back(a.front());
        a.pop_front();
      } else {
        result.push_back(b.front());
        b.pop_front();
      }
    } else if (a.size() > 0) {
      result.push_back(a.front());
      a.pop_front();
    } else if (b.size() > 0) {
      result.push_back(b.front());
      b.pop_front();
    }
  }
  return result;
}

bool arrObj::isMergeSorted(list<int> a)
{
  list<int> testList = a;
    testList.sort();
    return (testList == a);
}

bool arrObj::isSorted(int *a)
{
    int i;
    for(i = 0; i < (arrSize-1); i++)
        if (a[i] > a[i+1])
            return false;
    return true;
}
<|endoftext|>


<commit_before>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

// GCC (at least g++ 4.7.2) and Visual Studio 2015 do support
// setting default values of a struct using C++11 syntax.
// Clang 3.7.0 and Visual Studio 2013 do not support
// setting default values of a struct using C++11 syntax.
// Visual Studio 2013 fails to compile, whereas Clang-compiled
// executable with code with setting default values of a struct
// causes Segmentation fault upon execution of the program.
// Compilers that don't support setting default values of a struct
// are handled by setting the default values in a macro.
// http://stackoverflow.com/questions/16782103/initializing-default-values-in-a-struct/16783513#16783513
#ifdef __clang__
#elif defined(__GNUC__)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#elif defined(_WIN32)
#if (_MSC_VER >= 1900)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#endif
#endif

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <string>   // std::string
#include <vector>   // std::vector
#include <stdint.h> // uint32_t etc.

#ifndef WINDOW_WIDTH
#define WINDOW_WIDTH (1600.0f)
#endif

#ifndef WINDOW_HEIGHT
#define WINDOW_HEIGHT (900.0f)
#endif

#ifndef ASPECT_RATIO
#define ASPECT_RATIO (WINDOW_WIDTH / WINDOW_HEIGHT)
#endif

#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef EARTH_RADIUS
#define EARTH_RADIUS 6371000.0f
#endif

#ifndef TEXT_SIZE
#define TEXT_SIZE 40
#endif

#ifndef FONT_SIZE
#define FONT_SIZE 16
#endif

#ifndef MAX_FPS
#define MAX_FPS 60
#endif

extern glm::mat4 ProjectionMatrix;
extern glm::mat4 ViewMatrix;
extern glm::vec3 position;
extern GLfloat gravity;
extern bool is_flight_mode_in_use;
extern bool in_help_mode;
extern GLfloat fallSpeed;
extern double horizontalAngle;
extern double verticalAngle;
extern GLfloat initialFoV;
extern double earth_radius;
extern bool hasMouseEverMoved;
extern bool is_invert_mouse_in_use;
extern bool is_key_I_released;
extern bool is_key_F_released;
extern bool is_key_F1_released;
extern bool is_world_loaded;        // no more than one world object can be loaded. TODO: check that no more than one world is loaded!
extern bool is_world_spherical;

extern GLfloat speed;
extern GLfloat turbo_factor;
extern GLfloat twin_turbo_factor;
extern GLfloat mouseSpeed;

extern glm::vec3 camera_position;

namespace model
{
    class World;
    class Shader;
    class Graph;
    class Material;
    class Font;
    class Species;
    class Glyph;
}

typedef struct ShaderStruct
{
    ShaderStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    model::World* parent_pointer; // pointer to the world (draw list).
    std::string vertex_shader;    // filename of vertex shader.
    std::string fragment_shader;  // filename of fragment shader.
} ShaderStruct;

typedef struct MaterialStruct
{
    MaterialStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    model::Shader* parent_pointer;   // pointer to the shader.
    std::string texture_file_format; // type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"dds"`/`"DDS"`.
    std::string texture_filename;    // filename of the model file.
    std::string image_path;
} MaterialStruct;

typedef struct NodeStruct
{
    NodeStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    GLuint nodeID;
    model::Graph* parent_pointer;
    glm::vec3 coordinate_vector;
    std::vector<uint32_t> neighbor_nodeIDs;
} NodeStruct;

typedef struct ObjectStruct
{
    ObjectStruct()
        : species_parent_pointer(NULL), glyph_parent_pointer(NULL), original_scale_vector(glm::vec3(1.0f, 1.0f, 1.0f)), rotate_angle(NAN), is_character(false)
    {
        // constructor.
    }
    model::Species* species_parent_pointer; // pointer to the parent species.
    model::Glyph* glyph_parent_pointer;     // pointer to the parent glyph.
    glm::vec3 original_scale_vector; // original scale vector.
    GLfloat rotate_angle;            // rotate angle.
    bool is_character;               // The parent of a character object is a Glyph. The parent of a regular object is a Species.
    glm::vec3 coordinate_vector;     // coordinate vector.
    glm::vec3 rotate_vector;         // rotate vector.
    glm::vec3 translate_vector;      // translate vector.
} ObjectStruct;

typedef struct SpeciesStruct
{
    SpeciesStruct()
        : parent_pointer(NULL), is_world(false), world_radius(NAN), triangulation_type("bilinear_interpolation")
    {
        // constructor.
    }
    // used for all files (for all species).
    model::Material* parent_pointer;         // pointer to the material object.
    bool is_world;                           // worlds currently do not rotate nor translate.
    double world_radius;                     // radius of sea level in meters. used only for worlds.
    std::string model_file_format;           // type of the model file. supported file formats so far: `"bmp"`/`"BMP"`, `"obj"`/`"OBJ"`.
                                             // TODO: add support for `"SRTM"`.
    std::string model_filename;              // filename of the model file.
    // for `"bmp"` model files.
    std::string color_channel;               // color channel to use for altitude data.

    glm::vec3 light_position;                // light position.
    std::string coordinate_system;           // used only for worlds (`is_world` == `true`). valid values: `"cartesian"`.
                                             // TODO: add support for `"spherical"`. `"spherical"` is used eg. in SRTM heightmaps.
    std::string triangulation_type;
} SpeciesStruct;

#define DEFAULT_VERTEX_SCALING_FACTOR (0.001f)

typedef struct FontStruct
{
    FontStruct()
        : parent_pointer(NULL), vertex_scaling_factor(DEFAULT_VERTEX_SCALING_FACTOR)
    {
        // constructor.
    }
    // used for all files (for all font).
    model::Material* parent_pointer;        // pointer to the material object.
    GLfloat vertex_scaling_factor;
    std::string font_file_format;           // type of the font file. supported file formats so far: `"svg"`/`"SVG"`.
    std::string font_filename;              // filename of the font file.
} FontStruct;

typedef struct GlyphStruct
{
    GlyphStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    // used for all files (for all glyph).
    model::Font* parent_pointer;             // pointer to the font object.
    glm::vec3 light_position;                // light position.
} GlyphStruct;

typedef struct
{
    GLuint screen_width;
    GLuint screen_height;
    GLuint x;
    GLuint y;
    GLuint text_size;
    GLuint font_size;
    const char* text;
    const char* char_font_texture_file_format;
    const char* horizontal_alignment;
    const char* vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct
{
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
} SphericalWorldStruct;

typedef struct
{
    GLuint* input_vertex_pointer;
    uint32_t image_width;
    uint32_t image_height;
    std::string triangulation_type;
    double sphere_radius;
    SphericalWorldStruct spherical_world_struct;
} TriangulateQuadsStruct;

extern SphericalCoordinatesStruct spherical_position;

#endif
<commit_msg>Muokattu `typedef struct TriangulateQuadsStruct`. Muokattu `typedef struct TriangulateQuadsStruct`: lisätty oletuskonstruktori sekä muuttuja `should_ylikuutio_use_real_texture_coordinates` (oletusarvo `true`).<commit_after>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

// GCC (at least g++ 4.7.2) and Visual Studio 2015 do support
// setting default values of a struct using C++11 syntax.
// Clang 3.7.0 and Visual Studio 2013 do not support
// setting default values of a struct using C++11 syntax.
// Visual Studio 2013 fails to compile, whereas Clang-compiled
// executable with code with setting default values of a struct
// causes Segmentation fault upon execution of the program.
// Compilers that don't support setting default values of a struct
// are handled by setting the default values in a macro.
// http://stackoverflow.com/questions/16782103/initializing-default-values-in-a-struct/16783513#16783513
#ifdef __clang__
#elif defined(__GNUC__)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#elif defined(_WIN32)
#if (_MSC_VER >= 1900)
#define __STRUCT_DEFAULT_VALUES_ARE_ACCEPTED
#endif
#endif

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <string>   // std::string
#include <vector>   // std::vector
#include <stdint.h> // uint32_t etc.

#ifndef WINDOW_WIDTH
#define WINDOW_WIDTH (1600.0f)
#endif

#ifndef WINDOW_HEIGHT
#define WINDOW_HEIGHT (900.0f)
#endif

#ifndef ASPECT_RATIO
#define ASPECT_RATIO (WINDOW_WIDTH / WINDOW_HEIGHT)
#endif

#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef EARTH_RADIUS
#define EARTH_RADIUS 6371000.0f
#endif

#ifndef TEXT_SIZE
#define TEXT_SIZE 40
#endif

#ifndef FONT_SIZE
#define FONT_SIZE 16
#endif

#ifndef MAX_FPS
#define MAX_FPS 60
#endif

extern glm::mat4 ProjectionMatrix;
extern glm::mat4 ViewMatrix;
extern glm::vec3 position;
extern GLfloat gravity;
extern bool is_flight_mode_in_use;
extern bool in_help_mode;
extern GLfloat fallSpeed;
extern double horizontalAngle;
extern double verticalAngle;
extern GLfloat initialFoV;
extern double earth_radius;
extern bool hasMouseEverMoved;
extern bool is_invert_mouse_in_use;
extern bool is_key_I_released;
extern bool is_key_F_released;
extern bool is_key_F1_released;
extern bool is_world_loaded;        // no more than one world object can be loaded. TODO: check that no more than one world is loaded!
extern bool is_world_spherical;

extern GLfloat speed;
extern GLfloat turbo_factor;
extern GLfloat twin_turbo_factor;
extern GLfloat mouseSpeed;

extern glm::vec3 camera_position;

namespace model
{
    class World;
    class Shader;
    class Graph;
    class Material;
    class Font;
    class Species;
    class Glyph;
}

typedef struct ShaderStruct
{
    ShaderStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    model::World* parent_pointer; // pointer to the world (draw list).
    std::string vertex_shader;    // filename of vertex shader.
    std::string fragment_shader;  // filename of fragment shader.
} ShaderStruct;

typedef struct MaterialStruct
{
    MaterialStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    model::Shader* parent_pointer;   // pointer to the shader.
    std::string texture_file_format; // type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"dds"`/`"DDS"`.
    std::string texture_filename;    // filename of the model file.
    std::string image_path;
} MaterialStruct;

typedef struct NodeStruct
{
    NodeStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    GLuint nodeID;
    model::Graph* parent_pointer;
    glm::vec3 coordinate_vector;
    std::vector<uint32_t> neighbor_nodeIDs;
} NodeStruct;

typedef struct ObjectStruct
{
    ObjectStruct()
        : species_parent_pointer(NULL), glyph_parent_pointer(NULL), original_scale_vector(glm::vec3(1.0f, 1.0f, 1.0f)), rotate_angle(NAN), is_character(false)
    {
        // constructor.
    }
    model::Species* species_parent_pointer; // pointer to the parent species.
    model::Glyph* glyph_parent_pointer;     // pointer to the parent glyph.
    glm::vec3 original_scale_vector; // original scale vector.
    GLfloat rotate_angle;            // rotate angle.
    bool is_character;               // The parent of a character object is a Glyph. The parent of a regular object is a Species.
    glm::vec3 coordinate_vector;     // coordinate vector.
    glm::vec3 rotate_vector;         // rotate vector.
    glm::vec3 translate_vector;      // translate vector.
} ObjectStruct;

typedef struct SpeciesStruct
{
    SpeciesStruct()
        : parent_pointer(NULL), is_world(false), world_radius(NAN), triangulation_type("bilinear_interpolation")
    {
        // constructor.
    }
    // used for all files (for all species).
    model::Material* parent_pointer;         // pointer to the material object.
    bool is_world;                           // worlds currently do not rotate nor translate.
    double world_radius;                     // radius of sea level in meters. used only for worlds.
    std::string model_file_format;           // type of the model file. supported file formats so far: `"bmp"`/`"BMP"`, `"obj"`/`"OBJ"`.
                                             // TODO: add support for `"SRTM"`.
    std::string model_filename;              // filename of the model file.
    // for `"bmp"` model files.
    std::string color_channel;               // color channel to use for altitude data.

    glm::vec3 light_position;                // light position.
    std::string coordinate_system;           // used only for worlds (`is_world` == `true`). valid values: `"cartesian"`.
                                             // TODO: add support for `"spherical"`. `"spherical"` is used eg. in SRTM heightmaps.
    std::string triangulation_type;
} SpeciesStruct;

#define DEFAULT_VERTEX_SCALING_FACTOR (0.001f)

typedef struct FontStruct
{
    FontStruct()
        : parent_pointer(NULL), vertex_scaling_factor(DEFAULT_VERTEX_SCALING_FACTOR)
    {
        // constructor.
    }
    // used for all files (for all font).
    model::Material* parent_pointer;        // pointer to the material object.
    GLfloat vertex_scaling_factor;
    std::string font_file_format;           // type of the font file. supported file formats so far: `"svg"`/`"SVG"`.
    std::string font_filename;              // filename of the font file.
} FontStruct;

typedef struct GlyphStruct
{
    GlyphStruct()
        : parent_pointer(NULL)
    {
        // constructor.
    }
    // used for all files (for all glyph).
    model::Font* parent_pointer;             // pointer to the font object.
    glm::vec3 light_position;                // light position.
} GlyphStruct;

typedef struct
{
    GLuint screen_width;
    GLuint screen_height;
    GLuint x;
    GLuint y;
    GLuint text_size;
    GLuint font_size;
    const char* text;
    const char* char_font_texture_file_format;
    const char* horizontal_alignment;
    const char* vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct
{
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
} SphericalWorldStruct;

typedef struct TriangulateQuadsStruct
{
    TriangulateQuadsStruct()
        : should_ylikuutio_use_real_texture_coordinates(true)
    {
        // constructor.
    }
    GLuint* input_vertex_pointer;
    uint32_t image_width;
    uint32_t image_height;
    std::string triangulation_type;
    bool should_ylikuutio_use_real_texture_coordinates;
    double sphere_radius;
    SphericalWorldStruct spherical_world_struct;
} TriangulateQuadsStruct;

extern SphericalCoordinatesStruct spherical_position;

#endif
<|endoftext|>


<commit_before>#include <iostream>

#include "ApplicationIo.h"

#include <thread>

using namespace std;

int main ()
{
  ApplicationIo *AppIo = new ApplicationIo();

  set_malibu_threading_enable(false);

  cout << "Openning" << endl;

  AppIo->Open();

  cout << "StartStreaming" << endl;

  AppIo->StartStreaming();

  std::this_thread::sleep_for(std::chrono::seconds(5));

  cout << "StopStreaming" << endl;

  cout << "Close" << endl;

  AppIo->Close();

}<commit_msg>Removed main2.cpp test<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include "EmailSender.h"
#include "util.h"

__attribute__((noreturn)) void Usage() {
    std::cerr << "usage: " << ::progname << " sender recipient subject message_body [priority [format]]\n";
    std::cerr << "       \"priority\" has to be one of \"very_low\", \"low\", \"medium\", \"high\", or \"very_high\".\n";
    std::cerr << "       \"format\" has to be one of \"plain_text\" or \"html\".\n\n";
    std::exit(EXIT_FAILURE);
}

EmailSender::Priority StringToPriority(const std::string &priority_candidate) {
    if (priority_candidate == "very_low")
        return EmailSender::VERY_LOW;
    if (priority_candidate == "low")
        return EmailSender::LOW;
    if (priority_candidate == "medium")
        return EmailSender::MEDIUM;
    if (priority_candidate == "high")
        return EmailSender::HIGH;
    if (priority_candidate == "very_high")
        return EmailSender::VERY_HIGH;
    Error("\"" + priority_candidate + "\" is an unknown priority!");
}

EmailSender::Format StringToFormat(const std::string &format_candidate) {
    if (format_candidate == "plain_text")
        return EmailSender::PLAIN_TEXT;
    else if (format_candidate == "html")
        return EmailSender::HTML;
    Error("\"" + format_candidate + "\" is an unknown format!");
}

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    if (argc != 5 and argc != 6 and argc != 7)
        Usage();

    EmailSender::Priority priority;
    EmailSender::Format format(EmailSender::PLAIN_TEXT);
    if (argc == 5)
        priority = EmailSender::DO_NOT_SET_PRIORITY;
    else if (argc == 6)
        priority = StringToPriority(argv[5]);
    else { // Assume argc == 7.
        priority = StringToPriority(argv[5]);
        format = StringToFormat(argv[6]);
    }

    if (not EmailSender::SendEmail(argv[1], argv[2], argv[3], argv[4], priority, format))
        Error("failed to send your email!");
}
<commit_msg>Completely changed the command-line argument-processing.<commit_after>#include <iostream>
#include <cstdlib>
#include "EmailSender.h"
#include "StringUtil.h"
#include "util.h"

__attribute__((noreturn)) void Usage() {
    std::cerr << "usage: " << ::progname << " [--sender=sender] [-reply-to=reply_to] --recipient=recipient "
              << "--subject=subject--message-body=message_body [--priority=priority] [--format=format]\n"
              << "       \"priority\" has to be one of \"very_low\", \"low\", \"medium\", \"high\", or\n"
              << "       \"very_high\".  \"format\" has to be one of \"plain_text\" or \"html\"  At least one\n"
              << "       of \"sender\" or \"reply-to\" has to be specified.\n\n";
    std::exit(EXIT_FAILURE);
}

EmailSender::Priority StringToPriority(const std::string &priority_candidate) {
    if (priority_candidate == "very_low")
        return EmailSender::VERY_LOW;
    if (priority_candidate == "low")
        return EmailSender::LOW;
    if (priority_candidate == "medium")
        return EmailSender::MEDIUM;
    if (priority_candidate == "high")
        return EmailSender::HIGH;
    if (priority_candidate == "very_high")
        return EmailSender::VERY_HIGH;
    Error("\"" + priority_candidate + "\" is an unknown priority!");
}

EmailSender::Format StringToFormat(const std::string &format_candidate) {
    if (format_candidate == "plain_text")
        return EmailSender::PLAIN_TEXT;
    else if (format_candidate == "html")
        return EmailSender::HTML;
    Error("\"" + format_candidate + "\" is an unknown format!");
}

bool ExtractArg(const char * const argument, const std::string &arg_name, std::string * const arg_value) {
    if (StringUtil::StartsWith(argument, "--" + arg_name + "=")) {
        *arg_value = argument + arg_name.length() + 3 /* two dashes and one equal sign */;
        if (arg_value->empty())
            Error(arg_name + " is missing!");

        return true;
    }

    return false;
}

void ParseCommandLine(char **argv, std::string * const sender, std::string * const reply_to,
                      std::string * const recipient, std::string * const subject, std::string * const message_body,
                      std::string * const priority, std::string * const format)
{
    while (*argv != nullptr) {
        if (ExtractArg(*argv, "sender", sender) or ExtractArg(*argv, "reply-to", reply_to)
            or ExtractArg(*argv, "recipient", recipient) or ExtractArg(*argv, "subject", subject)
            or ExtractArg(*argv, "message-body", message_body) or ExtractArg(*argv, "priority", priority)
            or ExtractArg(*argv, "format", format))
            ++argv;
        else
            Error("unknown argument: " + std::string(*argv));
    }

    if (sender->empty() and reply_to->empty())
        Error("you must specify --sender and/or --reply-to!");
    if (recipient->empty())
        Error("you must specify a recipient!");
    if (subject->empty())
        Error("you must specify a subject!");
    if (message_body->empty())
        Error("you must specify a message-body!");
}

int main(int /*argc*/, char *argv[]) {
    ::progname = argv[0];

    EmailSender::Priority priority(EmailSender::DO_NOT_SET_PRIORITY);
    EmailSender::Format format(EmailSender::PLAIN_TEXT);

    std::string sender, reply_to, recipient, subject, message_body, priority_as_string, format_as_string;
    ParseCommandLine(++argv, &sender, &reply_to, &recipient, &subject, &message_body, &priority_as_string,
                     &format_as_string);

    if (not priority_as_string.empty())
        priority = StringToPriority(priority_as_string);
    if (not format_as_string.empty())
        format = StringToFormat(format_as_string);

    if (not EmailSender::SendEmail(sender, recipient, subject, message_body, priority, format, reply_to))
        Error("failed to send your email!");
}
<|endoftext|>


<commit_before>/**
 * @file plugin_configuration.cpp
 *
 * @date Feb 11, 2013
 * @author partio
 */

#include "plugin_configuration.h"

using namespace himan;
using namespace std;

plugin_configuration::plugin_configuration()
	: itsName("")
	, itsOptions()
	, itsStatistics(new statistics)
{
}

plugin_configuration::plugin_configuration(shared_ptr<configuration> conf)
	: configuration(*conf)
	, itsName("")
	, itsOptions()
	, itsStatistics(new statistics)
{
}

plugin_configuration::plugin_configuration(const string& theName, const map<string,string>& theOptions)
	: itsName(theName)
	, itsOptions(theOptions)
	, itsStatistics(new statistics)
{
}

void plugin_configuration::AddOption(const string& key, const string& value)
{
	itsOptions[key] = value;
}

void plugin_configuration::Options(const map<string,string>& theOptions)
{
	itsOptions = theOptions;
}

const map<string,string>& plugin_configuration::Options() const
{
	return itsOptions;
}

void plugin_configuration::Name(const string& theName)
{
	itsName = theName;
}

string plugin_configuration::Name() const
{
	return itsName;
}

bool plugin_configuration::Exists(const string & key) const
{
	return !(GetValue(key).empty());
}

string plugin_configuration::GetValue(const string & key) const
{

	map<string,string>::const_iterator iter = itsOptions.find(key);

	if (iter == itsOptions.end())
	{
		return "";
	}

	return iter->second;
}

shared_ptr<info> plugin_configuration::Info() const
{
	return itsInfo;
}

void plugin_configuration::Info(shared_ptr<info> theInfo)
{
	itsInfo = theInfo;
}

shared_ptr<statistics> plugin_configuration::Statistics() const
{
	return itsStatistics;
}

bool plugin_configuration::StatisticsEnabled() const
{
	return !(itsStatisticsLabel.empty());

}

void plugin_configuration::StartStatistics()
{
	itsStatistics->Start();
}

void plugin_configuration::WriteStatistics()
{
	itsStatistics->itsTimer->Stop();

	cout << "*** STATISTICS FOR " << itsStatisticsLabel << " ***" << endl;

	cout << "Use cuda:\t" << (itsUseCuda ? "true" : "false") << endl;
	cout << "Origin time:\t" << itsInfo->OriginDateTime().String() << endl;

	cout << "geom_name\t" << itsGeomName << endl;

	// Hoping we have iterators set

	itsInfo->First();

	cout << "Level type:\t" << HPLevelTypeToString.at(itsInfo->Level().Type()) << endl;
	cout << "Level count:\t" << itsInfo->SizeLevels() << endl;

	// assuming even time step

	cout << "Time step len:\t" << itsInfo->Time().Step() << endl;
	cout << "Time step unit:\t" << HPTimeResolutionToString.at(itsInfo->Time().StepResolution()) << endl;
	cout << "Time count:\t" << itsInfo->SizeTimes() << endl;

	cout << "Outfile type:\t" << HPFileTypeToString.at(itsOutputFileType) << endl;
	cout << "File write:\t" << HPFileWriteOptionToString.at(itsFileWriteOption) << endl;
	cout << "Read from_db:\t" << (itsReadDataFromDatabase ? "true" : "false") << endl;
	cout << "Leading dim:\t" << HPDimensionTypeToString.at(itsLeadingDimension) << endl;

	cout << "Plugin:\t\t" << itsName << endl;

	size_t elapsedTime = itsStatistics->itsTimer->GetTime();

	size_t threadCountDivisor = itsStatistics->itsUsedThreadCount;

	if (itsLeadingDimension == kTimeDimension && itsInfo->SizeTimes() < itsStatistics->itsUsedThreadCount)
	{
		threadCountDivisor = itsInfo->SizeTimes();
	}
	else if (itsLeadingDimension == kLevelDimension && itsInfo->SizeLevels() < itsStatistics->itsUsedThreadCount)
	{
		threadCountDivisor = itsInfo->SizeLevels();
	}

	int fetchingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsFetchingTime)/static_cast<double>(threadCountDivisor)/static_cast<double> (elapsedTime));
	int processingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsProcessingTime)/static_cast<double>(threadCountDivisor)/static_cast<double> (elapsedTime));

	int writingTimePercentage = 0;

	string writingThreads;
	if (itsFileWriteOption == kSingleFile)
	{
		writingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsWritingTime)/static_cast<double> (elapsedTime));
		writingThreads = ", single thread";
	}
	else
	{
		writingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsWritingTime/threadCountDivisor)/static_cast<double> (elapsedTime));
		writingThreads = ", average over used threads";
	}

	cout	<< "Thread count:\t" <<  itsStatistics->itsUsedThreadCount << endl
			<< "Cuda count:\t" << itsStatistics->itsUsedCudaCount << endl
			<< "Elapsed time:\t" <<  elapsedTime << " microseconds" << endl
			<< "Fetching time:\t" << itsStatistics->itsFetchingTime/threadCountDivisor << " microseconds, average over used threads (" << fetchingTimePercentage << "%)" << endl
			<< "Process time:\t" << itsStatistics->itsProcessingTime/threadCountDivisor << " microseconds, average over used threads (" << processingTimePercentage << "%)" << endl
			<< "Writing time:\t" << itsStatistics->itsWritingTime/threadCountDivisor << " microseconds" << writingThreads << " (" << writingTimePercentage << "%)" << endl
			<< "Values:\t\t" << itsStatistics->itsValueCount << endl
			<< "Missing values:\t" << itsStatistics->itsMissingValueCount << " (" << static_cast<int> (100*static_cast<double>(itsStatistics->itsMissingValueCount)/static_cast<double>(itsStatistics->itsValueCount)) << "%)" << endl
			<< "PPS:\t\t" << 1000*1000*static_cast<double>(itsStatistics->itsValueCount)/static_cast<double>(elapsedTime) << endl;

}

ostream& plugin_configuration::Write(ostream& file) const
{

	// configuration::Write();

    file << "<" << ClassName() << " " << Version() << ">" << endl;
    file << "__itsName__ " << itsName << endl;

    for(map<string, string>::const_iterator iter = itsOptions.begin(); iter != itsOptions.end(); ++iter)
    {
    	file << "__" << iter->first << "__ " << iter->second << endl;
    }

    return file;
}
<commit_msg>Safeguard against floating point exception<commit_after>/**
 * @file plugin_configuration.cpp
 *
 * @date Feb 11, 2013
 * @author partio
 */

#include "plugin_configuration.h"

using namespace himan;
using namespace std;

plugin_configuration::plugin_configuration()
	: itsName("")
	, itsOptions()
	, itsStatistics(new statistics)
{
}

plugin_configuration::plugin_configuration(shared_ptr<configuration> conf)
	: configuration(*conf)
	, itsName("")
	, itsOptions()
	, itsStatistics(new statistics)
{
}

plugin_configuration::plugin_configuration(const string& theName, const map<string,string>& theOptions)
	: itsName(theName)
	, itsOptions(theOptions)
	, itsStatistics(new statistics)
{
}

void plugin_configuration::AddOption(const string& key, const string& value)
{
	itsOptions[key] = value;
}

void plugin_configuration::Options(const map<string,string>& theOptions)
{
	itsOptions = theOptions;
}

const map<string,string>& plugin_configuration::Options() const
{
	return itsOptions;
}

void plugin_configuration::Name(const string& theName)
{
	itsName = theName;
}

string plugin_configuration::Name() const
{
	return itsName;
}

bool plugin_configuration::Exists(const string & key) const
{
	return !(GetValue(key).empty());
}

string plugin_configuration::GetValue(const string & key) const
{

	map<string,string>::const_iterator iter = itsOptions.find(key);

	if (iter == itsOptions.end())
	{
		return "";
	}

	return iter->second;
}

shared_ptr<info> plugin_configuration::Info() const
{
	return itsInfo;
}

void plugin_configuration::Info(shared_ptr<info> theInfo)
{
	itsInfo = theInfo;
}

shared_ptr<statistics> plugin_configuration::Statistics() const
{
	return itsStatistics;
}

bool plugin_configuration::StatisticsEnabled() const
{
	return !(itsStatisticsLabel.empty());

}

void plugin_configuration::StartStatistics()
{
	itsStatistics->Start();
}

void plugin_configuration::WriteStatistics()
{
	itsStatistics->itsTimer->Stop();

	cout << "*** STATISTICS FOR " << itsStatisticsLabel << " ***" << endl;

	cout << "Use cuda:\t" << (itsUseCuda ? "true" : "false") << endl;
	cout << "Origin time:\t" << itsInfo->OriginDateTime().String() << endl;

	cout << "geom_name\t" << itsGeomName << endl;

	// Hoping we have iterators set

	itsInfo->First();

	cout << "Level type:\t" << HPLevelTypeToString.at(itsInfo->Level().Type()) << endl;
	cout << "Level count:\t" << itsInfo->SizeLevels() << endl;

	// assuming even time step

	cout << "Time step len:\t" << itsInfo->Time().Step() << endl;
	cout << "Time step unit:\t" << HPTimeResolutionToString.at(itsInfo->Time().StepResolution()) << endl;
	cout << "Time count:\t" << itsInfo->SizeTimes() << endl;

	cout << "Outfile type:\t" << HPFileTypeToString.at(itsOutputFileType) << endl;
	cout << "File write:\t" << HPFileWriteOptionToString.at(itsFileWriteOption) << endl;
	cout << "Read from_db:\t" << (itsReadDataFromDatabase ? "true" : "false") << endl;
	cout << "Leading dim:\t" << HPDimensionTypeToString.at(itsLeadingDimension) << endl;

	cout << "Plugin:\t\t" << itsName << endl;

	size_t elapsedTime = itsStatistics->itsTimer->GetTime();

	size_t threadCountDivisor = itsStatistics->itsUsedThreadCount;

	if (itsLeadingDimension == kTimeDimension && itsInfo->SizeTimes() < itsStatistics->itsUsedThreadCount)
	{
		threadCountDivisor = itsInfo->SizeTimes();
	}
	else if (itsLeadingDimension == kLevelDimension && itsInfo->SizeLevels() < itsStatistics->itsUsedThreadCount)
	{
		threadCountDivisor = itsInfo->SizeLevels();
	}

	if (threadCountDivisor == 0)
	{
		itsLogger->Warning("Unable to print statistics due to invalid value for threadcount (0) -- somebody forgot to configure their plugin?");
		return;
	}

	int fetchingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsFetchingTime)/static_cast<double>(threadCountDivisor)/static_cast<double> (elapsedTime));
	int processingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsProcessingTime)/static_cast<double>(threadCountDivisor)/static_cast<double> (elapsedTime));

	int writingTimePercentage = 0;

	string writingThreads;

	if (itsFileWriteOption == kSingleFile)
	{
		writingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsWritingTime)/static_cast<double> (elapsedTime));
		writingThreads = ", single thread";
	}
	else
	{
		writingTimePercentage = static_cast<int> (100*static_cast<double> (itsStatistics->itsWritingTime/threadCountDivisor)/static_cast<double> (elapsedTime));
		writingThreads = ", average over used threads";
	}

	cout	<< "Thread count:\t" <<  itsStatistics->itsUsedThreadCount << endl
			<< "Cuda count:\t" << itsStatistics->itsUsedCudaCount << endl
			<< "Elapsed time:\t" <<  elapsedTime << " microseconds" << endl
			<< "Fetching time:\t" << itsStatistics->itsFetchingTime/threadCountDivisor << " microseconds, average over used threads (" << fetchingTimePercentage << "%)" << endl
			<< "Process time:\t" << itsStatistics->itsProcessingTime/threadCountDivisor << " microseconds, average over used threads (" << processingTimePercentage << "%)" << endl
			<< "Writing time:\t" << itsStatistics->itsWritingTime/threadCountDivisor << " microseconds" << writingThreads << " (" << writingTimePercentage << "%)" << endl
			<< "Values:\t\t" << itsStatistics->itsValueCount << endl
			<< "Missing values:\t" << itsStatistics->itsMissingValueCount << " (" << static_cast<int> (100*static_cast<double>(itsStatistics->itsMissingValueCount)/static_cast<double>(itsStatistics->itsValueCount)) << "%)" << endl
			<< "PPS:\t\t" << 1000*1000*static_cast<double>(itsStatistics->itsValueCount)/static_cast<double>(elapsedTime) << endl;

}

ostream& plugin_configuration::Write(ostream& file) const
{

	// configuration::Write();

    file << "<" << ClassName() << " " << Version() << ">" << endl;
    file << "__itsName__ " << itsName << endl;

    for(map<string, string>::const_iterator iter = itsOptions.begin(); iter != itsOptions.end(); ++iter)
    {
    	file << "__" << iter->first << "__ " << iter->second << endl;
    }

    return file;
}
<|endoftext|>


<commit_before>/*
 * Molch, an implementation of the axolotl ratchet based on libsodium
 *
 * ISC License
 *
 * Copyright (C) 2015-2016 Max Bruckner (FSMaxB) <max at maxbruckner dot de>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef LIB_KEY_HPP
#define LIB_KEY_HPP

#include <array>
#include <memory>
#include <ostream>
#include <sodium.h>
#include <iterator>
#include <algorithm>

#include "buffer.hpp"
#include "constants.h"
#include "exception.hpp"
#include "endianness.hpp"
#include "gsl.hpp"
#include "protobuf.hpp"
#include "protobuf-arena.hpp"

namespace Molch {

	//type of key, this is used to distinguish key types
	//and for example avoid copying a private key to a public key
	enum class KeyType : uint8_t {
		Key,
		MessageKey,
		ChainKey,
		HeaderKey,
		RootKey,
		BackupKey,
		PublicKey,
		PrivateKey,
		PublicSigningKey,
		PrivateSigningKey
	};

	template <size_t length, KeyType keytype>
	class Key : public std::array<std::byte,length> {
	private:
		Key& copy(const Key& key) {
			this->empty = key.empty;

			std::copy(std::cbegin(key), std::cend(key), std::begin(*this));

			return *this;
		}

		Key& move(Key&& key) {
			this->empty = key.empty;

			if (key.empty) {
				key.zero();
				return *this;
			}

			return this->copy(key);
		}

	public:
		bool empty{true};

		Key() = default;
		Key(const Key& key) {
			this->copy(key);
		}

		Key(Key&& key) {
			this->move(std::move(key));
		}

		Key(const ProtobufCKey& key) {
			this->set({uchar_to_byte(key.key.data), key.key.len});
		}

		Key(const span<std::byte>& key) {
			this->set(key);
		}

		~Key() {
			this->zero();
		}

		Key& operator=(const Key& key) {
			return this->copy(key);
		}
		Key& operator=(Key&& key) {
			return this->move(std::move(key));
		}

		/*
		 * Constant time comparison of two keys.
		 *
		 * returns:
		 *  -1 if this is less than key
		 *   0 if this is equal to key
		 *  +1 if this is greater than key
		 *
		 *  throws an exception if either is empty.
		 */
		int compare(const Key& key) const {
			Expects(!this->empty && !key.empty);

			TRY_WITH_RESULT(result, sodium_compare(*this, key));
			return result.value();
		}

		//comparison operators
		bool operator>(const Key& key) const {
			return (this->compare(key) == 1);
		}
		bool operator<(const Key& key) const {
			return (this->compare(key) == -1);
		}
		bool operator>=(const Key& key) const {
			return !(*this < key);
		}
		bool operator<=(const Key& key) const {
			return !(*this > key);
		}
		bool operator==(const Key& key) const {
			if (this->empty && key.empty) {
				return true;
			} else if (this->empty || key.empty) {
				return false;
			}

			return (this->compare(key) == 0);
		}
		bool operator!=(const Key& key) const {
			return !(*this == key);
		}

		KeyType type() {
			return type;
		}

		template <size_t derived_length,KeyType derived_type>
		void deriveTo(Key<derived_length,derived_type>& derived_key, const uint32_t subkey_counter) const {
			Expects(!this->empty);

			static_assert(derived_length <= crypto_generichash_blake2b_BYTES_MAX, "The derived length is greater than crypto_generichas_blake2b_BYTES_MAX");
			static_assert(derived_length >= crypto_generichash_blake2b_BYTES_MIN, "The derived length is smaller than crypto_generichash_blake2b_BYTES_MAX");
			static_assert(length <= crypto_generichash_blake2b_KEYBYTES_MAX, "The length to derive from is greater than crypto_generichash_blake2b_KEYBYTES_MAX");
			static_assert(length >= crypto_generichash_blake2b_KEYBYTES_MIN, "The length to derive from is smaller than crypto_generichash_blake2b_KEYBYTES_MIN");

			//create a salt that contains the number of the subkey
			Key<crypto_generichash_blake2b_SALTBYTES,KeyType::Key> salt;
			salt.zero(); //fill with zeroes

			//fill the salt with a big endian representation of the subkey counter
			TRY_VOID(to_big_endian(subkey_counter, {salt.data()+ salt.size() - sizeof(uint32_t), sizeof(uint32_t)}));

			const unsigned char personal[]{"molch_cryptolib"};
			static_assert(sizeof(personal) == crypto_generichash_blake2b_PERSONALBYTES, "personal string is not crypto_generichash_blake2b_PERSONALBYTES long");

			//set length of output
			TRY_VOID(crypto_generichash_blake2b_salt_personal(
					derived_key,
					{nullptr, static_cast<size_t>(0)}, //input
					*this,
					salt,
					{uchar_to_byte(personal), sizeof(personal)}));

			derived_key.empty = false;
		}

		void fillRandom() {
			randombytes_buf(*this);
			this->empty = false;
		}

		//TODO get rid of this
		bool isNone() const noexcept {
			if (this->empty) {
				return true;
			}

			return sodium_is_zero(*this);
		}

		//copy from a raw byte array
		void set(const span<const std::byte> data) {
			Expects(data.size() == length);

			std::copy(std::cbegin(data), std::cend(data), this->data());
			this->empty = false;
		}

		//copy to a raw byte array
		void copyTo(span<std::byte> data) const {
			Expects(data.size() == length);

			std::copy(std::cbegin(*this), std::cend(*this), std::begin(data));
		}

		void clearKey() noexcept {
			this->zero();
			this->empty = true;
		}

		void zero() noexcept {
			sodium_memzero(*this);
		}

		ProtobufCKey* exportProtobuf(Arena& arena) const {
			auto key{arena.allocate<ProtobufCKey>(1)};
			molch__protobuf__key__init(key);

			key->key.data = arena.allocate<uint8_t>(length);
			key->key.len = length;
			this->copyTo({
					uchar_to_byte(key->key.data),
					key->key.len
					});

			return key;
		}

		std::ostream& printHex(std::ostream& stream) const {
			static constexpr size_t width{30};

			if (this->empty) {
				return stream << "(empty)";
			}

			const size_t hex_length{this->size() * 2 + sizeof("")};
			auto hex{std::make_unique<char[]>(hex_length)};
			TRY_VOID(sodium_bin2hex({hex.get(), hex_length}, *this));

			for (size_t i{0}; i < hex_length; i++) {
				if ((width != 0) && ((i % width) == 0) && (i != 0)) {
					stream << '\n';
				} else if ((i % 2 == 0) && (i != 0)) {
					stream << ' ';
				}
				stream << hex[i];
			}

			return stream;
		}
	};

	using MessageKey = Key<MESSAGE_KEY_SIZE,KeyType::MessageKey>;

	class ChainKey : public Key<CHAIN_KEY_SIZE,KeyType::ChainKey> {
	public:
		//inherit constructors
		using Key<CHAIN_KEY_SIZE,KeyType::ChainKey>::Key;

		MessageKey deriveMessageKey() const {
			MessageKey message_key;
			this->deriveTo(message_key, 0);

			return message_key;
		}

		ChainKey deriveChainKey() const {
			ChainKey chain_key;
			this->deriveTo(chain_key, 1);

			return chain_key;
		}
	};

	using HeaderKey = Key<HEADER_KEY_SIZE,KeyType::HeaderKey>;
	using RootKey = Key<ROOT_KEY_SIZE,KeyType::RootKey>;
	using BackupKey = Key<BACKUP_KEY_SIZE,KeyType::BackupKey>;
	using PublicKey = Key<PUBLIC_KEY_SIZE,KeyType::PublicKey>;
	using PrivateKey = Key<PRIVATE_KEY_SIZE,KeyType::PrivateKey>;
	using PublicSigningKey = Key<PUBLIC_MASTER_KEY_SIZE,KeyType::PublicSigningKey>;
	using PrivateSigningKey = Key<PRIVATE_MASTER_KEY_SIZE,KeyType::PrivateSigningKey>;
}

#endif /* LIB_KEY_HPP */
<commit_msg>Key: Simplify deriveTo template parameters by adding a static constexpr length to Key<commit_after>/*
 * Molch, an implementation of the axolotl ratchet based on libsodium
 *
 * ISC License
 *
 * Copyright (C) 2015-2016 Max Bruckner (FSMaxB) <max at maxbruckner dot de>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef LIB_KEY_HPP
#define LIB_KEY_HPP

#include <array>
#include <memory>
#include <ostream>
#include <sodium.h>
#include <iterator>
#include <algorithm>

#include "buffer.hpp"
#include "constants.h"
#include "exception.hpp"
#include "endianness.hpp"
#include "gsl.hpp"
#include "protobuf.hpp"
#include "protobuf-arena.hpp"

namespace Molch {

	//type of key, this is used to distinguish key types
	//and for example avoid copying a private key to a public key
	enum class KeyType : uint8_t {
		Key,
		MessageKey,
		ChainKey,
		HeaderKey,
		RootKey,
		BackupKey,
		PublicKey,
		PrivateKey,
		PublicSigningKey,
		PrivateSigningKey
	};

	template <size_t key_length, KeyType keytype>
	class Key : public std::array<std::byte,key_length> {
	private:
		Key& copy(const Key& key) {
			this->empty = key.empty;

			std::copy(std::cbegin(key), std::cend(key), std::begin(*this));

			return *this;
		}

		Key& move(Key&& key) {
			this->empty = key.empty;

			if (key.empty) {
				key.zero();
				return *this;
			}

			return this->copy(key);
		}

	public:
		static constexpr size_t length{key_length};

		bool empty{true};

		Key() = default;
		Key(const Key& key) {
			this->copy(key);
		}

		Key(Key&& key) {
			this->move(std::move(key));
		}

		Key(const ProtobufCKey& key) {
			this->set({uchar_to_byte(key.key.data), key.key.len});
		}

		Key(const span<std::byte>& key) {
			this->set(key);
		}

		~Key() {
			this->zero();
		}

		Key& operator=(const Key& key) {
			return this->copy(key);
		}
		Key& operator=(Key&& key) {
			return this->move(std::move(key));
		}

		/*
		 * Constant time comparison of two keys.
		 *
		 * returns:
		 *  -1 if this is less than key
		 *   0 if this is equal to key
		 *  +1 if this is greater than key
		 *
		 *  throws an exception if either is empty.
		 */
		int compare(const Key& key) const {
			Expects(!this->empty && !key.empty);

			TRY_WITH_RESULT(result, sodium_compare(*this, key));
			return result.value();
		}

		//comparison operators
		bool operator>(const Key& key) const {
			return (this->compare(key) == 1);
		}
		bool operator<(const Key& key) const {
			return (this->compare(key) == -1);
		}
		bool operator>=(const Key& key) const {
			return !(*this < key);
		}
		bool operator<=(const Key& key) const {
			return !(*this > key);
		}
		bool operator==(const Key& key) const {
			if (this->empty && key.empty) {
				return true;
			} else if (this->empty || key.empty) {
				return false;
			}

			return (this->compare(key) == 0);
		}
		bool operator!=(const Key& key) const {
			return !(*this == key);
		}

		KeyType type() {
			return type;
		}

		template <typename DerivedKeyType>
		void deriveTo(DerivedKeyType& derived_key, const uint32_t subkey_counter) const {
			Expects(!this->empty);

			static_assert(derived_key.length <= crypto_generichash_blake2b_BYTES_MAX, "The derived length is greater than crypto_generichas_blake2b_BYTES_MAX");
			static_assert(derived_key.length >= crypto_generichash_blake2b_BYTES_MIN, "The derived length is smaller than crypto_generichash_blake2b_BYTES_MAX");
			static_assert(length <= crypto_generichash_blake2b_KEYBYTES_MAX, "The length to derive from is greater than crypto_generichash_blake2b_KEYBYTES_MAX");
			static_assert(length >= crypto_generichash_blake2b_KEYBYTES_MIN, "The length to derive from is smaller than crypto_generichash_blake2b_KEYBYTES_MIN");

			//create a salt that contains the number of the subkey
			Key<crypto_generichash_blake2b_SALTBYTES,KeyType::Key> salt;
			salt.zero(); //fill with zeroes

			//fill the salt with a big endian representation of the subkey counter
			TRY_VOID(to_big_endian(subkey_counter, {salt.data()+ salt.size() - sizeof(uint32_t), sizeof(uint32_t)}));

			const unsigned char personal[]{"molch_cryptolib"};
			static_assert(sizeof(personal) == crypto_generichash_blake2b_PERSONALBYTES, "personal string is not crypto_generichash_blake2b_PERSONALBYTES long");

			//set length of output
			TRY_VOID(crypto_generichash_blake2b_salt_personal(
					derived_key,
					{nullptr, static_cast<size_t>(0)}, //input
					*this,
					salt,
					{uchar_to_byte(personal), sizeof(personal)}));

			derived_key.empty = false;
		}

		void fillRandom() {
			randombytes_buf(*this);
			this->empty = false;
		}

		//TODO get rid of this
		bool isNone() const noexcept {
			if (this->empty) {
				return true;
			}

			return sodium_is_zero(*this);
		}

		//copy from a raw byte array
		void set(const span<const std::byte> data) {
			Expects(data.size() == length);

			std::copy(std::cbegin(data), std::cend(data), this->data());
			this->empty = false;
		}

		//copy to a raw byte array
		void copyTo(span<std::byte> data) const {
			Expects(data.size() == length);

			std::copy(std::cbegin(*this), std::cend(*this), std::begin(data));
		}

		void clearKey() noexcept {
			this->zero();
			this->empty = true;
		}

		void zero() noexcept {
			sodium_memzero(*this);
		}

		ProtobufCKey* exportProtobuf(Arena& arena) const {
			auto key{arena.allocate<ProtobufCKey>(1)};
			molch__protobuf__key__init(key);

			key->key.data = arena.allocate<uint8_t>(length);
			key->key.len = length;
			this->copyTo({
					uchar_to_byte(key->key.data),
					key->key.len
					});

			return key;
		}

		std::ostream& printHex(std::ostream& stream) const {
			static constexpr size_t width{30};

			if (this->empty) {
				return stream << "(empty)";
			}

			const size_t hex_length{this->size() * 2 + sizeof("")};
			auto hex{std::make_unique<char[]>(hex_length)};
			TRY_VOID(sodium_bin2hex({hex.get(), hex_length}, *this));

			for (size_t i{0}; i < hex_length; i++) {
				if ((width != 0) && ((i % width) == 0) && (i != 0)) {
					stream << '\n';
				} else if ((i % 2 == 0) && (i != 0)) {
					stream << ' ';
				}
				stream << hex[i];
			}

			return stream;
		}
	};

	using MessageKey = Key<MESSAGE_KEY_SIZE,KeyType::MessageKey>;

	class ChainKey : public Key<CHAIN_KEY_SIZE,KeyType::ChainKey> {
	public:
		//inherit constructors
		using Key<CHAIN_KEY_SIZE,KeyType::ChainKey>::Key;

		MessageKey deriveMessageKey() const {
			MessageKey message_key;
			this->deriveTo(message_key, 0);

			return message_key;
		}

		ChainKey deriveChainKey() const {
			ChainKey chain_key;
			this->deriveTo(chain_key, 1);

			return chain_key;
		}
	};

	using HeaderKey = Key<HEADER_KEY_SIZE,KeyType::HeaderKey>;
	using RootKey = Key<ROOT_KEY_SIZE,KeyType::RootKey>;
	using BackupKey = Key<BACKUP_KEY_SIZE,KeyType::BackupKey>;
	using PublicKey = Key<PUBLIC_KEY_SIZE,KeyType::PublicKey>;
	using PrivateKey = Key<PRIVATE_KEY_SIZE,KeyType::PrivateKey>;
	using PublicSigningKey = Key<PUBLIC_MASTER_KEY_SIZE,KeyType::PublicSigningKey>;
	using PrivateSigningKey = Key<PRIVATE_MASTER_KEY_SIZE,KeyType::PrivateSigningKey>;
}

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