<commit_before>#include "core/base64.h"

#include "core/assert.h"
#include "core/cint.h"

#include <sstream>
#include <string_view>
#include <array>

// source: https://en.wikipedia.org/wiki/Base64

namespace euphoria::core::base64
{
    namespace
    {
        constexpr std::string_view CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    }

    std::string
    Encode(std::shared_ptr<MemoryChunk> memory)
    {
        MemoryChunk& in = *memory;
        std::ostringstream out;

        for(int i = 0; i < in.GetSize(); i += 3)
        {
            int b = (in[i] & 0xFC) >> 2;
            out << CODES[b];
            b = (in[i] & 0x03) << 4;
            if(i + 1 < in.GetSize())
            {
                b |= (in[i + 1] & 0xF0) >> 4;
                out << CODES[b];
                b = (in[i + 1] & 0x0F) << 2;
                if(i + 2 < in.GetSize())
                {
                    b |= (in[i + 2] & 0xC0) >> 6;
                    out << CODES[b];
                    b = in[i + 2] & 0x3F;
                    out << CODES[b];
                }
                else
                {
                    out << CODES[b];
                    out << '=';
                }
            }
            else
            {
                out << CODES[b];
                out << "==";
            }
        }

        return out.str();
    }

    std::shared_ptr<MemoryChunk>
    Decode(const std::string& input)
    {
        if(input.length() % 4 == 0)
        {
            ASSERT(!input.empty());
            auto asize = (input.length() * 3) / 4;
            auto found = input.find('=') != std::string::npos;
            auto bsize = found ? (input.length() - input.find('=')) : 0;
            int size = Csizet_to_int(asize) - Csizet_to_int(bsize);

            ASSERT(size > 0);

            auto ret = MemoryChunk::Alloc(size);
            MemoryChunk& decoded = *ret;
            int j = 0;
            for(int i = 0; i < Csizet_to_int(input.size()); i += 4)
            {
                // This could be made faster (but more complicated) by precomputing these index locations.
                const auto b = std::array<unsigned long, 4>
                {
                    CODES.find(input[i]),
                    CODES.find(input[i + 1]),
                    CODES.find(input[i + 2]),
                    CODES.find(input[i + 3])
                };
                decoded[j++] = static_cast<char>((b[0] << 2) | (b[1] >> 4));
                if(b[2] < 64)
                {
                    decoded[j++] = static_cast<char>((b[1] << 4) | (b[2] >> 2));
                    if(b[3] < 64)
                    {
                        decoded[j++] = static_cast<char>((b[2] << 6) | b[3]);
                    }
                }
            }
            return ret;
        }
        else
        {
            return MemoryChunk::Null();
        }
    }
}
<commit_msg>fixed windows compilation issue<commit_after>#include "core/base64.h"

#include "core/assert.h"
#include "core/cint.h"

#include <sstream>
#include <string_view>
#include <array>

// source: https://en.wikipedia.org/wiki/Base64

namespace euphoria::core::base64
{
    namespace
    {
        constexpr std::string_view CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    }

    std::string
    Encode(std::shared_ptr<MemoryChunk> memory)
    {
        MemoryChunk& in = *memory;
        std::ostringstream out;

        for(int i = 0; i < in.GetSize(); i += 3)
        {
            int b = (in[i] & 0xFC) >> 2;
            out << CODES[b];
            b = (in[i] & 0x03) << 4;
            if(i + 1 < in.GetSize())
            {
                b |= (in[i + 1] & 0xF0) >> 4;
                out << CODES[b];
                b = (in[i + 1] & 0x0F) << 2;
                if(i + 2 < in.GetSize())
                {
                    b |= (in[i + 2] & 0xC0) >> 6;
                    out << CODES[b];
                    b = in[i + 2] & 0x3F;
                    out << CODES[b];
                }
                else
                {
                    out << CODES[b];
                    out << '=';
                }
            }
            else
            {
                out << CODES[b];
                out << "==";
            }
        }

        return out.str();
    }

    std::shared_ptr<MemoryChunk>
    Decode(const std::string& input)
    {
        if(input.length() % 4 == 0)
        {
            ASSERT(!input.empty());
            auto asize = (input.length() * 3) / 4;
            auto found = input.find('=') != std::string::npos;
            auto bsize = found ? (input.length() - input.find('=')) : 0;
            int size = Csizet_to_int(asize) - Csizet_to_int(bsize);

            ASSERT(size > 0);

            auto ret = MemoryChunk::Alloc(size);
            MemoryChunk& decoded = *ret;
            int j = 0;
            for(int i = 0; i < Csizet_to_int(input.size()); i += 4)
            {
                // This could be made faster (but more complicated) by precomputing these index locations.
                const auto b = std::array<size_t, 4>
                {
                    CODES.find(input[Cint_to_sizet(i)]),
                    CODES.find(input[Cint_to_sizet(i + 1)]),
                    CODES.find(input[Cint_to_sizet(i + 2)]),
                    CODES.find(input[Cint_to_sizet(i + 3)])
                };
                decoded[j++] = static_cast<char>((b[0] << 2) | (b[1] >> 4));
                if(b[2] < 64)
                {
                    decoded[j++] = static_cast<char>((b[1] << 4) | (b[2] >> 2));
                    if(b[3] < 64)
                    {
                        decoded[j++] = static_cast<char>((b[2] << 6) | b[3]);
                    }
                }
            }
            return ret;
        }
        else
        {
            return MemoryChunk::Null();
        }
    }
}
<|endoftext|>


<commit_before>#include "clstm.h"
#include <assert.h>
#include <iostream>
#include <vector>
#include <memory>
#include <math.h>
#include <string>
#include "extras.h"
#include "utils.h"

using std_string = std::string;
#define string std_string
using std::vector;
using std::shared_ptr;
using std::unique_ptr;
using std::to_string;
using std::make_pair;
using std::cout;
using std::stoi;
using namespace Eigen;
using namespace ocropus;

double sqr(double x) { return x * x; }

double randu() {
  static int count = 1;
  for (;;) {
    double x = cos(count * 3.7);
    count++;
    if (fabs(x) > 0.1) return x;
  }
}

void randseq(Sequence &a, int N, int n, int m) {
  a.resize(N, n, m);
  for (int t = 0; t < N; t++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) a[t].v(i, j) = randu();
}
void randparams(vector<Params> &a) {
  int N = a.size();
  for (int t = 0; t < N; t++) {
    int n = a[t].rows();
    int m = a[t].cols();
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) a[t].v(i, j) = randu();
  }
}

double err(Sequence &a, Sequence &b) {
  assert(a.size() == b.size());
  assert(a.rows() == b.rows());
  assert(a.cols() == b.cols());
  int N = a.size(), n = a.rows(), m = a.cols();
  double total = 0.0;
  for (int t = 0; t < N; t++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) total += sqr(a[t].v(i, j) - b[t].v(i, j));
  return total;
}

void zero_grad(Network net) {
  walk_params(net, [](const string &s, Params *p) { p->zeroGrad(); });
}
void get_params(vector<Params> &params, Network net) {
  params.clear();
  walk_params(
      net, [&params](const string &s, Params *p) { params.emplace_back(*p); });
}

void set_params(Network net, vector<Params> &params) {
  int index = 0;
  walk_params(net, [&index, &params](const string &s, Params *p) {
    *p = params[index++];
  });
  assert(index == params.size());
}

struct Minimizer {
  double value = 1e9;
  double param = 0;
  void add(double value, double param = NAN) {
    if (value >= this->value) return;
    this->value = value;
    this->param = param;
  }
};

struct Maximizer {
  double value = -1e9;
  double param = 0;
  void add(double value, double param = NAN) {
    if (value <= this->value) return;
    this->value = value;
    this->param = param;
  }
};

void test_net(Network net, string id="", int bs=1) {
  if (id=="") id = net->kind;
  print("testing", id);
  int N = 4;
  int ninput = net->ninput();
  int noutput = net->noutput();
  ;
  bool verbose = getienv("verbose", 0);
  vector<Params> params, params1;
  get_params(params, net);
  randparams(params);
  set_params(net, params);
  Sequence xs, ys;
  randseq(xs, N, ninput, bs);
  randseq(ys, N, noutput, bs);

  Maximizer maxinerr;
  for (int t = 0; t < N; t++) {
    for (int i = 0; i < ninput; i++) {
      for (int b = 0; b < bs; b++) {
        Minimizer minerr;
        for (float h = 1e-6; h < 1.0; h *= 10) {
          set_inputs(net, xs);
          net->forward();
          double out1 = err(net->outputs, ys);
          net->inputs[t].v(i, b) += h;
          net->forward();
          double out2 = err(net->outputs, ys);
          double num_deriv = (out2 - out1) / h;

          set_inputs(net, xs);
          net->forward();
          set_targets(net, ys);
          net->backward();
          double a_deriv = net->inputs[t].d(i, b);
          double error = fabs(1.0 - num_deriv / a_deriv / -2.0);
          minerr.add(error, h);
        }
        if (verbose) print("deltas", t, i, b, minerr.value, minerr.param);
        assert(minerr.value < 0.1);
        maxinerr.add(minerr.value);
      }
    }
  }

  set_inputs(net, xs);
  net->forward();
  double out = err(net->outputs, ys);
  set_targets(net, ys);
  zero_grad(net);
  net->backward();
  get_params(params, net);

  Maximizer maxparamerr;
  for (int k = 0; k < params.size(); k++) {
    Params &p = params[k];
    int n = p.rows(), m = p.cols();
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        Minimizer minerr;
        for (float h = 1e-6; h < 1.0; h *= 10) {
          params1 = params;
          params1[k].v(i, j) += h;
          set_params(net, params1);
          net->forward();
          double out1 = err(net->outputs, ys);
          double num_deriv = (out1 - out) / h;
          double a_deriv = params[k].d(i, j);
          double error = fabs(1.0 - num_deriv / a_deriv / -2.0);
          minerr.add(error, h);
        }
        if (verbose) print("params", k, i, j, minerr.value, minerr.param);
        assert(minerr.value < 0.1);
        maxparamerr.add(minerr.value);
      }
    }
  }
  print("OK", maxinerr.value, maxparamerr.value);
}

int main(int argc, char **argv) {
  TRY {
    test_net(layer("LinearLayer", 7, 3, {}, {}));
    test_net(layer("SigmoidLayer", 7, 3, {}, {}));
    test_net(layer("TanhLayer", 7, 3, {}, {}));
    test_net(layer("NPLSTM", 7, 3, {}, {}));
    test_net(
        layer("Reversed", 7, 3, {}, {layer("SigmoidLayer", 7, 3, {}, {})}));
    test_net(layer("Parallel", 7, 3, {}, {layer("SigmoidLayer", 7, 3, {}, {}),
	    layer("LinearLayer", 7, 3, {}, {})}),
      "parallel(sigmoid,linear)");
    test_net(make_net("bidi", {{"ninput", 7},
                               {"noutput", 3},
                               {"nhidden", 5},
                               {"output_type", "SigmoidLayer"}}),
      "bidi");
    test_net(layer("Stacked", 3, 3, {}, {
	  layer("Btswitch", 3, 3, {}, {}),
	    layer("Btswitch", 3, 3, {}, {})}),
      "btswitch");
    test_net(layer("Batchstack", 3, 9, {}, {}),
      "Batchstack", 5);
    // not testing: SoftmaxLayer and ReluLayer
  }
  CATCH(const char *message) { print("ERROR", message); }
}
<commit_msg>changed test-deriv to use inf/-inf by default<commit_after>#include "clstm.h"
#include <assert.h>
#include <iostream>
#include <vector>
#include <memory>
#include <math.h>
#include <cmath>
#include <string>
#include "extras.h"
#include "utils.h"

using std_string = std::string;
#define string std_string
using std::vector;
using std::shared_ptr;
using std::unique_ptr;
using std::to_string;
using std::make_pair;
using std::cout;
using std::stoi;
using namespace Eigen;
using namespace ocropus;

double sqr(double x) { return x * x; }

double randu() {
  static int count = 1;
  for (;;) {
    double x = cos(count * 3.7);
    count++;
    if (fabs(x) > 0.1) return x;
  }
}

void randseq(Sequence &a, int N, int n, int m) {
  a.resize(N, n, m);
  for (int t = 0; t < N; t++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) a[t].v(i, j) = randu();
}
void randparams(vector<Params> &a) {
  int N = a.size();
  for (int t = 0; t < N; t++) {
    int n = a[t].rows();
    int m = a[t].cols();
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) a[t].v(i, j) = randu();
  }
}

double err(Sequence &a, Sequence &b) {
  assert(a.size() == b.size());
  assert(a.rows() == b.rows());
  assert(a.cols() == b.cols());
  int N = a.size(), n = a.rows(), m = a.cols();
  double total = 0.0;
  for (int t = 0; t < N; t++)
    for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++) total += sqr(a[t].v(i, j) - b[t].v(i, j));
  return total;
}

void zero_grad(Network net) {
  walk_params(net, [](const string &s, Params *p) { p->zeroGrad(); });
}
void get_params(vector<Params> &params, Network net) {
  params.clear();
  walk_params(
      net, [&params](const string &s, Params *p) { params.emplace_back(*p); });
}

void set_params(Network net, vector<Params> &params) {
  int index = 0;
  walk_params(net, [&index, &params](const string &s, Params *p) {
    *p = params[index++];
  });
  assert(index == params.size());
}

struct Minimizer {
  double value = INFINITY;
  double param = 0;
  void add(double value, double param = NAN) {
    if (value >= this->value) return;
    this->value = value;
    this->param = param;
  }
};

struct Maximizer {
  double value = -INFINITY;
  double param = 0;
  void add(double value, double param = NAN) {
    if (value <= this->value) return;
    this->value = value;
    this->param = param;
  }
};

void test_net(Network net, string id="", int bs=1) {
  if (id=="") id = net->kind;
  print("testing", id);
  int N = 4;
  int ninput = net->ninput();
  int noutput = net->noutput();
  ;
  bool verbose = getienv("verbose", 0);
  vector<Params> params, params1;
  get_params(params, net);
  randparams(params);
  set_params(net, params);
  Sequence xs, ys;
  randseq(xs, N, ninput, bs);
  randseq(ys, N, noutput, bs);

  Maximizer maxinerr;
  for (int t = 0; t < N; t++) {
    for (int i = 0; i < ninput; i++) {
      for (int b = 0; b < bs; b++) {
        Minimizer minerr;
        for (float h = 1e-6; h < 1.0; h *= 10) {
          set_inputs(net, xs);
          net->forward();
          double out1 = err(net->outputs, ys);
          net->inputs[t].v(i, b) += h;
          net->forward();
          double out2 = err(net->outputs, ys);
          double num_deriv = (out2 - out1) / h;

          set_inputs(net, xs);
          net->forward();
          set_targets(net, ys);
          net->backward();
          double a_deriv = net->inputs[t].d(i, b);
          double error = fabs(1.0 - num_deriv / a_deriv / -2.0);
          minerr.add(error, h);
        }
        if (verbose) print("deltas", t, i, b, minerr.value, minerr.param);
        assert(minerr.value < 0.1);
        maxinerr.add(minerr.value);
      }
    }
  }

  set_inputs(net, xs);
  net->forward();
  double out = err(net->outputs, ys);
  set_targets(net, ys);
  zero_grad(net);
  net->backward();
  get_params(params, net);

  Maximizer maxparamerr;
  for (int k = 0; k < params.size(); k++) {
    Params &p = params[k];
    int n = p.rows(), m = p.cols();
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        Minimizer minerr;
        for (float h = 1e-6; h < 1.0; h *= 10) {
          params1 = params;
          params1[k].v(i, j) += h;
          set_params(net, params1);
          net->forward();
          double out1 = err(net->outputs, ys);
          double num_deriv = (out1 - out) / h;
          double a_deriv = params[k].d(i, j);
          double error = fabs(1.0 - num_deriv / a_deriv / -2.0);
          minerr.add(error, h);
        }
        if (verbose) print("params", k, i, j, minerr.value, minerr.param);
        assert(minerr.value < 0.1);
        maxparamerr.add(minerr.value);
      }
    }
  }
  print("OK", maxinerr.value, maxparamerr.value);
}

int main(int argc, char **argv) {
  TRY {
    test_net(layer("LinearLayer", 7, 3, {}, {}));
    test_net(layer("SigmoidLayer", 7, 3, {}, {}));
    test_net(layer("TanhLayer", 7, 3, {}, {}));
    test_net(layer("NPLSTM", 7, 3, {}, {}));
    test_net(
        layer("Reversed", 7, 3, {}, {layer("SigmoidLayer", 7, 3, {}, {})}));
    test_net(layer("Parallel", 7, 3, {}, {layer("SigmoidLayer", 7, 3, {}, {}),
	    layer("LinearLayer", 7, 3, {}, {})}),
      "parallel(sigmoid,linear)");
    test_net(make_net("bidi", {{"ninput", 7},
                               {"noutput", 3},
                               {"nhidden", 5},
                               {"output_type", "SigmoidLayer"}}),
      "bidi");
    test_net(layer("Stacked", 3, 3, {}, {
	  layer("Btswitch", 3, 3, {}, {}),
	    layer("Btswitch", 3, 3, {}, {})}),
      "btswitch");
    test_net(layer("Batchstack", 3, 9, {}, {}),
      "Batchstack", 5);
    // not testing: SoftmaxLayer and ReluLayer
  }
  CATCH(const char *message) { print("ERROR", message); }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/escape_string.hpp"

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp>
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	char ih_hex[41];
	to_hex((char const*)&ih[0], 20, ih_hex);
	char msg[200];
	int msg_len = snprintf(msg, 200,
		"BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: %d\r\n"
		"Infohash: %s\r\n"
		"\r\n\r\n", listen_port, ih_hex);

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg, msg_len, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	snprintf(msg, 200, "%s ==> announce: ih: %s port: %u\n"
		, time_now_string(), ih_hex, listen_port);
	m_log << msg;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message\n";
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	from_hex(ih_str.c_str(), 40, (char*)&ih[0]);
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		char msg[200];
		snprintf(msg, 200, "%s *** incoming local announce %s:%d ih: %s\n"
			, time_now_string(), print_address(from.address()).c_str()
			, port, ih_str.c_str());
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<commit_msg>fixed lsd logging<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/escape_string.hpp"

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp>
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	char ih_hex[41];
	to_hex((char const*)&ih[0], 20, ih_hex);
	char msg[200];
	int msg_len = snprintf(msg, 200,
		"BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: %d\r\n"
		"Infohash: %s\r\n"
		"\r\n\r\n", listen_port, ih_hex);

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg, msg_len, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	snprintf(msg, 200, "%s ==> announce: ih: %s port: %u"
		, time_now_string(), ih_hex, listen_port);
	m_log << msg << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message" << std::endl;
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	from_hex(ih_str.c_str(), 40, (char*)&ih[0]);
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		char msg[200];
		snprintf(msg, 200, "%s *** incoming local announce %s:%d ih: %s\n"
			, time_now_string(), print_address(from.address()).c_str()
			, port, ih_str.c_str());
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: iipaobj.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2006-09-25 13:32:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _IIPAOBJ_HXX_
#define _IIPAOBJ_HXX_
#if defined(_MSC_VER) && (_MSC_VER > 1310)
#pragma warning(disable : 4917 4555)
#endif

#include "stdafx.h"
#include <oleidl.h>

#include <osl/interlck.h>
#include <rtl/ref.hxx>
class EmbedDocument_Impl;
class DocumentHolder;

class CIIAObj
    : public IOleInPlaceActiveObject
{

public:

    CIIAObj( DocumentHolder * );
    virtual ~CIIAObj();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID, LPVOID FAR * ppvObj);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);

    /* IOleInPlaceActiveObject methods */
    STDMETHODIMP GetWindow(HWND *);
    STDMETHODIMP ContextSensitiveHelp(BOOL);
    STDMETHODIMP TranslateAccelerator(LPMSG);
    STDMETHODIMP OnFrameWindowActivate(BOOL);
    STDMETHODIMP OnDocWindowActivate(BOOL);
    STDMETHODIMP ResizeBorder(LPCRECT, LPOLEINPLACEUIWINDOW
                              , BOOL);
    STDMETHODIMP EnableModeless(BOOL);

private:

    oslInterlockedCount                 m_refCount;
    ::rtl::Reference< DocumentHolder >  m_rDocHolder;
};

#endif<commit_msg>INTEGRATION: CWS changefileheader (1.6.38); FILE MERGED 2008/03/31 13:33:42 rt 1.6.38.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: iipaobj.hxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _IIPAOBJ_HXX_
#define _IIPAOBJ_HXX_
#if defined(_MSC_VER) && (_MSC_VER > 1310)
#pragma warning(disable : 4917 4555)
#endif

#include "stdafx.h"
#include <oleidl.h>

#include <osl/interlck.h>
#include <rtl/ref.hxx>
class EmbedDocument_Impl;
class DocumentHolder;

class CIIAObj
    : public IOleInPlaceActiveObject
{

public:

    CIIAObj( DocumentHolder * );
    virtual ~CIIAObj();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID, LPVOID FAR * ppvObj);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);

    /* IOleInPlaceActiveObject methods */
    STDMETHODIMP GetWindow(HWND *);
    STDMETHODIMP ContextSensitiveHelp(BOOL);
    STDMETHODIMP TranslateAccelerator(LPMSG);
    STDMETHODIMP OnFrameWindowActivate(BOOL);
    STDMETHODIMP OnDocWindowActivate(BOOL);
    STDMETHODIMP ResizeBorder(LPCRECT, LPOLEINPLACEUIWINDOW
                              , BOOL);
    STDMETHODIMP EnableModeless(BOOL);

private:

    oslInterlockedCount                 m_refCount;
    ::rtl::Reference< DocumentHolder >  m_rDocHolder;
};

#endif<|endoftext|>


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

#include "src/envoy/utils/utils.h"
#include "mixer/v1/attributes.pb.h"

using ::google::protobuf::Message;
using ::google::protobuf::Struct;
using ::google::protobuf::util::Status;

namespace Envoy {
namespace Utils {

namespace {

const std::string kSPIFFEPrefix("spiffe://");

// Per-host opaque data field
const std::string kPerHostMetadataKey("istio");

// Attribute field for per-host data override
const std::string kMetadataDestinationUID("uid");

}  // namespace

void ExtractHeaders(const Http::HeaderMap& header_map,
                    const std::set<std::string>& exclusives,
                    std::map<std::string, std::string>& headers) {
  struct Context {
    Context(const std::set<std::string>& exclusives,
            std::map<std::string, std::string>& headers)
        : exclusives(exclusives), headers(headers) {}
    const std::set<std::string>& exclusives;
    std::map<std::string, std::string>& headers;
  };
  Context ctx(exclusives, headers);
  header_map.iterate(
      [](const Http::HeaderEntry& header,
         void* context) -> Http::HeaderMap::Iterate {
        Context* ctx = static_cast<Context*>(context);
        if (ctx->exclusives.count(header.key().c_str()) == 0) {
          ctx->headers[header.key().c_str()] = header.value().c_str();
        }
        return Http::HeaderMap::Iterate::Continue;
      },
      &ctx);
}

bool GetIpPort(const Network::Address::Ip* ip, std::string* str_ip, int* port) {
  if (ip) {
    *port = ip->port();
    if (ip->ipv4()) {
      uint32_t ipv4 = ip->ipv4()->address();
      *str_ip = std::string(reinterpret_cast<const char*>(&ipv4), sizeof(ipv4));
      return true;
    }
    if (ip->ipv6()) {
      absl::uint128 ipv6 = ip->ipv6()->address();
      *str_ip = std::string(reinterpret_cast<const char*>(&ipv6), 16);
      return true;
    }
  }
  return false;
}

bool GetDestinationUID(const envoy::api::v2::core::Metadata& metadata,
                       std::string* uid) {
  const auto filter_it = metadata.filter_metadata().find(kPerHostMetadataKey);
  if (filter_it == metadata.filter_metadata().end()) {
    return false;
  }
  const Struct& struct_pb = filter_it->second;
  const auto fields_it = struct_pb.fields().find(kMetadataDestinationUID);
  if (fields_it == struct_pb.fields().end()) {
    return false;
  }
  *uid = fields_it->second.string_value();
  return true;
}

bool GetPrincipal(const Network::Connection* connection, bool peer,
                  std::string* principal) {
  if (connection) {
    Ssl::Connection* ssl = const_cast<Ssl::Connection*>(connection->ssl());
    if (ssl != nullptr) {
      std::string result;
      if (peer) {
        result = ssl->uriSanPeerCertificate();
      } else {
        result = ssl->uriSanLocalCertificate();
      }

      if (result.empty()) {  // empty result is not allowed
        return false;
      }
      if (result.length() >= kSPIFFEPrefix.length() &&
          result.compare(0, kSPIFFEPrefix.length(), kSPIFFEPrefix) == 0) {
        // Strip out the prefix "spiffe://" in the identity.
        *principal = result.substr(kSPIFFEPrefix.size());
      } else {
        *principal = result;
      }
      return true;
    }
  }
  return false;
}

bool IsMutualTLS(const Network::Connection* connection) {
  return connection != nullptr && connection->ssl() != nullptr &&
         connection->ssl()->peerCertificatePresented();
}

bool GetRequestedServerName(const Network::Connection* connection,
                            std::string* name) {
  if (connection) {
    *name = std::string(connection->requestedServerName());
    return true;
  }

  return false;
}

Status ParseJsonMessage(const std::string& json, Message* output) {
  ::google::protobuf::util::JsonParseOptions options;
  options.ignore_unknown_fields = true;
  return ::google::protobuf::util::JsonStringToMessage(json, output, options);
}

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

#include "src/envoy/utils/utils.h"
#include "mixer/v1/attributes.pb.h"

using ::google::protobuf::Message;
using ::google::protobuf::Struct;
using ::google::protobuf::util::Status;

namespace Envoy {
namespace Utils {

namespace {

const std::string kSPIFFEPrefix("spiffe://");

// Per-host opaque data field
const std::string kPerHostMetadataKey("istio");

// Attribute field for per-host data override
const std::string kMetadataDestinationUID("uid");

}  // namespace

void ExtractHeaders(const Http::HeaderMap& header_map,
                    const std::set<std::string>& exclusives,
                    std::map<std::string, std::string>& headers) {
  struct Context {
    Context(const std::set<std::string>& exclusives,
            std::map<std::string, std::string>& headers)
        : exclusives(exclusives), headers(headers) {}
    const std::set<std::string>& exclusives;
    std::map<std::string, std::string>& headers;
  };
  Context ctx(exclusives, headers);
  header_map.iterate(
      [](const Http::HeaderEntry& header,
         void* context) -> Http::HeaderMap::Iterate {
        Context* ctx = static_cast<Context*>(context);
        if (ctx->exclusives.count(header.key().c_str()) == 0) {
          ctx->headers[header.key().c_str()] = header.value().c_str();
        }
        return Http::HeaderMap::Iterate::Continue;
      },
      &ctx);
}

bool GetIpPort(const Network::Address::Ip* ip, std::string* str_ip, int* port) {
  if (ip) {
    *port = ip->port();
    if (ip->ipv4()) {
      uint32_t ipv4 = ip->ipv4()->address();
      *str_ip = std::string(reinterpret_cast<const char*>(&ipv4), sizeof(ipv4));
      return true;
    }
    if (ip->ipv6()) {
      absl::uint128 ipv6 = ip->ipv6()->address();
      *str_ip = std::string(reinterpret_cast<const char*>(&ipv6), 16);
      return true;
    }
  }
  return false;
}

bool GetDestinationUID(const envoy::api::v2::core::Metadata& metadata,
                       std::string* uid) {
  const auto filter_it = metadata.filter_metadata().find(kPerHostMetadataKey);
  if (filter_it == metadata.filter_metadata().end()) {
    return false;
  }
  const Struct& struct_pb = filter_it->second;
  const auto fields_it = struct_pb.fields().find(kMetadataDestinationUID);
  if (fields_it == struct_pb.fields().end()) {
    return false;
  }
  *uid = fields_it->second.string_value();
  return true;
}

bool GetPrincipal(const Network::Connection* connection, bool peer,
                  std::string* principal) {
  if (connection) {
    Ssl::Connection* ssl = const_cast<Ssl::Connection*>(connection->ssl());
    if (ssl != nullptr) {
      std::string result;
      if (peer) {
        result = ssl->uriSanPeerCertificate();
      } else {
        result = ssl->uriSanLocalCertificate();
      }

      if (result.empty()) {  // empty result is not allowed
        return false;
      }
      if (result.length() >= kSPIFFEPrefix.length() &&
          result.compare(0, kSPIFFEPrefix.length(), kSPIFFEPrefix) == 0) {
        // Strip out the prefix "spiffe://" in the identity.
        *principal = result.substr(kSPIFFEPrefix.size());
      } else {
        *principal = result;
      }
      return true;
    }
  }
  return false;
}

bool IsMutualTLS(const Network::Connection* connection) {
  return connection != nullptr && connection->ssl() != nullptr &&
         connection->ssl()->peerCertificatePresented();
}

bool GetRequestedServerName(const Network::Connection* connection,
                            std::string* name) {
  if (connection && !connection->requestedServerName().empty()) {
    *name = std::string(connection->requestedServerName());
    return true;
  }

  return false;
}

Status ParseJsonMessage(const std::string& json, Message* output) {
  ::google::protobuf::util::JsonParseOptions options;
  options.ignore_unknown_fields = true;
  return ::google::protobuf::util::JsonStringToMessage(json, output, options);
}

}  // namespace Utils
}  // namespace Envoy
<|endoftext|>


<commit_before>/*
 * LIFGap.hpp
 *
 *  Created on: Jul 29, 2011
 *      Author: garkenyon
 */

#ifndef LIFGAP_HPP_
#define LIFGAP_HPP_

#include "LIF.hpp"

#define NUM_LIFGAP_EVENTS   1 + NUM_LIF_EVENTS  // ???
#define EV_LIF_GSYN_GAP     NUM_LIF_EVENTS + 1

namespace PV {

class LIFGap: public PV::LIF {
public:
   LIFGap(const char* name, HyPerCol * hc);
   LIFGap(const char* name, HyPerCol * hc, PVLayerType type);
   virtual ~LIFGap();

   void addGapStrength(float gap_strength){sumGap += gap_strength;}
   int virtual updateStateOpenCL(float time, float dt);
   int virtual triggerReceive(InterColComm* comm);
   int virtual updateState(float time, float dt);
   int virtual readState(float * time);
   int virtual writeState(float time, bool last);

protected:

   pvdata_t * G_Gap;
   pvdata_t sumGap;

#ifdef PV_USE_OPENCL
   virtual int initializeThreadBuffers(char * kernelName);
   virtual int initializeThreadKernels(char * kernelName);

   // OpenCL buffers
   //
   CLBuffer * clG_Gap;
   virtual int getNumCLEvents(){return NUM_LIFGAP_EVENTS};
#endif

private:
   virtual int initialize(PVLayerType type, const char * kernelName);

};

} /* namespace PV */
#endif /* LIFGAP_HPP_ */
<commit_msg>Added clGSynGap instance variable.<commit_after>/*
 * LIFGap.hpp
 *
 *  Created on: Jul 29, 2011
 *      Author: garkenyon
 */

#ifndef LIFGAP_HPP_
#define LIFGAP_HPP_

#include "LIF.hpp"

#define NUM_LIFGAP_EVENTS   1 + NUM_LIF_EVENTS  // ???
#define EV_LIF_GSYN_GAP     NUM_LIF_EVENTS + 1

namespace PV {

class LIFGap: public PV::LIF {
public:
   LIFGap(const char* name, HyPerCol * hc);
   LIFGap(const char* name, HyPerCol * hc, PVLayerType type);
   virtual ~LIFGap();

   void addGapStrength(float gap_strength){sumGap += gap_strength;}
   int virtual updateStateOpenCL(float time, float dt);
   int virtual triggerReceive(InterColComm* comm);
   int virtual updateState(float time, float dt);
   int virtual readState(float * time);
   int virtual writeState(float time, bool last);

protected:

   pvdata_t * G_Gap;
   pvdata_t sumGap;

#ifdef PV_USE_OPENCL
   virtual int initializeThreadBuffers(char * kernelName);
   virtual int initializeThreadKernels(char * kernelName);

   // OpenCL buffers
   //
   CLBuffer * clG_Gap;
   CLBuffer * clGSynGap;

   virtual int getNumCLEvents(){return NUM_LIFGAP_EVENTS;}
#endif

private:
   virtual int initialize(PVLayerType type, const char * kernelName);

};

} /* namespace PV */
#endif /* LIFGAP_HPP_ */
<|endoftext|>


<commit_before>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * StageprofiWidget.cpp
 * This is the base widget class
 * Copyright (C) 2006-2009 Simon Newton
 */

#include <string.h>
#include <algorithm>
#include "ola/Callback.h"
#include "plugins/stageprofi/StageProfiWidget.h"

namespace ola {
namespace plugin {
namespace stageprofi {

enum stageprofi_packet_type_e {
  ID_GETDMX =  0xFE,
  ID_SETDMX = 0xFF,
  ID_SETLO =  0xE0,
  ID_SETHI =  0xE1,
};

typedef enum stageprofi_packet_type_e stageprofi_packet_type;

/*
 * New widget
 */
StageProfiWidget::~StageProfiWidget() {
  if (m_socket) {
    m_socket->Close();
    delete m_socket;
  }
}

/*
 * Disconnect from the widget
 */
int StageProfiWidget::Disconnect() {
  m_socket->Close();
  return 0;
}

/*
 * Send a dmx msg.
 * This has the nasty property of blocking if we remove the device
 * TODO: fix this
 */
bool StageProfiWidget::SendDmx(const DmxBuffer &buffer) const {
  unsigned int index = 0;
  while (index < buffer.Size()) {
    unsigned int size = std::min((unsigned int) DMX_MSG_LEN,
                                 buffer.Size() - index);
    Send255(index, buffer.GetRaw() + index, size);
    index += size;
  }
  return true;
}

/*
 * Called when there is adata to read
 */
void StageProfiWidget::SocketReady() {
  while (m_socket->DataRemaining() > 0) {
    DoRecv();
  }
}

void StageProfiWidget::Timeout() {
  if (m_ss)
    m_ss->Terminate();
}

/*
 * Check if this is actually a StageProfi device
 * @return true if this is a stageprofi,  false otherwise
 */
bool StageProfiWidget::DetectDevice() {
  if (m_ss)
    delete m_ss;

  m_got_response = false;
  m_ss = new SelectServer();
  m_ss->AddReadDescriptor(m_socket, NULL);
  m_ss->RegisterSingleTimeout(
      100,
      ola::NewSingleCallback(this, &StageProfiWidget::Timeout));

  // try a command, we should get a response
  SetChannel(0, 0);

  m_ss->Run();
  delete m_ss;
  m_ss = NULL;
  if (m_got_response)
    return true;

  m_socket->Close();
  return false;
}

//-----------------------------------------------------------------------------
// Private methods used for communicating with the widget

/*
 * Set a single channel
 */
int StageProfiWidget::SetChannel(unsigned int chan, uint8_t val) const {
  uint8_t msg[3];

  msg[0] = chan > DMX_MSG_LEN ? ID_SETHI : ID_SETLO;
  msg[1] = chan & 0xFF;
  msg[2] = val;
  return m_socket->Send(msg, sizeof(msg));
}

/*
 * Send 255 channels worth of data
 * @param start the start channel for the data
 * @param buf a pointer to the data
 * @param len the length of the data
 */
int StageProfiWidget::Send255(unsigned int start, const uint8_t *buf,
                              unsigned int length) const {
  uint8_t msg[DMX_MSG_LEN + DMX_HEADER_SIZE];
  unsigned int len = std::min((unsigned int) DMX_MSG_LEN, length);

  msg[0] = ID_SETDMX;
  msg[1] = start & 0xFF;
  msg[2] = (start>>8) & 0xFF;
  msg[3] = len;
  memcpy(msg + DMX_HEADER_SIZE, buf, len);
  return m_socket->Send(msg, len + DMX_HEADER_SIZE);
}

/*
 *
 */
int StageProfiWidget::DoRecv() {
  uint8_t byte = 0x00;
  unsigned int data_read;

  while (byte != 'G') {
    int ret = m_socket->Receive(&byte, 1, data_read);

    if (ret == -1 || data_read != 1) {
      return -1;
    }
  }
  m_got_response = true;
  return 0;
}
}  // stageprofi
}  // plugin
}  // ola
<commit_msg>Fix a compile error with the StageProfiWidget<commit_after>/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * StageprofiWidget.cpp
 * This is the base widget class
 * Copyright (C) 2006-2009 Simon Newton
 */

#include <string.h>
#include <algorithm>
#include "ola/Callback.h"
#include "plugins/stageprofi/StageProfiWidget.h"

namespace ola {
namespace plugin {
namespace stageprofi {

enum stageprofi_packet_type_e {
  ID_GETDMX =  0xFE,
  ID_SETDMX = 0xFF,
  ID_SETLO =  0xE0,
  ID_SETHI =  0xE1,
};

typedef enum stageprofi_packet_type_e stageprofi_packet_type;

/*
 * New widget
 */
StageProfiWidget::~StageProfiWidget() {
  if (m_socket) {
    m_socket->Close();
    delete m_socket;
  }
}

/*
 * Disconnect from the widget
 */
int StageProfiWidget::Disconnect() {
  m_socket->Close();
  return 0;
}

/*
 * Send a dmx msg.
 * This has the nasty property of blocking if we remove the device
 * TODO: fix this
 */
bool StageProfiWidget::SendDmx(const DmxBuffer &buffer) const {
  unsigned int index = 0;
  while (index < buffer.Size()) {
    unsigned int size = std::min((unsigned int) DMX_MSG_LEN,
                                 buffer.Size() - index);
    Send255(index, buffer.GetRaw() + index, size);
    index += size;
  }
  return true;
}

/*
 * Called when there is adata to read
 */
void StageProfiWidget::SocketReady() {
  while (m_socket->DataRemaining() > 0) {
    DoRecv();
  }
}

void StageProfiWidget::Timeout() {
  if (m_ss)
    m_ss->Terminate();
}

/*
 * Check if this is actually a StageProfi device
 * @return true if this is a stageprofi,  false otherwise
 */
bool StageProfiWidget::DetectDevice() {
  if (m_ss)
    delete m_ss;

  m_got_response = false;
  m_ss = new SelectServer();
  m_ss->AddReadDescriptor(m_socket, false);
  m_ss->RegisterSingleTimeout(
      100,
      ola::NewSingleCallback(this, &StageProfiWidget::Timeout));

  // try a command, we should get a response
  SetChannel(0, 0);

  m_ss->Run();
  delete m_ss;
  m_ss = NULL;
  if (m_got_response)
    return true;

  m_socket->Close();
  return false;
}

//-----------------------------------------------------------------------------
// Private methods used for communicating with the widget

/*
 * Set a single channel
 */
int StageProfiWidget::SetChannel(unsigned int chan, uint8_t val) const {
  uint8_t msg[3];

  msg[0] = chan > DMX_MSG_LEN ? ID_SETHI : ID_SETLO;
  msg[1] = chan & 0xFF;
  msg[2] = val;
  return m_socket->Send(msg, sizeof(msg));
}

/*
 * Send 255 channels worth of data
 * @param start the start channel for the data
 * @param buf a pointer to the data
 * @param len the length of the data
 */
int StageProfiWidget::Send255(unsigned int start, const uint8_t *buf,
                              unsigned int length) const {
  uint8_t msg[DMX_MSG_LEN + DMX_HEADER_SIZE];
  unsigned int len = std::min((unsigned int) DMX_MSG_LEN, length);

  msg[0] = ID_SETDMX;
  msg[1] = start & 0xFF;
  msg[2] = (start>>8) & 0xFF;
  msg[3] = len;
  memcpy(msg + DMX_HEADER_SIZE, buf, len);
  return m_socket->Send(msg, len + DMX_HEADER_SIZE);
}

/*
 *
 */
int StageProfiWidget::DoRecv() {
  uint8_t byte = 0x00;
  unsigned int data_read;

  while (byte != 'G') {
    int ret = m_socket->Receive(&byte, 1, data_read);

    if (ret == -1 || data_read != 1) {
      return -1;
    }
  }
  m_got_response = true;
  return 0;
}
}  // stageprofi
}  // plugin
}  // ola
<|endoftext|>


<commit_before>#include "model.h"
#include <string>
#include <exception>

std::istream& operator>>(std::istream& in, Model &model) {
  int count;
  in >> count;
  while (count --> 0) {
    std::string type;
    in >> type;
    if (type == "segment") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Segment>(Point(x1, y1), Point(x2, y2)));
    } else if (type == "rectangle") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Rectangle>(BoundingBox({Point(x1, y1), Point(x2, y2)})));
    } else if (type == "ellipse") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Ellipse>(BoundingBox({Point(x1, y1), Point(x2, y2)})));
    } else {
      throw std::runtime_error("Invalid model format");
    }
  }
  return in;
}
<commit_msg>model: operator>>: some information to runtime_exception() throw was added<commit_after>#include "model.h"
#include <string>
#include <exception>

std::istream& operator>>(std::istream& in, Model &model) {
  int count;
  in >> count;
  while (count --> 0) {
    std::string type;
    in >> type;
    if (type == "segment") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Segment>(Point(x1, y1), Point(x2, y2)));
    } else if (type == "rectangle") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Rectangle>(BoundingBox({Point(x1, y1), Point(x2, y2)})));
    } else if (type == "ellipse") {
      int x1, y1, x2, y2;
      in >> x1 >> y1 >> x2 >> y2;
      model.addFigure(std::make_shared<figures::Ellipse>(BoundingBox({Point(x1, y1), Point(x2, y2)})));
    } else {
      throw std::runtime_error("Invalid model format: unknown type: " + type);
    }
  }
  return in;
}
<|endoftext|>


<commit_before>/**
 * @file   AspectRatio.hpp
 * @brief  AspectRatio class prototype.
 * @author zer0
 * @date   2018-07-10
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/geometry/Size2.hpp>
#include <libtbag/math/Euclidean.hpp>

#include <utility>
#include <type_traits>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace math {

template <typename T>
void calcAspectRatio(T a, T b, T & a_result, T & b_result)
{
    auto const GCD = gcd(a, b);
    a_result = a / GCD;
    b_result = b / GCD;
}

template <typename T>
std::pair<T, T> calcAspectRatio(T a, T b)
{
    std::pair<T, T> result;
    calcAspectRatio(a, b, result.first, result.second);
    return result;
}

template <typename T, typename ScaleType = typename std::conditional<std::is_floating_point<T>::value, T, double>::type>
libtbag::geometry::BaseSize2<T> scaleUpAspectRatio(libtbag::geometry::BaseSize2<T> const & src,
                                                   libtbag::geometry::BaseSize2<T> const & scale_up)
{
    auto const SCALE_X = scale_up.width / static_cast<ScaleType>(src.width);
    auto const SCALE_Y = scale_up.height / static_cast<ScaleType>(src.height);
    if (SCALE_X < SCALE_Y) {
        return libtbag::geometry::BaseSize2<T>(src.width * SCALE_X, src.height * SCALE_X);
    } else {
        return libtbag::geometry::BaseSize2<T>(src.width * SCALE_Y, src.height * SCALE_Y);
    }
}

} // namespace math

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__

<commit_msg>Create getSizeOfAspectRatio() method.<commit_after>/**
 * @file   AspectRatio.hpp
 * @brief  AspectRatio class prototype.
 * @author zer0
 * @date   2018-07-10
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/geometry/Size2.hpp>
#include <libtbag/math/Euclidean.hpp>

#include <cassert>
#include <utility>
#include <type_traits>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace math {

template <typename T>
void calcAspectRatio(T a, T b, T & a_result, T & b_result)
{
    auto const GCD = gcd(a, b);
    assert(GCD != 0);
    a_result = a / GCD;
    b_result = b / GCD;
}

template <typename T>
std::pair<T, T> calcAspectRatio(T a, T b)
{
    std::pair<T, T> result;
    calcAspectRatio(a, b, result.first, result.second);
    return result;
}

template <typename T, typename ScaleType = typename std::conditional<std::is_floating_point<T>::value, T, double>::type>
libtbag::geometry::BaseSize2<T> scaleUpAspectRatio(libtbag::geometry::BaseSize2<T> const & src,
                                                   libtbag::geometry::BaseSize2<T> const & scale_up)
{
    assert(static_cast<ScaleType>(src.width) != 0);
    assert(static_cast<ScaleType>(src.height) != 0);

    auto const SCALE_X = scale_up.width / static_cast<ScaleType>(src.width);
    auto const SCALE_Y = scale_up.height / static_cast<ScaleType>(src.height);

    if (SCALE_X < SCALE_Y) {
        return libtbag::geometry::BaseSize2<T>(src.width * SCALE_X, src.height * SCALE_X);
    } else {
        return libtbag::geometry::BaseSize2<T>(src.width * SCALE_Y, src.height * SCALE_Y);
    }
}

template <typename T>
libtbag::geometry::BaseSize2<T> getSizeOfAspectRatio(T input_width, T input_height, T resize_width)
{
    assert(input_width != 0);
    return libtbag::geometry::BaseSize2<T>(resize_width, (input_height * resize_width) / input_width);
}

template <typename T>
libtbag::geometry::BaseSize2<T> getSizeOfAspectRatio(T input_width, T input_height, T resize_width, T minimum_height)
{
    auto result = getSizeOfAspectRatio<T>(input_width, input_height, resize_width);
    if (minimum_height > 0 && result.height >= minimum_height) {
        assert(input_height != 0);
        result.width = ((input_width * minimum_height) / input_height);
        result.height = minimum_height;
    }
    return result;
}

} // namespace math

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_MATH_ASPECTRATIO_HPP__

<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

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 "json_parser.h"
#include "json.h"
#include "temp_allocator.h"
#include "string_utils.h"
#include "vector.h"
#include "map.h"
#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "quaternion.h"
#include "matrix4x4.h"
#include "file.h"

namespace crown
{

//--------------------------------------------------------------------------
JSONElement::JSONElement()
	: m_at(NULL)
{
}

//--------------------------------------------------------------------------
JSONElement::JSONElement(const char* at)
	: m_at(at)
{
}

//--------------------------------------------------------------------------
JSONElement::JSONElement(const JSONElement& other)
	: m_at(other.m_at)
{
}

//--------------------------------------------------------------------------
JSONElement& JSONElement::operator=(const JSONElement& other)
{
	// Our begin is the other's at
	m_at = other.m_at;
	return *this;
}

//--------------------------------------------------------------------------
JSONElement JSONElement::operator[](uint32_t i)
{
	Array<const char*> array(default_allocator());

	json::parse_array(m_at, array);

	CE_ASSERT(i < array::size(array), "Index out of bounds");

	return JSONElement(array[i]);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::index(uint32_t i)
{
	return this->operator[](i);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::index_or_nil(uint32_t i)
{
	if (m_at != NULL)
	{
		Array<const char*> array(default_allocator());

		json::parse_array(m_at, array);

		if (i >= array::size(array))
		{
			return JSONElement();
		}

		return JSONElement(array[i]);
	}

	return JSONElement();
}

//--------------------------------------------------------------------------
JSONElement JSONElement::key(const char* k)
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	const char* value = map::get(object, DynamicString(k), (const char*) NULL);
	CE_ASSERT(value != NULL, "Key not found: '%s'", k);

	return JSONElement(value);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::key_or_nil(const char* k)
{
	if (m_at != NULL)
	{
		Map<DynamicString, const char*> object(default_allocator());
		json::parse_object(m_at, object);

		const char* value = map::get(object, DynamicString(k), (const char*) NULL);

		if (value)
			return JSONElement(value);
	}

	return JSONElement();
}

//--------------------------------------------------------------------------
bool JSONElement::has_key(const char* k) const
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	return map::has(object, DynamicString(k));
}

//--------------------------------------------------------------------------
bool JSONElement::to_bool() const
{
	return json::parse_bool(m_at);
}

//--------------------------------------------------------------------------
int32_t JSONElement::to_int() const
{
	return json::parse_int(m_at);
}

//--------------------------------------------------------------------------
float JSONElement::to_float() const
{
	return json::parse_float(m_at);
}

//--------------------------------------------------------------------------
void JSONElement::to_string(DynamicString& str) const
{
	json::parse_string(m_at, str);
}

//--------------------------------------------------------------------------
Vector2 JSONElement::to_vector2() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector2(json::parse_float(array[0]),
					json::parse_float(array[1]));
}

//--------------------------------------------------------------------------
Vector3 JSONElement::to_vector3() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector3(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]));
}

//--------------------------------------------------------------------------
Vector4 JSONElement::to_vector4() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector4(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]),
					json::parse_float(array[3]));
}

//--------------------------------------------------------------------------
Quaternion JSONElement::to_quaternion() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Quaternion(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]),
					json::parse_float(array[3]));
}

//--------------------------------------------------------------------------
Matrix4x4 JSONElement::to_matrix4x4() const
{
	TempAllocator128 alloc;
	Array<float> array(alloc);
	to_array(array);

	return Matrix4x4(array::begin(array));
}

//--------------------------------------------------------------------------
StringId32 JSONElement::to_string_id() const
{
	TempAllocator1024 alloc;
	DynamicString str(alloc);
	json::parse_string(m_at, str);
	return str.to_string_id();
}

//--------------------------------------------------------------------------
ResourceId JSONElement::to_resource_id(const char* type) const
{
	CE_ASSERT_NOT_NULL(type);
	TempAllocator1024 alloc;
	DynamicString str(alloc);
	json::parse_string(m_at, str);
	return ResourceId(type, str.c_str());
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<bool>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, json::parse_bool(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<int16_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (int16_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<uint16_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (uint16_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<int32_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (int32_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<uint32_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (uint32_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<float>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, json::parse_float(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Vector<DynamicString>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		DynamicString str;
		json::parse_string(temp[i], str);
		vector::push_back(array, str);
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_keys(Vector<DynamicString>& keys) const
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	const Map<DynamicString, const char*>::Node* it = map::begin(object);
	while (it != map::end(object))
	{
		vector::push_back(keys, (*it).key);
		it++;
	}
}

//--------------------------------------------------------------------------
bool JSONElement::is_nil() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::NIL;
	}

	return true;
}

//--------------------------------------------------------------------------
bool JSONElement::is_bool() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::BOOL;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_number() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::NUMBER;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_string() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::STRING;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_array() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::ARRAY;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_object() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::OBJECT;
	}

	return false;
}

//--------------------------------------------------------------------------
uint32_t JSONElement::size() const
{
	if (m_at == NULL)
	{
		return 0;
	}

	switch(json::type(m_at))
	{
		case JSONType::NIL:
		{
			return 1;
		}
		case JSONType::OBJECT:
		{
			Map<DynamicString, const char*> object(default_allocator());
			json::parse_object(m_at, object);
			return map::size(object);
		}
		case JSONType::ARRAY:
		{
			Array<const char*> array(default_allocator());
			json::parse_array(m_at, array);
			return array::size(array);
		}
		case JSONType::STRING:
		{
			DynamicString string;
			json::parse_string(m_at, string);
			return string.length();
		}
		case JSONType::NUMBER:
		{
			return 1;
		}
		case JSONType::BOOL:
		{
			return 1;
		}
		default:
		{
			CE_FATAL("Oops, unknown value type");
			return 0;
		}
	}
}

//--------------------------------------------------------------------------
JSONParser::JSONParser(const char* s)
	: m_file(false)
	, m_document(s)
{
	CE_ASSERT_NOT_NULL(s);
}

//--------------------------------------------------------------------------
JSONParser::JSONParser(File& f)
	: m_file(true)
	, m_document(NULL)
{
	const size_t size = f.size();
	char* doc = (char*) default_allocator().allocate(size);
	f.read(doc, size);
	m_document = doc;
}

//--------------------------------------------------------------------------
JSONParser::~JSONParser()
{
	if (m_file)
	{
		default_allocator().deallocate((void*) m_document);
	}
}

//--------------------------------------------------------------------------
JSONElement JSONParser::root()
{
	const char* ch = m_document;
	while ((*ch) && (*ch) <= ' ') ch++;

	return JSONElement(ch);
}

} //namespace crown
<commit_msg>Workaround android crash<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

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 "json_parser.h"
#include "json.h"
#include "temp_allocator.h"
#include "string_utils.h"
#include "vector.h"
#include "map.h"
#include "vector2.h"
#include "vector3.h"
#include "vector4.h"
#include "quaternion.h"
#include "matrix4x4.h"
#include "file.h"

namespace crown
{

//--------------------------------------------------------------------------
JSONElement::JSONElement()
	: m_at(NULL)
{
}

//--------------------------------------------------------------------------
JSONElement::JSONElement(const char* at)
	: m_at(at)
{
}

//--------------------------------------------------------------------------
JSONElement::JSONElement(const JSONElement& other)
	: m_at(other.m_at)
{
}

//--------------------------------------------------------------------------
JSONElement& JSONElement::operator=(const JSONElement& other)
{
	// Our begin is the other's at
	m_at = other.m_at;
	return *this;
}

//--------------------------------------------------------------------------
JSONElement JSONElement::operator[](uint32_t i)
{
	Array<const char*> array(default_allocator());

	json::parse_array(m_at, array);

	CE_ASSERT(i < array::size(array), "Index out of bounds");

	return JSONElement(array[i]);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::index(uint32_t i)
{
	return this->operator[](i);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::index_or_nil(uint32_t i)
{
	if (m_at != NULL)
	{
		Array<const char*> array(default_allocator());

		json::parse_array(m_at, array);

		if (i >= array::size(array))
		{
			return JSONElement();
		}

		return JSONElement(array[i]);
	}

	return JSONElement();
}

//--------------------------------------------------------------------------
JSONElement JSONElement::key(const char* k)
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	const char* value = map::get(object, DynamicString(k), (const char*) NULL);
	CE_ASSERT(value != NULL, "Key not found: '%s'", k);

	return JSONElement(value);
}

//--------------------------------------------------------------------------
JSONElement JSONElement::key_or_nil(const char* k)
{
	if (m_at != NULL)
	{
		Map<DynamicString, const char*> object(default_allocator());
		json::parse_object(m_at, object);

		const char* value = map::get(object, DynamicString(k), (const char*) NULL);

		if (value)
			return JSONElement(value);
	}

	return JSONElement();
}

//--------------------------------------------------------------------------
bool JSONElement::has_key(const char* k) const
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	return map::has(object, DynamicString(k));
}

//--------------------------------------------------------------------------
bool JSONElement::to_bool() const
{
	return json::parse_bool(m_at);
}

//--------------------------------------------------------------------------
int32_t JSONElement::to_int() const
{
	return json::parse_int(m_at);
}

//--------------------------------------------------------------------------
float JSONElement::to_float() const
{
	return json::parse_float(m_at);
}

//--------------------------------------------------------------------------
void JSONElement::to_string(DynamicString& str) const
{
	json::parse_string(m_at, str);
}

//--------------------------------------------------------------------------
Vector2 JSONElement::to_vector2() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector2(json::parse_float(array[0]),
					json::parse_float(array[1]));
}

//--------------------------------------------------------------------------
Vector3 JSONElement::to_vector3() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector3(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]));
}

//--------------------------------------------------------------------------
Vector4 JSONElement::to_vector4() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Vector4(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]),
					json::parse_float(array[3]));
}

//--------------------------------------------------------------------------
Quaternion JSONElement::to_quaternion() const
{
	TempAllocator64 alloc;
	Array<const char*> array(alloc);
	json::parse_array(m_at, array);

	return Quaternion(json::parse_float(array[0]),
					json::parse_float(array[1]),
					json::parse_float(array[2]),
					json::parse_float(array[3]));
}

//--------------------------------------------------------------------------
Matrix4x4 JSONElement::to_matrix4x4() const
{
	TempAllocator128 alloc;
	Array<float> array(alloc);
	to_array(array);

	return Matrix4x4(array::begin(array));
}

//--------------------------------------------------------------------------
StringId32 JSONElement::to_string_id() const
{
	TempAllocator1024 alloc;
	DynamicString str(alloc);
	json::parse_string(m_at, str);
	return str.to_string_id();
}

//--------------------------------------------------------------------------
ResourceId JSONElement::to_resource_id(const char* type) const
{
	CE_ASSERT_NOT_NULL(type);
	// TempAllocator1024 alloc;
	DynamicString str(default_allocator());
	json::parse_string(m_at, str);
	return ResourceId(type, str.c_str());
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<bool>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, json::parse_bool(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<int16_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (int16_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<uint16_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (uint16_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<int32_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (int32_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<uint32_t>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, (uint32_t)json::parse_int(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Array<float>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		array::push_back(array, json::parse_float(temp[i]));
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_array(Vector<DynamicString>& array) const
{
	Array<const char*> temp(default_allocator());

	json::parse_array(m_at, temp);

	for (uint32_t i = 0; i < array::size(temp); i++)
	{
		DynamicString str;
		json::parse_string(temp[i], str);
		vector::push_back(array, str);
	}
}

//--------------------------------------------------------------------------
void JSONElement::to_keys(Vector<DynamicString>& keys) const
{
	Map<DynamicString, const char*> object(default_allocator());
	json::parse_object(m_at, object);

	const Map<DynamicString, const char*>::Node* it = map::begin(object);
	while (it != map::end(object))
	{
		vector::push_back(keys, (*it).key);
		it++;
	}
}

//--------------------------------------------------------------------------
bool JSONElement::is_nil() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::NIL;
	}

	return true;
}

//--------------------------------------------------------------------------
bool JSONElement::is_bool() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::BOOL;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_number() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::NUMBER;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_string() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::STRING;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_array() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::ARRAY;
	}

	return false;
}

//--------------------------------------------------------------------------
bool JSONElement::is_object() const
{
	if (m_at != NULL)
	{
		return json::type(m_at) == JSONType::OBJECT;
	}

	return false;
}

//--------------------------------------------------------------------------
uint32_t JSONElement::size() const
{
	if (m_at == NULL)
	{
		return 0;
	}

	switch(json::type(m_at))
	{
		case JSONType::NIL:
		{
			return 1;
		}
		case JSONType::OBJECT:
		{
			Map<DynamicString, const char*> object(default_allocator());
			json::parse_object(m_at, object);
			return map::size(object);
		}
		case JSONType::ARRAY:
		{
			Array<const char*> array(default_allocator());
			json::parse_array(m_at, array);
			return array::size(array);
		}
		case JSONType::STRING:
		{
			DynamicString string;
			json::parse_string(m_at, string);
			return string.length();
		}
		case JSONType::NUMBER:
		{
			return 1;
		}
		case JSONType::BOOL:
		{
			return 1;
		}
		default:
		{
			CE_FATAL("Oops, unknown value type");
			return 0;
		}
	}
}

//--------------------------------------------------------------------------
JSONParser::JSONParser(const char* s)
	: m_file(false)
	, m_document(s)
{
	CE_ASSERT_NOT_NULL(s);
}

//--------------------------------------------------------------------------
JSONParser::JSONParser(File& f)
	: m_file(true)
	, m_document(NULL)
{
	const size_t size = f.size();
	char* doc = (char*) default_allocator().allocate(size);
	f.read(doc, size);
	m_document = doc;
}

//--------------------------------------------------------------------------
JSONParser::~JSONParser()
{
	if (m_file)
	{
		default_allocator().deallocate((void*) m_document);
	}
}

//--------------------------------------------------------------------------
JSONElement JSONParser::root()
{
	const char* ch = m_document;
	while ((*ch) && (*ch) <= ' ') ch++;

	return JSONElement(ch);
}

} //namespace crown
<|endoftext|>


<commit_before>
#include <mutex>
#include <cassert>
#include <cstring>
#include <sys/stat.h>

#include <list>
#include <unistd.h>

#include "global.h"

#include "partition_db.h"

std::string GetPartitionDBFilename(partition_t p)
{
	return g_db_files_dirname + "/" + std::to_string(p) + ".db";
}

static int createTableCallback(void *NotUsed, int argc, char **argv, char **azColName){
	printf("Callback called: create table\n");
	int i;
	char const * value;
	for(i=0; i<argc; i++) {
		if (argv[i]) {
			value = argv[i];
		} else {
			value = "NULL";
		}
		printf("%s = %s\n", azColName[i], value);
	}
	printf("\n");
	return 0;
}

PartitionDB::PartitionDB(const std::string &dbName)
{
	filename = dbName;
	fprintf(stderr, "Open database: %s\n", filename.c_str());
	if (sqlite3_open(filename.c_str(), &db))
	{
		fprintf(stderr, "%s\n", sqlite3_errmsg(db));
		perror("Can't open database!");
		exit(1);
	}
	fprintf(stderr, "Opened database successfully\n");

	char *sql = "CREATE TABLE IF NOT EXISTS stored_values( " \
		"row_id INT PRIMARY KEY," \
		"device_id 	INT NOT NULL," \
		"timestamp 	INT	NOT NULL," \
		"expiration INT NOT NULL," \
		"data	BLOB	NOT NULL );";

	char *errMsg = NULL;
	if(sqlite3_exec(db, sql, createTableCallback, 0, &errMsg) != SQLITE_OK)
	{
		fprintf(stderr, "SQL error: %s\n", errMsg);
		sqlite3_free(errMsg);
		perror("Table not found and can't create it!");
		exit(1);
	}
}

PartitionDB::~PartitionDB()
{
	sqlite3_close(db);
}

static bool compareBuffer(char *buf1, char *buf2, size_t len)
{
	for (int i = 0; i < len; i++)
	{
		if (buf1[i] != buf2[i]) return false;
	}
	return true;
}

bool PartitionDB::put(device_t device_id, time_t timestamp, time_t expiration, void *data, size_t datalen)
{
	assert(datalen < kMaxDataLen);

	int result;
	sqlite3_stmt *stmt;
	char sql[256];
	int sql_len;

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "SELECT * FROM stored_values WHERE (device_id = %d AND timestamp = %ld);", device_id, timestamp);
	stmt = NULL;
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		return false;
	}

	/*
	 * TODO : Duplicate handling not fully implemented
	 */
	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			time_t row_expiration = sqlite3_column_int(stmt, 3);
			size_t row_data_size = sqlite3_column_bytes(stmt, 4);
			if (row_data_size != datalen)
			{
				sqlite3_finalize(stmt);
				return false;
			}
			void const *row_data = sqlite3_column_blob(stmt, 4);
			assert(row_data);
			if (!compareBuffer)
			{
				sqlite3_finalize(stmt);
				return false;
			}
			sqlite3_finalize(stmt);
			return true;
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			return false;
		}
	}
	sqlite3_finalize(stmt);

	stmt = NULL;
	sql_len = sprintf(sql, "INSERT INTO stored_values VALUES(NULL, %d, %ld, %ld, ?);", device_id, timestamp, expiration);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		return false;
	}

	result = sqlite3_bind_blob(stmt, 1, data, datalen, SQLITE_STATIC);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return false;
	}

	result = sqlite3_step(stmt);
	bool success = (result == SQLITE_DONE);

	sqlite3_finalize(stmt);
	return success;
}

std::list<Data> * PartitionDB::get(device_t device_id, time_t min_timestamp, time_t max_timestamp)
{
	char sql[256];
	int sql_len;
	int result;
	sqlite3_stmt *stmt;

	std::list<Data> *ret = new std::list<Data>();

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "SELECT * FROM stored_values " \
		"WHERE (device_id = %d AND timestamp BETWEEN %ld AND %ld) " \
		"ORDER BY timestamp ASC;", device_id, min_timestamp, max_timestamp);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return nullptr; // TODO Throw exception or return empty list?
	}

	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			time_t timestamp = sqlite3_column_int(stmt, 2);
			time_t expiration = sqlite3_column_int(stmt, 3);
			size_t data_size = sqlite3_column_bytes(stmt, 4);
			assert(data_size < kMaxDataLen);
			void const *data = sqlite3_column_blob(stmt, 4);

			Data d;
			d.timestamp = timestamp;
			d.expiration = expiration;
			d.datalen = data_size;
			memcpy(&d.data, data, data_size);

			ret->push_back(d);
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			throw "sqlite db error";
		}
	}
	sqlite3_finalize(stmt);

	return ret;
}

bool PartitionDB::remove(time_t timestamp)
{
	char sql[256];
	int sql_len;
	int result;
	sqlite3_stmt *stmt;

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "DELETE FROM stored_values WHERE (timestamp < %ld);", timestamp);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return false;
	}

	result = sqlite3_step(stmt);
	bool success = (result == SQLITE_DONE);

	sqlite3_finalize(stmt);
	return success;
}

std::list<device_t> * PartitionDB::getDevices(void)
{
	int result;
	sqlite3_stmt *stmt;
	std::list<device_t> *ret = new std::list<device_t>;

	std::lock_guard<std::mutex> lg(db_lock);

	result = sqlite3_prepare_v2(db, "SELECT DISTINCT device_id FROM stored_values;", -1, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return nullptr; // TODO Empty list or throw exception?
	}

	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			device_t d = sqlite3_column_int(stmt, 0);
			ret->push_back(d);
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			throw "sqlite db error";
		}
	}
	sqlite3_finalize(stmt);

	return ret;
}

long long PartitionDB::size(void)
{
	struct stat sb;
	if (lstat(filename.c_str(), &sb) != 0)
	{
		fprintf(stderr, "failed to stat file %s\n", filename.c_str());
		throw "can't stat db file";
	}
	return sb.st_size;
}

<commit_msg>initialization works, changed db file extension to .sqllite<commit_after>
#include <mutex>
#include <cassert>
#include <cstring>
#include <sys/stat.h>

#include <list>
#include <unistd.h>

#include "global.h"

#include "partition_db.h"

std::string GetPartitionDBFilename(partition_t p)
{
	return g_db_files_dirname + "/" + std::to_string(p) + ".sqllite";
}

static int createTableCallback(void *NotUsed, int argc, char **argv, char **azColName){
	printf("Callback called: create table\n");
	int i;
	char const * value;
	for(i=0; i<argc; i++) {
		if (argv[i]) {
			value = argv[i];
		} else {
			value = "NULL";
		}
		printf("%s = %s\n", azColName[i], value);
	}
	printf("\n");
	return 0;
}

PartitionDB::PartitionDB(const std::string &dbName)
{
	filename = dbName;
	fprintf(stderr, "Open database: %s\n", filename.c_str());
	if (sqlite3_open(filename.c_str(), &db) != SQLITE_OK)
	{
		fprintf(stderr, "%s\n", sqlite3_errmsg(db));
		perror("Can't open database!");
		exit(1);
	}
	fprintf(stderr, "Opened database successfully\n");

	char *sql = "CREATE TABLE IF NOT EXISTS stored_values( " \
		"row_id INT PRIMARY KEY," \
		"device_id 	INT NOT NULL," \
		"timestamp 	INT	NOT NULL," \
		"expiration INT NOT NULL," \
		"data	BLOB	NOT NULL );";

	char *errMsg = NULL;
	if(sqlite3_exec(db, sql, createTableCallback, 0, &errMsg) != SQLITE_OK)
	{
		fprintf(stderr, "SQL error: %s\n", errMsg);
		sqlite3_free(errMsg);
		perror("Table not found and can't create it!");
		exit(1);
	}
}

PartitionDB::~PartitionDB()
{
	sqlite3_close(db);
}

static bool compareBuffer(char *buf1, char *buf2, size_t len)
{
	for (int i = 0; i < len; i++)
	{
		if (buf1[i] != buf2[i]) return false;
	}
	return true;
}

bool PartitionDB::put(device_t device_id, time_t timestamp, time_t expiration, void *data, size_t datalen)
{
	assert(datalen < kMaxDataLen);

	int result;
	sqlite3_stmt *stmt;
	char sql[256];
	int sql_len;

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "SELECT * FROM stored_values WHERE (device_id = %d AND timestamp = %ld);", device_id, timestamp);
	stmt = NULL;
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		return false;
	}

	/*
	 * TODO : Duplicate handling not fully implemented
	 */
	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			time_t row_expiration = sqlite3_column_int(stmt, 3);
			size_t row_data_size = sqlite3_column_bytes(stmt, 4);
			if (row_data_size != datalen)
			{
				sqlite3_finalize(stmt);
				return false;
			}
			void const *row_data = sqlite3_column_blob(stmt, 4);
			assert(row_data);
			if (!compareBuffer)
			{
				sqlite3_finalize(stmt);
				return false;
			}
			sqlite3_finalize(stmt);
			return true;
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			return false;
		}
	}
	sqlite3_finalize(stmt);

	stmt = NULL;
	sql_len = sprintf(sql, "INSERT INTO stored_values VALUES(NULL, %d, %ld, %ld, ?);", device_id, timestamp, expiration);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		return false;
	}

	result = sqlite3_bind_blob(stmt, 1, data, datalen, SQLITE_STATIC);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return false;
	}

	result = sqlite3_step(stmt);
	bool success = (result == SQLITE_DONE);

	sqlite3_finalize(stmt);
	return success;
}

std::list<Data> * PartitionDB::get(device_t device_id, time_t min_timestamp, time_t max_timestamp)
{
	char sql[256];
	int sql_len;
	int result;
	sqlite3_stmt *stmt;

	std::list<Data> *ret = new std::list<Data>();

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "SELECT * FROM stored_values " \
		"WHERE (device_id = %d AND timestamp BETWEEN %ld AND %ld) " \
		"ORDER BY timestamp ASC;", device_id, min_timestamp, max_timestamp);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return nullptr; // TODO Throw exception or return empty list?
	}

	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			time_t timestamp = sqlite3_column_int(stmt, 2);
			time_t expiration = sqlite3_column_int(stmt, 3);
			size_t data_size = sqlite3_column_bytes(stmt, 4);
			assert(data_size < kMaxDataLen);
			void const *data = sqlite3_column_blob(stmt, 4);

			Data d;
			d.timestamp = timestamp;
			d.expiration = expiration;
			d.datalen = data_size;
			memcpy(&d.data, data, data_size);

			ret->push_back(d);
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			throw "sqlite db error";
		}
	}
	sqlite3_finalize(stmt);

	return ret;
}

bool PartitionDB::remove(time_t timestamp)
{
	char sql[256];
	int sql_len;
	int result;
	sqlite3_stmt *stmt;

	std::lock_guard<std::mutex> lg(db_lock);

	sql_len = sprintf(sql, "DELETE FROM stored_values WHERE (timestamp < %ld);", timestamp);
	result = sqlite3_prepare_v2(db, sql, sql_len, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return false;
	}

	result = sqlite3_step(stmt);
	bool success = (result == SQLITE_DONE);

	sqlite3_finalize(stmt);
	return success;
}

std::list<device_t> * PartitionDB::getDevices(void)
{
	int result;
	sqlite3_stmt *stmt;
	std::list<device_t> *ret = new std::list<device_t>;

	std::lock_guard<std::mutex> lg(db_lock);

	result = sqlite3_prepare_v2(db, "SELECT DISTINCT device_id FROM stored_values;", -1, &stmt, NULL);
	if (result != SQLITE_OK)
	{
		sqlite3_finalize(stmt);
		return nullptr; // TODO Empty list or throw exception?
	}

	while (true)
	{
		result = sqlite3_step(stmt);
		if (result == SQLITE_DONE)
		{
			break;
		}
		else if (result == SQLITE_ROW)
		{
			device_t d = sqlite3_column_int(stmt, 0);
			ret->push_back(d);
		}
		else if (result == SQLITE_BUSY)
		{
			usleep(1000);
		}
		else
		{
			sqlite3_finalize(stmt);
			throw "sqlite db error";
		}
	}
	sqlite3_finalize(stmt);

	return ret;
}

long long PartitionDB::size(void)
{
	struct stat sb;
	if (lstat(filename.c_str(), &sb) != 0)
	{
		fprintf(stderr, "failed to stat file %s\n", filename.c_str());
		throw "can't stat db file";
	}
	return sb.st_size;
}

<|endoftext|>