<commit_before>#include <sequence/Tools.hpp>

#include <cassert>

#include <algorithm>

#include <sequence/details/StringUtils.hpp>

namespace sequence {

namespace {

bool containsPatternCharacter(CStringView str) { return str.contains('#'); }

void replaceAll(std::string &subject, const std::string &search,
                const std::string &replace) {
  size_t pos = 0;
  while ((pos = subject.find(search, pos)) != std::string::npos) {
    subject.replace(pos, search.length(), replace);
    pos += replace.length();
  }
}

} // namespace

std::string createPattern(CStringView prefix, CStringView suffix,
                          unsigned char padding) {
  if (padding > MAX_PADDING) {
    throw std::domain_error("padding should be <= MAX_PADDING");
  }
  if (padding == 0) {
    padding = 1;
  }
  std::array<char, MAX_PADDING> buffer;
  std::fill(buffer.begin(), buffer.end(), PADDING_CHAR);
  return concat(prefix, CStringView(buffer.cbegin(), padding), suffix);
}

std::pair<CStringView, CStringView> getPrefixAndSuffix(CStringView pattern) {
  const auto first = pattern.indexOf(PADDING_CHAR);
  if (first == CStringView::npos) {
    throw std::invalid_argument("no padding character found in pattern");
  }
  const auto last = pattern.lastIndexOf(PADDING_CHAR);
  assert(last != CStringView::npos);
  const CStringView padding = pattern.substr(first, last - first + 1);
  if (std::any_of(padding.begin(), padding.end(),
                  [](char c) { return c != PADDING_CHAR; })) {
    throw std::invalid_argument("multiple padding found in pattern");
  }
  if (padding.size() > MAX_PADDING) {
    throw std::invalid_argument("padding too large found in pattern");
  }
  return {pattern.substr(0, first), pattern.substr(last + 1)};
}

unsigned getPadding(CStringView pattern) {
  const auto pair = getPrefixAndSuffix(pattern);
  return pattern.size() - pair.first.size() - pair.second.size();
}

Item createSingleFile(CStringView filename) {
  if (containsPatternCharacter(filename))
    return {};
  return Item{filename.toString()};
}

Item createSequence(CStringView pattern, Index start, Index end,
                    unsigned char step) {
  if (step == 0)
    return {};
  if (end < start)
    return {};
  Item item(pattern);
  item.padding = getPadding(pattern);
  item.step = step;
  item.start = start;
  item.end = end;
  return item;
}

Item createSequence(CStringView pattern, Indices indices) {
  return Item(pattern, std::move(indices));
}

std::regex getMatcher(CStringView pattern, bool ignoreCase) {
  auto flags = std::regex_constants::ECMAScript;
  if (ignoreCase)
    flags |= std::regex_constants::icase;
  return std::regex(details::getMatcherString(pattern.toString()), flags);
}

bool match(const std::regex &matcher, const Item &candidate) {
  return std::regex_match(candidate.filename, matcher);
}

namespace details {
std::string getMatcherString(std::string pattern) {
  if (pattern.empty())
    throw std::invalid_argument("empty pattern");
  // replacing @ by #
  std::replace(pattern.begin(), pattern.end(), '@', '#');
  const auto padding = std::count(pattern.begin(), pattern.end(), '#');
  if (padding == 0)
    throw std::invalid_argument(
        "pattern should contain a padding character '#' or '@'");
  replaceAll(pattern, ".", "\\.");
  replaceAll(pattern, "*", ".*");
  if (padding == 1)
    replaceAll(pattern, "#", "#+");
  return pattern;
}

} // namespace details
} // namespace sequence
<commit_msg>Allow creating single file containing padding char<commit_after>#include <sequence/Tools.hpp>

#include <cassert>

#include <algorithm>

#include <sequence/details/StringUtils.hpp>

namespace sequence {

namespace {

void replaceAll(std::string &subject, const std::string &search,
                const std::string &replace) {
  size_t pos = 0;
  while ((pos = subject.find(search, pos)) != std::string::npos) {
    subject.replace(pos, search.length(), replace);
    pos += replace.length();
  }
}

} // namespace

std::string createPattern(CStringView prefix, CStringView suffix,
                          unsigned char padding) {
  if (padding > MAX_PADDING) {
    throw std::domain_error("padding should be <= MAX_PADDING");
  }
  if (padding == 0) {
    padding = 1;
  }
  std::array<char, MAX_PADDING> buffer;
  std::fill(buffer.begin(), buffer.end(), PADDING_CHAR);
  return concat(prefix, CStringView(buffer.cbegin(), padding), suffix);
}

std::pair<CStringView, CStringView> getPrefixAndSuffix(CStringView pattern) {
  const auto first = pattern.indexOf(PADDING_CHAR);
  if (first == CStringView::npos) {
    throw std::invalid_argument("no padding character found in pattern");
  }
  const auto last = pattern.lastIndexOf(PADDING_CHAR);
  assert(last != CStringView::npos);
  const CStringView padding = pattern.substr(first, last - first + 1);
  if (std::any_of(padding.begin(), padding.end(),
                  [](char c) { return c != PADDING_CHAR; })) {
    throw std::invalid_argument("multiple padding found in pattern");
  }
  if (padding.size() > MAX_PADDING) {
    throw std::invalid_argument("padding too large found in pattern");
  }
  return {pattern.substr(0, first), pattern.substr(last + 1)};
}

unsigned getPadding(CStringView pattern) {
  const auto pair = getPrefixAndSuffix(pattern);
  return pattern.size() - pair.first.size() - pair.second.size();
}

Item createSingleFile(CStringView filename) {
  return Item{filename.toString()};
}

Item createSequence(CStringView pattern, Index start, Index end,
                    unsigned char step) {
  if (step == 0)
    return {};
  if (end < start)
    return {};
  Item item(pattern);
  item.padding = getPadding(pattern);
  item.step = step;
  item.start = start;
  item.end = end;
  return item;
}

Item createSequence(CStringView pattern, Indices indices) {
  return Item(pattern, std::move(indices));
}

std::regex getMatcher(CStringView pattern, bool ignoreCase) {
  auto flags = std::regex_constants::ECMAScript;
  if (ignoreCase)
    flags |= std::regex_constants::icase;
  return std::regex(details::getMatcherString(pattern.toString()), flags);
}

bool match(const std::regex &matcher, const Item &candidate) {
  return std::regex_match(candidate.filename, matcher);
}

namespace details {
std::string getMatcherString(std::string pattern) {
  if (pattern.empty())
    throw std::invalid_argument("empty pattern");
  // replacing @ by #
  std::replace(pattern.begin(), pattern.end(), '@', '#');
  const auto padding = std::count(pattern.begin(), pattern.end(), '#');
  if (padding == 0)
    throw std::invalid_argument(
        "pattern should contain a padding character '#' or '@'");
  replaceAll(pattern, ".", "\\.");
  replaceAll(pattern, "*", ".*");
  if (padding == 1)
    replaceAll(pattern, "#", "#+");
  return pattern;
}

} // namespace details
} // namespace sequence
<|endoftext|>


<commit_before>#include <fstream>

#include "Utils.h"

#if defined(__APPLE__)
#	include <sys/select.h>
#	include <sys/time.h>
#	include <sys/types.h>
#	include <sys/select.h>
#	include <unistd.h>
#	include <termios.h>
#else
#	include <conio.h>
#endif

std::vector<uint8_t> ReadFileAsVector( const char* FileName )
{
	std::ifstream File( FileName, std::ifstream::binary );

	File.seekg( 0, std::ios::end );
	std::streampos End = File.tellg();
	File.seekg( 0, std::ios::beg );
	std::streampos Start = File.tellg();
	size_t Size = static_cast<size_t>( End - Start );

	std::vector<uint8_t> Result( Size );

	File.read( reinterpret_cast<char*>( Result.data() ), Size );

	return Result;
}

std::shared_ptr<clBlob> ReadFileAsBlob( const char* FileName )
{
	return std::make_shared<clBlob>( ReadFileAsVector( FileName ) );
}

int IsKeyPressed()
{
#if defined(_WIN32)
	return _kbhit();
#elif defined(__APPLE__)
	struct termios ttystate;
 	tcgetattr( STDIN_FILENO, &ttystate );
	ttystate.c_lflag &= ~ICANON;
	ttystate.c_cc[VMIN] = 1;
	tcsetattr( STDIN_FILENO, TCSANOW, &ttystate );

	fd_set fds;
	FD_ZERO( &fds );
	FD_SET( STDIN_FILENO, &fds );
	struct timeval tv = { 0L, 0L };
	(void)select( STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv );
	bool HasKey = FD_ISSET( STDIN_FILENO, &fds );
	return HasKey ? fgetc( stdin ) : 0;
#else
	return kbhit();
#endif
}
<commit_msg>IsKeyPressed() eats keys<commit_after>#include <fstream>

#include "Utils.h"

#if defined(__APPLE__)
#	include <sys/select.h>
#	include <sys/time.h>
#	include <sys/types.h>
#	include <sys/select.h>
#	include <unistd.h>
#	include <termios.h>
#else
#	include <conio.h>
#endif

std::vector<uint8_t> ReadFileAsVector( const char* FileName )
{
	std::ifstream File( FileName, std::ifstream::binary );

	File.seekg( 0, std::ios::end );
	std::streampos End = File.tellg();
	File.seekg( 0, std::ios::beg );
	std::streampos Start = File.tellg();
	size_t Size = static_cast<size_t>( End - Start );

	std::vector<uint8_t> Result( Size );

	File.read( reinterpret_cast<char*>( Result.data() ), Size );

	return Result;
}

std::shared_ptr<clBlob> ReadFileAsBlob( const char* FileName )
{
	return std::make_shared<clBlob>( ReadFileAsVector( FileName ) );
}

int IsKeyPressed()
{
#if defined(_WIN32)
	bool Res = _kbhit();
	while (_kbhit()) getch();
	return Res;
#elif defined(__APPLE__)
	struct termios ttystate;
 	tcgetattr( STDIN_FILENO, &ttystate );
	ttystate.c_lflag &= ~ICANON;
	ttystate.c_cc[VMIN] = 1;
	tcsetattr( STDIN_FILENO, TCSANOW, &ttystate );

	fd_set fds;
	FD_ZERO( &fds );
	FD_SET( STDIN_FILENO, &fds );
	struct timeval tv = { 0L, 0L };
	(void)select( STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv );
	bool HasKey = FD_ISSET( STDIN_FILENO, &fds );
	return HasKey ? fgetc( stdin ) : 0;
#else
	bool Res = kbhit();
	while (kbhit()) getch();
	return Res;
#endif
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2009, Mozilla Foundation

   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 Mozilla Foundation 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 ORGANISATION 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.
*/

/*
 * Utils.cpp - Generic program utility functions.
 *
 * Contributor(s):
 *   Chris Pearce <chris@pearce.org.nz>
 */

#include <ogg/ogg.h>
#include <fstream>
#include <iostream>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include "Utils.hpp"

ogg_page*
Clone(ogg_page* p)
{
  ogg_page* q = new ogg_page();
  memcpy(q, p, sizeof(ogg_page));
  q->header = new unsigned char[p->header_len + p->body_len];
  q->body = q->header + q->header_len;
  memcpy(q->header, p->header, p->header_len);
  memcpy(q->body, p->body, p->body_len);
  assert(memcmp(p->header, q->header, q->header_len) == 0);
  assert(memcmp(p->body, q->body, q->body_len) == 0);
  assert(q->header_len == p->header_len);
  assert(q->body_len == p->body_len);
  return q;
}

void
FreeClone(ogg_page* p)
{
  delete[] p->header;
  delete p;
}

void
WritePage(ofstream& output, const ogg_page& page) {
  output.write((const char*)page.header, page.header_len);
  output.write((const char*)page.body, page.body_len);
}

// Get the length in bytes of a file. 32bit only, won't work for files larger
// than 2GB.
ogg_int64_t
FileLength(const char* aFileName)
{
  ifstream is;
  is.open (aFileName, ios::binary);
  is.seekg (0, ios::end);
  streampos length = is.tellg();
  is.close();
  return (ogg_int64_t)length;
}

ogg_packet*
Clone(ogg_packet* p)
{
  if (!p)
    return 0;
  ogg_packet* q = new ogg_packet();
  memcpy(q, p, sizeof(ogg_packet));
  q->packet = new unsigned char[p->bytes];
  memcpy(q->packet, p->packet, p->bytes);
  return q;
}

bool
IsIndexPacket(ogg_packet* packet)
{
  return packet &&
         packet->bytes >= (long)(HEADER_MAGIC_LEN + 8) &&
         memcmp(packet->packet, HEADER_MAGIC, HEADER_MAGIC_LEN) == 0;
}

#define FILE_BUFFER_SIZE (1024 * 1024)

// Returns nuber of bytes read.
bool ReadPage(ogg_sync_state* state,
              ogg_page* page,
              istream& stream,
              ogg_uint64_t& bytesRead)
{
  ogg_int32_t bytes = 0;
  ogg_int32_t r = 0;
  ogg_uint64_t intialBytesRead = bytesRead;
  while ((r = ogg_sync_pageout(state, page)) != 1) {
    char* buffer = ogg_sync_buffer(state, FILE_BUFFER_SIZE);
    assert(buffer);
    stream.read(buffer, FILE_BUFFER_SIZE);
    bytes = stream.gcount();
    bytesRead += bytes;
    if (bytes == 0) {
      // End of file
      assert(stream.eof());
      if (intialBytesRead != bytesRead) {
        cerr << "WARNING: Reached end of file, when expecting to find more data! "
             << "Page header may be incorrect!" << endl;
      }
      return false;
    }
    ogg_int32_t ret = ogg_sync_wrote(state, bytes);
    assert(ret == 0);
  }
  return true;
}

// Returns nuber of bytes skipped to next page, or -1 on failure.
int PageSeek(ogg_sync_state* state,
             ogg_page* page,
             istream& stream,
             ogg_uint64_t& bytesRead)
{
  int retval = 0;
  ogg_int32_t bytes = 0;
  ogg_int32_t r = 0;
  ogg_uint64_t intialBytesRead = bytesRead;
  while ((r = ogg_sync_pageseek(state, page)) <= 0) {
    if (r == 0) {
      // Need to read more data to get to next page.
      char* buffer = ogg_sync_buffer(state, FILE_BUFFER_SIZE);
      assert(buffer);

      stream.read(buffer, FILE_BUFFER_SIZE);
      bytes = stream.gcount();
      bytesRead += bytes;
      if (bytes == 0) {
        // End of file
        assert(stream.eof());
        if (intialBytesRead != bytesRead) {
          cerr << "WARNING: Reached end of file, when expecting to find more data! "
               << "Page header may be incorrect!" << endl;
        }
        return false;
      }

      ogg_int32_t ret = ogg_sync_wrote(state, bytes);
      assert(ret == 0);
    } else {
      assert(r<0);
      // We skipped -r bytes reading up to next ogg page capture.
      retval += (-r);
    }
  }
  if (r == -1) {
    cout << "ERROR: sync failure in ReadPage()" << endl;
    return -1;
  }
  return retval;
}

bool
IsPageAtOffset(const string& filename, ogg_int64_t offset, ogg_page* page)
{
  ifstream file(filename.c_str(), ios::in | ios::binary);
  assert(file);
  file.seekg((ogg_int32_t)offset, ios_base::beg);
  char* buf = new char[max(page->body_len, page->header_len)];
  file.read(buf, page->header_len);
  assert(file.gcount() == page->header_len);
  if (memcmp(buf, page->header, page->header_len) != 0) {
    cerr << "Incorrect page offset calculation for page at offset "
         << offset << endl;
    delete[] buf;
    return false;
  }

  file.read(buf, page->body_len);
  assert(file.gcount() == page->body_len);
  if (memcmp(buf, page->body, page->body_len) != 0) {
    cerr << "Incorrect page offset calculation for page at offset "
         << offset << endl;
    delete[] buf;
    return false;
  }

  delete[] buf;
  return true;
}

void
CopyFileData(istream& input, ostream& output, ogg_int64_t bytesToCopy)
{
  assert(input.good());
  assert(output.good());
  // Copy data in chunks at most 1mb in size.
  assert(bytesToCopy >= 0);
  assert((ogg_int64_t)FILE_BUFFER_SIZE < (ogg_int64_t)INT_MAX);
  ogg_int32_t len = (ogg_int32_t)min(bytesToCopy, (ogg_int64_t)FILE_BUFFER_SIZE);
  char* buf = new char[len];
  ogg_int64_t bytesCopied = 0;
  while (bytesCopied != bytesToCopy) {
    ogg_int64_t remaining = bytesToCopy - bytesCopied;
    ogg_int32_t x = (ogg_int32_t)min(remaining, (ogg_int64_t)len);
    input.read(buf, x);
    assert(x == input.gcount());
    output.write(buf, x);
    bytesCopied += x;
  }
  delete[] buf;
}

ogg_uint32_t
GetChecksum(ogg_page* page)
{
  assert(page != 0);
  assert(page->header != 0);
  assert(page->header_len > 25);
  return LEUint32(page->header + 22);
}

bool
IsFisheadPacket(ogg_packet* packet)
{
  return packet &&
         packet->bytes > 8 &&
         memcmp(packet->packet, "fishead", 8) == 0;
}

bool
IsFisbonePacket(ogg_packet* packet)
{
  return packet->packet &&
         packet->bytes >= 52 &&
         memcmp(packet->packet, "fisbone", 8) == 0;
}

// Theora version
int TheoraVersion(th_info* info,
                  unsigned char maj,
                  unsigned char min,
                  unsigned char sub)
{
  ogg_uint32_t ver = (maj << 16) + (min << 8) + sub;
  ogg_uint32_t th_ver = (info->version_major << 16) +
                        (info->version_minor << 8) +
                        info->version_subminor;
  return (th_ver >= ver) ? 1 : 0;
}

// Returns the number of packets that start on a page.
int
CountPacketStarts(ogg_page* page)
{
  int i;
  // If we're not continuing a packet, we're at a packet start.
  int packets_start = (ogg_page_continued(page) == 0) ? 1 : 0;
  int num_lacing_vals = page->header[26];
  unsigned char* lacing_vals = &page->header[27];
  for (i=1; i<num_lacing_vals; i++) {
    if (lacing_vals[i-1] < 0xff) {
      packets_start++;
    }
  }
  return packets_start;
}

unsigned char*
WriteLEUint64(unsigned char* p, const ogg_uint64_t num)
{
  ogg_int32_t i;
  ogg_uint64_t n = num;
  assert(p);
  for (i=0; i<8; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEUint64(p) == num);
  return p + 8;
}

unsigned char*
WriteLEInt64(unsigned char* p, const ogg_int64_t num)
{
  ogg_int64_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<8; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEInt64(p) == num);
  return p + 8;
}

unsigned char*
WriteLEUint32(unsigned char* p, const ogg_uint32_t num)
{
  ogg_uint32_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<4; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEUint32(p) == num);
  return p + 4;
}

unsigned char*
WriteLEInt32(unsigned char* p, const ogg_int32_t num)
{
  ogg_int32_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<4; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEInt32(p) == num);
  return p + 4;
}

unsigned char*
WriteLEUint16(unsigned char* p, const ogg_uint16_t num)
{
  ogg_uint16_t n = num;
  assert(p);
  p[0] = (unsigned char)(n & 0xff);
  p[1] = (unsigned char)((n >> 8) & 0xff);
  assert(LEUint16(p) == num);
  return p + 2;
}

ogg_uint64_t
LEUint64(unsigned char* p)
{
  ogg_uint64_t lo = LEUint32(p);
  ogg_uint64_t hi = LEUint32(p+4);
  return lo + (hi << 32);
}

ogg_int64_t
LEInt64(unsigned char* p)
{
  ogg_int64_t lo = LEUint32(p);
  ogg_int64_t hi = LEInt32(p+4);
  return lo + (hi << 32);
};

ogg_uint32_t
LEUint32(unsigned const char* p) {
  ogg_uint32_t i =  p[0] +
                   (p[1] << 8) +
                   (p[2] << 16) +
                   (p[3] << 24);
  return i;
}

ogg_int32_t
LEInt32(unsigned const char* p) {
  ogg_int32_t i =  p[0] +
             (p[1] << 8) +
             (p[2] << 16) +
             (p[3] << 24);
  return i;
}

ogg_uint16_t
LEUint16(unsigned const char* p) {
  ogg_uint16_t i =  p[0] +
                   (p[1] << 8);
  return i;
}

void Tokenize(const string& str,
              vector<string>& tokens,
              const string& delimiter)
{
  string::size_type matchStart = 0;
  string::size_type matchEnd = str.find(delimiter, matchStart);
  while (matchEnd != string::npos && matchStart != matchEnd)
  {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(matchStart, matchEnd - matchStart));
    matchStart = matchEnd + delimiter.size();
    matchEnd = str.find(delimiter, matchStart);
  }
}

<commit_msg>Fix cast which was causing 32 bit wrap round on seek - limiting the size of the processed movie to 2Gb.<commit_after>/*
   Copyright (C) 2009, Mozilla Foundation

   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 Mozilla Foundation 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 ORGANISATION 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.
*/

/*
 * Utils.cpp - Generic program utility functions.
 *
 * Contributor(s):
 *   Chris Pearce <chris@pearce.org.nz>
 */

#include <ogg/ogg.h>
#include <fstream>
#include <iostream>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include "Utils.hpp"

ogg_page*
Clone(ogg_page* p)
{
  ogg_page* q = new ogg_page();
  memcpy(q, p, sizeof(ogg_page));
  q->header = new unsigned char[p->header_len + p->body_len];
  q->body = q->header + q->header_len;
  memcpy(q->header, p->header, p->header_len);
  memcpy(q->body, p->body, p->body_len);
  assert(memcmp(p->header, q->header, q->header_len) == 0);
  assert(memcmp(p->body, q->body, q->body_len) == 0);
  assert(q->header_len == p->header_len);
  assert(q->body_len == p->body_len);
  return q;
}

void
FreeClone(ogg_page* p)
{
  delete[] p->header;
  delete p;
}

void
WritePage(ofstream& output, const ogg_page& page) {
  output.write((const char*)page.header, page.header_len);
  output.write((const char*)page.body, page.body_len);
}

// Get the length in bytes of a file. 32bit only, won't work for files larger
// than 2GB.
ogg_int64_t
FileLength(const char* aFileName)
{
  ifstream is;
  is.open (aFileName, ios::binary);
  is.seekg (0, ios::end);
  streampos length = is.tellg();
  is.close();
  return (ogg_int64_t)length;
}

ogg_packet*
Clone(ogg_packet* p)
{
  if (!p)
    return 0;
  ogg_packet* q = new ogg_packet();
  memcpy(q, p, sizeof(ogg_packet));
  q->packet = new unsigned char[p->bytes];
  memcpy(q->packet, p->packet, p->bytes);
  return q;
}

bool
IsIndexPacket(ogg_packet* packet)
{
  return packet &&
         packet->bytes >= (long)(HEADER_MAGIC_LEN + 8) &&
         memcmp(packet->packet, HEADER_MAGIC, HEADER_MAGIC_LEN) == 0;
}

#define FILE_BUFFER_SIZE (1024 * 1024)

// Returns nuber of bytes read.
bool ReadPage(ogg_sync_state* state,
              ogg_page* page,
              istream& stream,
              ogg_uint64_t& bytesRead)
{
  ogg_int32_t bytes = 0;
  ogg_int32_t r = 0;
  ogg_uint64_t intialBytesRead = bytesRead;
  while ((r = ogg_sync_pageout(state, page)) != 1) {
    char* buffer = ogg_sync_buffer(state, FILE_BUFFER_SIZE);
    assert(buffer);
    stream.read(buffer, FILE_BUFFER_SIZE);
    bytes = stream.gcount();
    bytesRead += bytes;
    if (bytes == 0) {
      // End of file
      assert(stream.eof());
      if (intialBytesRead != bytesRead) {
        cerr << "WARNING: Reached end of file, when expecting to find more data! "
             << "Page header may be incorrect!" << endl;
      }
      return false;
    }
    ogg_int32_t ret = ogg_sync_wrote(state, bytes);
    assert(ret == 0);
  }
  return true;
}

// Returns nuber of bytes skipped to next page, or -1 on failure.
int PageSeek(ogg_sync_state* state,
             ogg_page* page,
             istream& stream,
             ogg_uint64_t& bytesRead)
{
  int retval = 0;
  ogg_int32_t bytes = 0;
  ogg_int32_t r = 0;
  ogg_uint64_t intialBytesRead = bytesRead;
  while ((r = ogg_sync_pageseek(state, page)) <= 0) {
    if (r == 0) {
      // Need to read more data to get to next page.
      char* buffer = ogg_sync_buffer(state, FILE_BUFFER_SIZE);
      assert(buffer);

      stream.read(buffer, FILE_BUFFER_SIZE);
      bytes = stream.gcount();
      bytesRead += bytes;
      if (bytes == 0) {
        // End of file
        assert(stream.eof());
        if (intialBytesRead != bytesRead) {
          cerr << "WARNING: Reached end of file, when expecting to find more data! "
               << "Page header may be incorrect!" << endl;
        }
        return false;
      }

      ogg_int32_t ret = ogg_sync_wrote(state, bytes);
      assert(ret == 0);
    } else {
      assert(r<0);
      // We skipped -r bytes reading up to next ogg page capture.
      retval += (-r);
    }
  }
  if (r == -1) {
    cout << "ERROR: sync failure in ReadPage()" << endl;
    return -1;
  }
  return retval;
}

bool
IsPageAtOffset(const string& filename, ogg_int64_t offset, ogg_page* page)
{
  ifstream file(filename.c_str(), ios::in | ios::binary);
  assert(file);
  file.seekg((std::streamoff)offset, ios_base::beg);
  char* buf = new char[max(page->body_len, page->header_len)];
  file.read(buf, page->header_len);
  assert(file.gcount() == page->header_len);
  if (memcmp(buf, page->header, page->header_len) != 0) {
    cerr << "Incorrect page offset calculation for page at offset "
         << offset << endl;
    delete[] buf;
    return false;
  }

  file.read(buf, page->body_len);
  assert(file.gcount() == page->body_len);
  if (memcmp(buf, page->body, page->body_len) != 0) {
    cerr << "Incorrect page offset calculation for page at offset "
         << offset << endl;
    delete[] buf;
    return false;
  }

  delete[] buf;
  return true;
}

void
CopyFileData(istream& input, ostream& output, ogg_int64_t bytesToCopy)
{
  assert(input.good());
  assert(output.good());
  // Copy data in chunks at most 1mb in size.
  assert(bytesToCopy >= 0);
  assert((ogg_int64_t)FILE_BUFFER_SIZE < (ogg_int64_t)INT_MAX);
  ogg_int32_t len = (ogg_int32_t)min(bytesToCopy, (ogg_int64_t)FILE_BUFFER_SIZE);
  char* buf = new char[len];
  ogg_int64_t bytesCopied = 0;
  while (bytesCopied != bytesToCopy) {
    ogg_int64_t remaining = bytesToCopy - bytesCopied;
    ogg_int32_t x = (ogg_int32_t)min(remaining, (ogg_int64_t)len);
    input.read(buf, x);
    assert(x == input.gcount());
    output.write(buf, x);
    bytesCopied += x;
  }
  delete[] buf;
}

ogg_uint32_t
GetChecksum(ogg_page* page)
{
  assert(page != 0);
  assert(page->header != 0);
  assert(page->header_len > 25);
  return LEUint32(page->header + 22);
}

bool
IsFisheadPacket(ogg_packet* packet)
{
  return packet &&
         packet->bytes > 8 &&
         memcmp(packet->packet, "fishead", 8) == 0;
}

bool
IsFisbonePacket(ogg_packet* packet)
{
  return packet->packet &&
         packet->bytes >= 52 &&
         memcmp(packet->packet, "fisbone", 8) == 0;
}

// Theora version
int TheoraVersion(th_info* info,
                  unsigned char maj,
                  unsigned char min,
                  unsigned char sub)
{
  ogg_uint32_t ver = (maj << 16) + (min << 8) + sub;
  ogg_uint32_t th_ver = (info->version_major << 16) +
                        (info->version_minor << 8) +
                        info->version_subminor;
  return (th_ver >= ver) ? 1 : 0;
}

// Returns the number of packets that start on a page.
int
CountPacketStarts(ogg_page* page)
{
  int i;
  // If we're not continuing a packet, we're at a packet start.
  int packets_start = (ogg_page_continued(page) == 0) ? 1 : 0;
  int num_lacing_vals = page->header[26];
  unsigned char* lacing_vals = &page->header[27];
  for (i=1; i<num_lacing_vals; i++) {
    if (lacing_vals[i-1] < 0xff) {
      packets_start++;
    }
  }
  return packets_start;
}

unsigned char*
WriteLEUint64(unsigned char* p, const ogg_uint64_t num)
{
  ogg_int32_t i;
  ogg_uint64_t n = num;
  assert(p);
  for (i=0; i<8; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEUint64(p) == num);
  return p + 8;
}

unsigned char*
WriteLEInt64(unsigned char* p, const ogg_int64_t num)
{
  ogg_int64_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<8; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEInt64(p) == num);
  return p + 8;
}

unsigned char*
WriteLEUint32(unsigned char* p, const ogg_uint32_t num)
{
  ogg_uint32_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<4; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEUint32(p) == num);
  return p + 4;
}

unsigned char*
WriteLEInt32(unsigned char* p, const ogg_int32_t num)
{
  ogg_int32_t n = num;
  ogg_int32_t i;
  assert(p);
  for (i=0; i<4; i++) {
    p[i] = (unsigned char)(n & 0xff);
    n >>= 8;
  }
  assert(LEInt32(p) == num);
  return p + 4;
}

unsigned char*
WriteLEUint16(unsigned char* p, const ogg_uint16_t num)
{
  ogg_uint16_t n = num;
  assert(p);
  p[0] = (unsigned char)(n & 0xff);
  p[1] = (unsigned char)((n >> 8) & 0xff);
  assert(LEUint16(p) == num);
  return p + 2;
}

ogg_uint64_t
LEUint64(unsigned char* p)
{
  ogg_uint64_t lo = LEUint32(p);
  ogg_uint64_t hi = LEUint32(p+4);
  return lo + (hi << 32);
}

ogg_int64_t
LEInt64(unsigned char* p)
{
  ogg_int64_t lo = LEUint32(p);
  ogg_int64_t hi = LEInt32(p+4);
  return lo + (hi << 32);
};

ogg_uint32_t
LEUint32(unsigned const char* p) {
  ogg_uint32_t i =  p[0] +
                   (p[1] << 8) +
                   (p[2] << 16) +
                   (p[3] << 24);
  return i;
}

ogg_int32_t
LEInt32(unsigned const char* p) {
  ogg_int32_t i =  p[0] +
             (p[1] << 8) +
             (p[2] << 16) +
             (p[3] << 24);
  return i;
}

ogg_uint16_t
LEUint16(unsigned const char* p) {
  ogg_uint16_t i =  p[0] +
                   (p[1] << 8);
  return i;
}

void Tokenize(const string& str,
              vector<string>& tokens,
              const string& delimiter)
{
  string::size_type matchStart = 0;
  string::size_type matchEnd = str.find(delimiter, matchStart);
  while (matchEnd != string::npos && matchStart != matchEnd)
  {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(matchStart, matchEnd - matchStart));
    matchStart = matchEnd + delimiter.size();
    matchEnd = str.find(delimiter, matchStart);
  }
}

<|endoftext|>


<commit_before>/*
 *  Copyright (C) Sascha Montellese
 *
 *  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, 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with cpp-signals; see the file COPYING.  If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#include <catch.hpp>

#include <cpp-signal.h>

class copy_test_class : public cpp_signal<>::slot_tracker
{
public:
  copy_test_class()
    : m_int(0)
  { }
  ~copy_test_class() = default;

  unsigned int get_int() const { return m_int; }
  inline void slot_int(int count) { m_int += count; }

private:
  unsigned int m_int;
};

SCENARIO("slot-tracking classes can be copied", "[copy]")
{
  GIVEN("A signal and two instances of a slot-tracking class")
  {
    copy_test_class slot;
    copy_test_class slot_copy;

    cpp_signal<>::signal<void(int)> signal;

    REQUIRE(slot.get_int() == 0);
    REQUIRE(slot_copy.get_int() == 0);

    const int value = 1;

    WHEN("connecting one slot to the signal and emitting the signal")
    {
      signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);
      signal.emit(value);

      THEN("the connected (and tracked) slot is called and the unconnected slot isn't called")
      {
        REQUIRE(slot.get_int() == value);
        REQUIRE(slot_copy.get_int() == 0);
      }
    }

    WHEN("the connected slot is copied to the unconnected slot and the signal is emitted")
    {
      signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);
      slot_copy = slot;

      signal.emit(value);

      THEN("the previously connected slot is called again and the copied slot is called as well")
      {
        REQUIRE(slot.get_int() == value);
        REQUIRE(slot_copy.get_int() == value);
      }
    }
  }
}

SCENARIO("signals can be copied", "[copy]")
{
  GIVEN("A signal and an untracked connected slot")
  {
    int slot_count = 0;
    auto lambda = [&slot_count]() { ++slot_count; };

    cpp_signal<>::signal<void()> signal;
    signal.connect(lambda);

    REQUIRE(slot_count == 0);

    WHEN("the signal is emitted")
    {
      signal.emit();

      THEN("the slot is called")
      {
        REQUIRE(slot_count == 1);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit();
      signal_copy.emit();

      THEN("the slot is called again twice")
      {
        REQUIRE(slot_count == 2);
      }
    }
  }

  GIVEN("A signal and a tracked connected slot")
  {
    copy_test_class slot;

    cpp_signal<>::signal<void(int)> signal;
    signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);

    REQUIRE(slot.get_int() == 0);

    const int value = 1;

    WHEN("the signal is emitted")
    {
      signal.emit(value);

      THEN("the slot is called")
      {
        REQUIRE(slot.get_int() == value);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit(value);
      signal_copy.emit(value);

      THEN("the slot is called twice")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }
  }

  GIVEN("Two chained signals and a tracked connected slot")
  {
    copy_test_class slot;

    cpp_signal<>::signal<void(int)> signal;
    cpp_signal<>::signal<void(int)> chained_signal;
    signal.connect(chained_signal);
    chained_signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);

    REQUIRE(slot.get_int() == 0);

    const int value = 1;

    WHEN("the signal is emitted")
    {
      signal.emit(value);

      THEN("the chainged signal is called and calls the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == value);
      }
    }

    WHEN("the chained signal is copied and the signal is emitted")
    {
      auto chained_signal_copy = chained_signal;

      signal.emit(value);

      THEN("the chained signals are called and the call the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit(value);
      signal_copy.emit(value);

      THEN("the chained signals are called and the call the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }
  }
}<commit_msg>c mark copy_test_class destructor noexcept override<commit_after>/*
 *  Copyright (C) Sascha Montellese
 *
 *  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, 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with cpp-signals; see the file COPYING.  If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#include <catch.hpp>

#include <cpp-signal.h>

class copy_test_class : public cpp_signal<>::slot_tracker
{
public:
  copy_test_class()
    : m_int(0)
  { }
  ~copy_test_class() noexcept override = default;

  unsigned int get_int() const { return m_int; }
  inline void slot_int(int count) { m_int += count; }

private:
  unsigned int m_int;
};

SCENARIO("slot-tracking classes can be copied", "[copy]")
{
  GIVEN("A signal and two instances of a slot-tracking class")
  {
    copy_test_class slot;
    copy_test_class slot_copy;

    cpp_signal<>::signal<void(int)> signal;

    REQUIRE(slot.get_int() == 0);
    REQUIRE(slot_copy.get_int() == 0);

    const int value = 1;

    WHEN("connecting one slot to the signal and emitting the signal")
    {
      signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);
      signal.emit(value);

      THEN("the connected (and tracked) slot is called and the unconnected slot isn't called")
      {
        REQUIRE(slot.get_int() == value);
        REQUIRE(slot_copy.get_int() == 0);
      }
    }

    WHEN("the connected slot is copied to the unconnected slot and the signal is emitted")
    {
      signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);
      slot_copy = slot;

      signal.emit(value);

      THEN("the previously connected slot is called again and the copied slot is called as well")
      {
        REQUIRE(slot.get_int() == value);
        REQUIRE(slot_copy.get_int() == value);
      }
    }
  }
}

SCENARIO("signals can be copied", "[copy]")
{
  GIVEN("A signal and an untracked connected slot")
  {
    int slot_count = 0;
    auto lambda = [&slot_count]() { ++slot_count; };

    cpp_signal<>::signal<void()> signal;
    signal.connect(lambda);

    REQUIRE(slot_count == 0);

    WHEN("the signal is emitted")
    {
      signal.emit();

      THEN("the slot is called")
      {
        REQUIRE(slot_count == 1);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit();
      signal_copy.emit();

      THEN("the slot is called again twice")
      {
        REQUIRE(slot_count == 2);
      }
    }
  }

  GIVEN("A signal and a tracked connected slot")
  {
    copy_test_class slot;

    cpp_signal<>::signal<void(int)> signal;
    signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);

    REQUIRE(slot.get_int() == 0);

    const int value = 1;

    WHEN("the signal is emitted")
    {
      signal.emit(value);

      THEN("the slot is called")
      {
        REQUIRE(slot.get_int() == value);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit(value);
      signal_copy.emit(value);

      THEN("the slot is called twice")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }
  }

  GIVEN("Two chained signals and a tracked connected slot")
  {
    copy_test_class slot;

    cpp_signal<>::signal<void(int)> signal;
    cpp_signal<>::signal<void(int)> chained_signal;
    signal.connect(chained_signal);
    chained_signal.connect<copy_test_class, &copy_test_class::slot_int>(slot);

    REQUIRE(slot.get_int() == 0);

    const int value = 1;

    WHEN("the signal is emitted")
    {
      signal.emit(value);

      THEN("the chainged signal is called and calls the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == value);
      }
    }

    WHEN("the chained signal is copied and the signal is emitted")
    {
      auto chained_signal_copy = chained_signal;

      signal.emit(value);

      THEN("the chained signals are called and the call the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }

    WHEN("the signal is copied and both signals are emitted")
    {
      auto signal_copy = signal;

      signal.emit(value);
      signal_copy.emit(value);

      THEN("the chained signals are called and the call the slot with the forwarded parameter")
      {
        REQUIRE(slot.get_int() == 2 * value);
      }
    }
  }
}<|endoftext|>


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

#ifndef __PROCESS_PROTOBUF_HPP__
#define __PROCESS_PROTOBUF_HPP__

#include <glog/logging.h>

#include <google/protobuf/arena.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>

#include <set>
#include <vector>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/id.hpp>
#include <process/process.hpp>

#include <stout/hashmap.hpp>
#include <stout/lambda.hpp>

// Provides an implementation of process::post that for a protobuf.
namespace process {

inline void post(const process::UPID& to,
                 const google::protobuf::Message& message)
{
  std::string data;
  message.SerializeToString(&data);
  post(to, message.GetTypeName(), data.data(), data.size());
}

inline void post(const process::UPID& from,
                 const process::UPID& to,
                 const google::protobuf::Message& message)
{
  std::string data;
  message.SerializeToString(&data);
  post(from, to, message.GetTypeName(), data.data(), data.size());
}

} // namespace process {

// The rest of this file provides libprocess "support" for using
// protocol buffers. In particular, this file defines a subclass of
// Process (ProtobufProcess) that allows you to install protocol
// buffer handlers in addition to normal message and HTTP
// handlers. Install handlers can optionally take the sender's UPID
// as their first argument.
// Note that this header file assumes you will be linking
// against BOTH libprotobuf and libglog.

namespace google {
namespace protobuf {

// Type conversions helpful for changing between protocol buffer types
// and standard C++ types (for parameters).
template <typename T>
const T& convert(const T& t)
{
  return t;
}

template <typename T>
std::vector<T> convert(const google::protobuf::RepeatedPtrField<T>& items)
{
  std::vector<T> result;
  for (int i = 0; i < items.size(); i++) {
    result.push_back(items.Get(i));
  }

  return result;
}

} // namespace protobuf {
} // namespace google {

template <typename T>
class ProtobufProcess : public process::Process<T>
{
public:
  virtual ~ProtobufProcess() {}

protected:
  virtual void visit(const process::MessageEvent& event)
  {
    if (protobufHandlers.count(event.message.name) > 0) {
      from = event.message.from; // For 'reply'.
      protobufHandlers[event.message.name](
          event.message.from, event.message.body);
      from = process::UPID();
    } else {
      process::Process<T>::visit(event);
    }
  }

  void send(const process::UPID& to,
            const google::protobuf::Message& message)
  {
    std::string data;
    message.SerializeToString(&data);
    process::Process<T>::send(to, message.GetTypeName(),
                              data.data(), data.size());
  }

  using process::Process<T>::send;

  void reply(const google::protobuf::Message& message)
  {
    CHECK(from) << "Attempting to reply without a sender";
    std::string data;
    message.SerializeToString(&data);
    send(from, message);
  }

  // Installs that take the sender as the first argument.
  template <typename M>
  void install(void (T::*method)(const process::UPID&, const M&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&handlerM<M>,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M, typename P>
  using MessageProperty = P(M::*)() const;

  template <typename M>
  void install(void (T::*method)(const process::UPID&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&handler0,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M,
            typename ...P, typename ...PC>
  void install(
      void (T::*method)(const process::UPID&, PC...),
      MessageProperty<M, P>... param)
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(static_cast<void(&)(
                       T*,
                       void (T::*)(const process::UPID&, PC...),
                       const process::UPID&,
                       const std::string&,
                       MessageProperty<M, P>...)>(handlerN),
                   t, method,
                   lambda::_1, lambda::_2, param...);
    delete m;
  }

  // Installs that do not take the sender.
  template <typename M>
  void install(void (T::*method)(const M&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&_handlerM<M>,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M>
  void install(void (T::*method)())
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&_handler0,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M,
            typename ...P, typename ...PC>
  void install(
      void (T::*method)(PC...),
      MessageProperty<M, P>... param)
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(static_cast<void(&)(
                       T*,
                       void (T::*)(PC...),
                       const process::UPID&,
                       const std::string&,
                       MessageProperty<M, P>...)>(_handlerN),
                   t, method,
                   lambda::_1, lambda::_2, param...);
    delete m;
  }

  using process::Process<T>::install;

private:
  // Handlers that take the sender as the first argument.
  template <typename M>
  static void handlerM(
      T* t,
      void (T::*method)(const process::UPID&, const M&),
      const process::UPID& sender,
      const std::string& data)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(sender, *m);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  static void handler0(
      T* t,
      void (T::*method)(const process::UPID&),
      const process::UPID& sender,
      const std::string& data)
  {
    (t->*method)(sender);
  }

  template <typename M,
            typename ...P, typename ...PC>
  static void handlerN(
      T* t,
      void (T::*method)(const process::UPID&, PC...),
      const process::UPID& sender,
      const std::string& data,
      MessageProperty<M, P>... p)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(sender, google::protobuf::convert((m->*p)())...);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  // Handlers that ignore the sender.
  template <typename M>
  static void _handlerM(
      T* t,
      void (T::*method)(const M&),
      const process::UPID&,
      const std::string& data)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(*m);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  static void _handler0(
      T* t,
      void (T::*method)(),
      const process::UPID&,
      const std::string& data)
  {
    (t->*method)();
  }

  template <typename M,
            typename ...P, typename ...PC>
  static void _handlerN(
      T* t,
      void (T::*method)(PC...),
      const process::UPID&,
      const std::string& data,
      MessageProperty<M, P>... p)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(google::protobuf::convert((m->*p)())...);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  typedef lambda::function<
      void(const process::UPID&, const std::string&)> handler;
  hashmap<std::string, handler> protobufHandlers;

  // Sender of "current" message, inaccessible by subclasses.
  // This is only used for reply().
  process::UPID from;
};

// Implements a process for sending protobuf "requests" to a process
// and waiting for a protobuf "response", but uses futures so that
// this can be done without needing to implement a process.
template <typename Req, typename Res>
class ReqResProcess : public ProtobufProcess<ReqResProcess<Req, Res>>
{
public:
  ReqResProcess(const process::UPID& _pid, const Req& _req)
    : process::ProcessBase(process::ID::generate("__req_res__")),
      pid(_pid),
      req(_req)
  {
    ProtobufProcess<ReqResProcess<Req, Res>>::template
      install<Res>(&ReqResProcess<Req, Res>::response);
  }

  virtual ~ReqResProcess()
  {
    // Discard the promise.
    promise.discard();
  }

  process::Future<Res> run()
  {
    promise.future().onDiscard(defer(this, &ReqResProcess::discarded));

    ProtobufProcess<ReqResProcess<Req, Res>>::send(pid, req);

    return promise.future();
  }

private:
  void discarded()
  {
    promise.discard();
    process::terminate(this);
  }

  void response(const Res& res)
  {
    promise.set(res);
    process::terminate(this);
  }

  const process::UPID pid;
  const Req req;
  process::Promise<Res> promise;
};

// Allows you to describe request/response protocols and then use
// those for sending requests and getting back responses.
template <typename Req, typename Res>
struct Protocol
{
  process::Future<Res> operator()(
      const process::UPID& pid,
      const Req& req) const
  {
    // Help debugging by adding some "type constraints".
    { Req* req = nullptr; google::protobuf::Message* m = req; (void)m; }
    { Res* res = nullptr; google::protobuf::Message* m = res; (void)m; }

    ReqResProcess<Req, Res>* process = new ReqResProcess<Req, Res>(pid, req);
    process::spawn(process, true);
    return process::dispatch(process, &ReqResProcess<Req, Res>::run);
  }
};

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

#ifndef __PROCESS_PROTOBUF_HPP__
#define __PROCESS_PROTOBUF_HPP__

#include <glog/logging.h>

#include <google/protobuf/arena.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>

#include <set>
#include <vector>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/id.hpp>
#include <process/process.hpp>

#include <stout/hashmap.hpp>
#include <stout/lambda.hpp>

// Provides an implementation of process::post that for a protobuf.
namespace process {

inline void post(const process::UPID& to,
                 const google::protobuf::Message& message)
{
  std::string data;
  message.SerializeToString(&data);
  post(to, message.GetTypeName(), data.data(), data.size());
}

inline void post(const process::UPID& from,
                 const process::UPID& to,
                 const google::protobuf::Message& message)
{
  std::string data;
  message.SerializeToString(&data);
  post(from, to, message.GetTypeName(), data.data(), data.size());
}

} // namespace process {

// The rest of this file provides libprocess "support" for using
// protocol buffers. In particular, this file defines a subclass of
// Process (ProtobufProcess) that allows you to install protocol
// buffer handlers in addition to normal message and HTTP
// handlers. Install handlers can optionally take the sender's UPID
// as their first argument.
// Note that this header file assumes you will be linking
// against BOTH libprotobuf and libglog.

namespace google {
namespace protobuf {

// Type conversions helpful for changing between protocol buffer types
// and standard C++ types (for parameters).
template <typename T>
const T& convert(const T& t)
{
  return t;
}

template <typename T>
std::vector<T> convert(const google::protobuf::RepeatedPtrField<T>& items)
{
  return std::vector<T>(items.begin(), items.end());
}

} // namespace protobuf {
} // namespace google {

template <typename T>
class ProtobufProcess : public process::Process<T>
{
public:
  virtual ~ProtobufProcess() {}

protected:
  virtual void visit(const process::MessageEvent& event)
  {
    if (protobufHandlers.count(event.message.name) > 0) {
      from = event.message.from; // For 'reply'.
      protobufHandlers[event.message.name](
          event.message.from, event.message.body);
      from = process::UPID();
    } else {
      process::Process<T>::visit(event);
    }
  }

  void send(const process::UPID& to,
            const google::protobuf::Message& message)
  {
    std::string data;
    message.SerializeToString(&data);
    process::Process<T>::send(to, message.GetTypeName(),
                              data.data(), data.size());
  }

  using process::Process<T>::send;

  void reply(const google::protobuf::Message& message)
  {
    CHECK(from) << "Attempting to reply without a sender";
    std::string data;
    message.SerializeToString(&data);
    send(from, message);
  }

  // Installs that take the sender as the first argument.
  template <typename M>
  void install(void (T::*method)(const process::UPID&, const M&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&handlerM<M>,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M, typename P>
  using MessageProperty = P(M::*)() const;

  template <typename M>
  void install(void (T::*method)(const process::UPID&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&handler0,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M,
            typename ...P, typename ...PC>
  void install(
      void (T::*method)(const process::UPID&, PC...),
      MessageProperty<M, P>... param)
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(static_cast<void(&)(
                       T*,
                       void (T::*)(const process::UPID&, PC...),
                       const process::UPID&,
                       const std::string&,
                       MessageProperty<M, P>...)>(handlerN),
                   t, method,
                   lambda::_1, lambda::_2, param...);
    delete m;
  }

  // Installs that do not take the sender.
  template <typename M>
  void install(void (T::*method)(const M&))
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&_handlerM<M>,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M>
  void install(void (T::*method)())
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(&_handler0,
                   t, method,
                   lambda::_1, lambda::_2);
    delete m;
  }

  template <typename M,
            typename ...P, typename ...PC>
  void install(
      void (T::*method)(PC...),
      MessageProperty<M, P>... param)
  {
    google::protobuf::Message* m = new M();
    T* t = static_cast<T*>(this);
    protobufHandlers[m->GetTypeName()] =
      lambda::bind(static_cast<void(&)(
                       T*,
                       void (T::*)(PC...),
                       const process::UPID&,
                       const std::string&,
                       MessageProperty<M, P>...)>(_handlerN),
                   t, method,
                   lambda::_1, lambda::_2, param...);
    delete m;
  }

  using process::Process<T>::install;

private:
  // Handlers that take the sender as the first argument.
  template <typename M>
  static void handlerM(
      T* t,
      void (T::*method)(const process::UPID&, const M&),
      const process::UPID& sender,
      const std::string& data)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(sender, *m);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  static void handler0(
      T* t,
      void (T::*method)(const process::UPID&),
      const process::UPID& sender,
      const std::string& data)
  {
    (t->*method)(sender);
  }

  template <typename M,
            typename ...P, typename ...PC>
  static void handlerN(
      T* t,
      void (T::*method)(const process::UPID&, PC...),
      const process::UPID& sender,
      const std::string& data,
      MessageProperty<M, P>... p)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(sender, google::protobuf::convert((m->*p)())...);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  // Handlers that ignore the sender.
  template <typename M>
  static void _handlerM(
      T* t,
      void (T::*method)(const M&),
      const process::UPID&,
      const std::string& data)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(*m);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  static void _handler0(
      T* t,
      void (T::*method)(),
      const process::UPID&,
      const std::string& data)
  {
    (t->*method)();
  }

  template <typename M,
            typename ...P, typename ...PC>
  static void _handlerN(
      T* t,
      void (T::*method)(PC...),
      const process::UPID&,
      const std::string& data,
      MessageProperty<M, P>... p)
  {
    google::protobuf::Arena arena;
    M* m = CHECK_NOTNULL(google::protobuf::Arena::CreateMessage<M>(&arena));
    m->ParseFromString(data);

    if (m->IsInitialized()) {
      (t->*method)(google::protobuf::convert((m->*p)())...);
    } else {
      LOG(WARNING) << "Initialization errors: "
                   << m->InitializationErrorString();
    }
  }

  typedef lambda::function<
      void(const process::UPID&, const std::string&)> handler;
  hashmap<std::string, handler> protobufHandlers;

  // Sender of "current" message, inaccessible by subclasses.
  // This is only used for reply().
  process::UPID from;
};

// Implements a process for sending protobuf "requests" to a process
// and waiting for a protobuf "response", but uses futures so that
// this can be done without needing to implement a process.
template <typename Req, typename Res>
class ReqResProcess : public ProtobufProcess<ReqResProcess<Req, Res>>
{
public:
  ReqResProcess(const process::UPID& _pid, const Req& _req)
    : process::ProcessBase(process::ID::generate("__req_res__")),
      pid(_pid),
      req(_req)
  {
    ProtobufProcess<ReqResProcess<Req, Res>>::template
      install<Res>(&ReqResProcess<Req, Res>::response);
  }

  virtual ~ReqResProcess()
  {
    // Discard the promise.
    promise.discard();
  }

  process::Future<Res> run()
  {
    promise.future().onDiscard(defer(this, &ReqResProcess::discarded));

    ProtobufProcess<ReqResProcess<Req, Res>>::send(pid, req);

    return promise.future();
  }

private:
  void discarded()
  {
    promise.discard();
    process::terminate(this);
  }

  void response(const Res& res)
  {
    promise.set(res);
    process::terminate(this);
  }

  const process::UPID pid;
  const Req req;
  process::Promise<Res> promise;
};

// Allows you to describe request/response protocols and then use
// those for sending requests and getting back responses.
template <typename Req, typename Res>
struct Protocol
{
  process::Future<Res> operator()(
      const process::UPID& pid,
      const Req& req) const
  {
    // Help debugging by adding some "type constraints".
    { Req* req = nullptr; google::protobuf::Message* m = req; (void)m; }
    { Res* res = nullptr; google::protobuf::Message* m = res; (void)m; }

    ReqResProcess<Req, Res>* process = new ReqResProcess<Req, Res>(pid, req);
    process::spawn(process, true);
    return process::dispatch(process, &ReqResProcess<Req, Res>::run);
  }
};

#endif // __PROCESS_PROTOBUF_HPP__
<|endoftext|>


<commit_before>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct XYPad : Module {
	enum ParamIds {
		X_POS_PARAM,
		Y_POS_PARAM,
		GATE_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		NUM_INPUTS
	};
	enum OutputIds {
		X_OUTPUT,
		Y_OUTPUT,
		GATE_OUTPUT,
		NUM_OUTPUTS
	};

	XYPad() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();

	void initialize() {
	}
};

void XYPad::step() {
	outputs[X_OUTPUT].value = rescalef(params[X_POS_PARAM].value, 0.0, 300, 0.0, 10.0);
	outputs[Y_OUTPUT].value = rescalef(params[Y_POS_PARAM].value, 0.0, 300, 10.0, 0.0);
	outputs[GATE_OUTPUT].value = rescalef(params[GATE_PARAM].value, 0.0, 1, 0, 10.0);
}

struct XYPadDisplay : Widget {
	XYPad *module;
	bool mouseDown = false;
	float minX = 5, minY = 5, maxX = 290, maxY = 370;
	XYPadDisplay() {}

	void setMouseDown(bool down){
		mouseDown = down;
		module->params[XYPad::GATE_PARAM].value = down;
	}

	Widget *onMouseDown(Vec pos, int button){
		setMouseDown(true);
		return this;
	}

	Widget *onMouseUp(Vec pos, int button){
		setMouseDown(false);
		return this;
	}

	Widget *onMouseMove(Vec pos, Vec mouseRel){
		if(mouseDown
			 && pos.x > minX && pos.x < maxX
			 && pos.y > minY && pos.y < maxY ){
			module->params[XYPad::X_POS_PARAM].value = pos.x;
			module->params[XYPad::Y_POS_PARAM].value = pos.y;
		}
		return this;
	}
	void onMouseEnter() {}
	void onMouseLeave() {}
	void onDragStart() {}
	void onDragEnd() {
		setMouseDown(false);
	}
	void onDragMove(Vec mouseRel) {
		if(mouseDown){
			float newX = module->params[XYPad::X_POS_PARAM].value + mouseRel.x;
			if(newX > minX && newX < maxX){
				module->params[XYPad::X_POS_PARAM].value = newX;
			}
			float newY = module->params[XYPad::Y_POS_PARAM].value + mouseRel.y;
			if(newY > minY && newY < maxY){
				module->params[XYPad::Y_POS_PARAM].value = newY;
			}
		}

	}

	void draw(NVGcontext *vg) {
		float ballX = module->params[XYPad::X_POS_PARAM].value;
		float ballY = module->params[XYPad::Y_POS_PARAM].value;

		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeWidth(vg, 2);

		// nvgBeginPath(vg);
		// nvgRect(vg, 20, 20, maxY, box.size.y-40);
		// nvgStroke(vg);

		nvgBeginPath(vg);
		nvgCircle(vg, ballX, ballY, 10);
		if(mouseDown)nvgFill(vg);
		nvgStroke(vg);
	}
};

XYPadWidget::XYPadWidget() {
	XYPad *module = new XYPad();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*20, RACK_GRID_HEIGHT);

	{
		LightPanel *panel = new LightPanel();
		panel->backgroundColor = nvgRGB(30, 40, 43);
		panel->box.size = box.size;
		addChild(panel);
	}

	{
		XYPadDisplay *display = new XYPadDisplay();
		display->module = module;
		display->box.pos = Vec(0, 0);
		display->box.size = Vec(box.size.x, RACK_GRID_HEIGHT);
		addChild(display);
	}

	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 60, 360), module, XYPad::X_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 40, 360), module, XYPad::Y_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 20, 360), module, XYPad::GATE_OUTPUT));
}

<commit_msg>xypad<commit_after>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct XYPad : Module {
	enum ParamIds {
		X_POS_PARAM,
		Y_POS_PARAM,
		GATE_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		NUM_INPUTS
	};
	enum OutputIds {
		X_OUTPUT,
		Y_OUTPUT,
		GATE_OUTPUT,
		NUM_OUTPUTS
	};

	float minX = 0, minY = 0, maxX = 0, maxY = 0;
	float displayWidth = 0, displayHeight = 0;
	float totalBallSize = 12;

	XYPad() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
	void step();
	void initialize(){
		defaultPos();
	}

	json_t *toJson() {
		json_t *rootJ = json_object();
		json_object_set_new(rootJ, "xPos", json_real(params[X_POS_PARAM].value));
		json_object_set_new(rootJ, "yPos", json_real(params[Y_POS_PARAM].value));
		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		json_t *xPosJ = json_object_get(rootJ, "xPos");
		json_t *yPosJ = json_object_get(rootJ, "yPos");
		if (xPosJ){ params[X_POS_PARAM].value = json_real_value(xPosJ); }
		if (yPosJ){ params[Y_POS_PARAM].value = json_real_value(yPosJ); }
	}

	void defaultPos() {
		params[XYPad::X_POS_PARAM].value = displayWidth / 2.0;
		params[XYPad::Y_POS_PARAM].value = displayHeight / 2.0;
	}

	void updateMinMax(){
		minX = totalBallSize;
		minY = totalBallSize;
		maxX = displayWidth - totalBallSize;
		maxY = displayHeight - totalBallSize;

	}
};

void XYPad::step() {
	outputs[X_OUTPUT].value = rescalef(params[X_POS_PARAM].value, minX, maxX, 0.0, 10.0);
	outputs[Y_OUTPUT].value = rescalef(params[Y_POS_PARAM].value, minY, maxY, 10.0, 0.0);
	outputs[GATE_OUTPUT].value = rescalef(params[GATE_PARAM].value, 0.0, 1.0, 0.0, 10.0);
}

struct XYPadDisplay : Widget {
	XYPad *module;
	bool mouseDown = false;
	XYPadDisplay() {

	}

	void setMouseDown(bool down){
		mouseDown = down;
		module->params[XYPad::GATE_PARAM].value = down;
	}

	Widget *onMouseDown(Vec pos, int button){
		setMouseDown(true);
		return this;
	}

	Widget *onMouseUp(Vec pos, int button){
		setMouseDown(false);
		return this;
	}

	Widget *onMouseMove(Vec pos, Vec mouseRel){
		if(mouseDown){
			module->params[XYPad::X_POS_PARAM].value = clampf(pos.x, module->minX, module->maxX);
			module->params[XYPad::Y_POS_PARAM].value = clampf(pos.y, module->minY, module->maxY);
		}
		return this;
	}
	void onMouseEnter() {}
	void onMouseLeave() {}
	void onDragStart() {}
	void onDragEnd() {
		setMouseDown(false);
	}
	void onDragMove(Vec mouseRel) {
		if(mouseDown){
			float newX = module->params[XYPad::X_POS_PARAM].value + mouseRel.x;
			float newY = module->params[XYPad::Y_POS_PARAM].value + mouseRel.y;
			module->params[XYPad::X_POS_PARAM].value = clampf(newX, module->minX, module->maxX);
			module->params[XYPad::Y_POS_PARAM].value = clampf(newY, module->minY, module->maxY);
		}
	}

	void draw(NVGcontext *vg) {
		float ballX = module->params[XYPad::X_POS_PARAM].value;
		float ballY = module->params[XYPad::Y_POS_PARAM].value;

		//background
		nvgFillColor(vg, nvgRGB(20, 30, 33));
		nvgBeginPath(vg);
		nvgRect(vg, 0, 0, box.size.x, box.size.y);
		nvgFill(vg);

		//horizontal line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, 0, ballY);
		nvgLineTo(vg, box.size.x, ballY);
		nvgStroke(vg);

		//vertical line
		nvgStrokeColor(vg, nvgRGB(255, 255, 255));
		nvgBeginPath(vg);
		nvgMoveTo(vg, ballX, 0);
		nvgLineTo(vg, ballX, box.size.y);
		nvgStroke(vg);

		//ball
		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeColor(vg, nvgRGB(25, 150, 252));
		nvgStrokeWidth(vg, 2);
		nvgBeginPath(vg);
		nvgCircle(vg, ballX, ballY, 10);
		if(mouseDown)nvgFill(vg);
		nvgStroke(vg);
	}
};

XYPadWidget::XYPadWidget() {
	XYPad *module = new XYPad();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*20, RACK_GRID_HEIGHT);

	{
		LightPanel *panel = new LightPanel();
		panel->box.size = box.size;
		addChild(panel);
	}

	{
		XYPadDisplay *display = new XYPadDisplay();
		display->module = module;
		display->box.pos = Vec(2, 2);
		display->box.size = Vec(box.size.x - 4, RACK_GRID_HEIGHT - 35);
		addChild(display);

		module->displayWidth = display->box.size.x;
		module->displayHeight = display->box.size.y;
		module->updateMinMax();
		module->defaultPos();
	}

	rack::Label* const titleLabel = new rack::Label;
	titleLabel->box.pos = Vec(3, 350);
	titleLabel->text = "XY Pad";
	addChild(titleLabel);

	rack::Label* const xLabel = new rack::Label;
	xLabel->box.pos = Vec(235, 344);
	xLabel->text = "X";
	addChild(xLabel);

	rack::Label* const yLabel = new rack::Label;
	yLabel->box.pos = Vec(255, 344);
	yLabel->text = "Y";
	addChild(yLabel);

	rack::Label* const gLabel = new rack::Label;
	gLabel->box.pos = Vec(275, 344);
	gLabel->text = "G";
	addChild(gLabel);

	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 60, 360), module, XYPad::X_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 40, 360), module, XYPad::Y_OUTPUT));
	addOutput(createOutput<TinyPJ301MPort>(Vec(box.size.x - 20, 360), module, XYPad::GATE_OUTPUT));
}

<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH
#define DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH

#include <vector>

#include <dune/common/dynmatrix.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/parallel/threadmanager.hh>
#include <dune/stuff/common/tmp-storage.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/grid/walker/functors.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/localoperator/interface.hh>
#include <dune/gdt/localfunctional/interface.hh>
#include <dune/gdt/spaces/interface.hh>

namespace Dune {
namespace GDT {
namespace LocalAssembler {

template <class LocalOperatorImp>
class Codim0Matrix
{
  static_assert(
      std::is_base_of<LocalOperator::Codim0Interface<typename LocalOperatorImp::Traits>, LocalOperatorImp>::value,
      "LocalOperatorImp has to be derived from LocalOperator::Codim0Interface!");

public:
  typedef LocalOperatorImp LocalOperatorType;

  explicit Codim0Matrix(const LocalOperatorType& op)
    : localOperator_(op)
  {
  }

  const LocalOperatorType& localOperator() const
  {
    return localOperator_;
  }

private:
  static const size_t numTmpObjectsRequired_ = 1;

public:
  std::vector<size_t> numTmpObjectsRequired() const
  {
    return {numTmpObjectsRequired_, localOperator_.numTmpObjectsRequired()};
  }

  /**
   *  \tparam T           Traits of the SpaceInterface implementation, representing the type of testSpace
   *  \tparam A           Traits of the SpaceInterface implementation, representing the type of ansatzSpace
   *  \tparam EntityType  A model of Dune::Entity< 0 >
   *  \tparam M           Traits of the Dune::Stuff::LA::Container::MatrixInterface implementation, representing the
   * type of systemMatrix
   *  \tparam R           RangeFieldType, i.e. double
   */
  template <class T, class A, class EntityType, class M, class R>
  void assembleLocal(const SpaceInterface<T>& testSpace, const SpaceInterface<A>& ansatzSpace, const EntityType& entity,
                     Dune::Stuff::LA::MatrixInterface<M, R>& systemMatrix,
                     std::vector<std::vector<Dune::DynamicMatrix<R>>>& tmpLocalMatricesContainer,
                     std::vector<Dune::DynamicVector<size_t>>& tmpIndicesContainer) const
  {
    // check
    assert(tmpLocalMatricesContainer.size() >= 1);
    assert(tmpLocalMatricesContainer[0].size() >= numTmpObjectsRequired_);
    assert(tmpLocalMatricesContainer[1].size() >= localOperator_.numTmpObjectsRequired());
    assert(tmpIndicesContainer.size() >= 2);
    // get and clear matrix
    Dune::DynamicMatrix<R>& localMatrix = tmpLocalMatricesContainer[0][0];
    localMatrix *= 0.0;
    auto& tmpOperatorMatrices = tmpLocalMatricesContainer[1];
    // apply local operator (result is in localMatrix)
    localOperator_.apply(
        testSpace.base_function_set(entity), ansatzSpace.base_function_set(entity), localMatrix, tmpOperatorMatrices);
    // write local matrix to global
    Dune::DynamicVector<size_t>& globalRows = tmpIndicesContainer[0];
    Dune::DynamicVector<size_t>& globalCols = tmpIndicesContainer[1];
    const size_t rows                       = testSpace.mapper().numDofs(entity);
    const size_t cols = ansatzSpace.mapper().numDofs(entity);
    assert(globalRows.size() >= rows);
    assert(globalCols.size() >= cols);
    testSpace.mapper().globalIndices(entity, globalRows);
    ansatzSpace.mapper().globalIndices(entity, globalCols);
    for (size_t ii = 0; ii < rows; ++ii) {
      const auto& localRow  = localMatrix[ii];
      const size_t globalII = globalRows[ii];
      for (size_t jj = 0; jj < cols; ++jj) {
        const size_t globalJJ = globalCols[jj];
        systemMatrix.add_to_entry(globalII, globalJJ, localRow[jj]);
      }
    } // write local matrix to global
  } // ... assembleLocal(...)

private:
  const LocalOperatorType& localOperator_;
}; // class Codim0Matrix

template <class LocalFunctionalImp>
class Codim0Vector
{
  static_assert(
      std::is_base_of<LocalFunctional::Codim0Interface<typename LocalFunctionalImp::Traits>, LocalFunctionalImp>::value,
      "LocalFunctionalImp has to be derived from LocalFunctional::Codim0Interface!");

public:
  typedef LocalFunctionalImp LocalFunctionalType;

  explicit Codim0Vector(const LocalFunctionalType& func)
    : localFunctional_(func)
  {
  }

  const LocalFunctionalType& localFunctional() const
  {
    return localFunctional_;
  }

private:
  static const size_t numTmpObjectsRequired_ = 1;

public:
  std::vector<size_t> numTmpObjectsRequired() const
  {
    return {numTmpObjectsRequired_, localFunctional_.numTmpObjectsRequired()};
  }

  /**
   *  \tparam T           Traits of the SpaceInterface implementation, representing the type of testSpace
   *  \tparam EntityType  A model of Dune::Entity< 0 >
   *  \tparam V           Traits of the Dune::Stuff::LA::Container::VectorInterface implementation, representing the
   * type of systemVector
   *  \tparam R           RangeFieldType, i.e. double
   */
  template <class T, class EntityType, class V, class R>
  void assembleLocal(const SpaceInterface<T>& testSpace, const EntityType& entity,
                     Dune::Stuff::LA::VectorInterface<V, R>& systemVector,
                     std::vector<std::vector<Dune::DynamicVector<R>>>& tmpLocalVectorContainer,
                     Dune::DynamicVector<size_t>& tmpIndices) const
  {
    // check
    assert(tmpLocalVectorContainer.size() >= 2);
    assert(tmpLocalVectorContainer[0].size() >= numTmpObjectsRequired_);
    assert(tmpLocalVectorContainer[1].size() >= localFunctional_.numTmpObjectsRequired());
    // get and clear vector
    auto& localVector = tmpLocalVectorContainer[0][0];
    localVector *= 0.0;
    auto& tmpFunctionalVectors = tmpLocalVectorContainer[1];
    // apply local functional (result is in localVector)
    localFunctional_.apply(testSpace.base_function_set(entity), localVector, tmpFunctionalVectors);
    // write local vector to global
    const size_t size = testSpace.mapper().numDofs(entity);
    assert(tmpIndices.size() >= size);
    testSpace.mapper().globalIndices(entity, tmpIndices);
    for (size_t ii = 0; ii < size; ++ii) {
      systemVector.add_to_entry(tmpIndices[ii], localVector[ii]);
    } // write local matrix to global
  } // ... assembleLocal(...)

private:
  const LocalFunctionalType& localFunctional_;
}; // class Codim0Vector

template <class GridViewImp, class LocalOperatorType, class TestFunctionType, class AnsatzFunctionType, class FieldType>
class Codim0OperatorAccumulateFunctor : public Stuff::Grid::Functor::Codim0<GridViewImp>
{
  static_assert(
      std::is_base_of<LocalOperator::Codim0Interface<typename LocalOperatorType::Traits>, LocalOperatorType>::value,
      "LocalOperatorType has to be derived from LocalOperator::Codim0Interface!");
  static_assert(Stuff::is_localizable_function<TestFunctionType>::value,
                "TestFunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(Stuff::is_localizable_function<AnsatzFunctionType>::value,
                "AnsatzFunctionType has to be derived from Stuff::LocalizableFunctionInterface!");

  typedef Stuff::Grid::Functor::Codim0<GridViewImp> BaseType;
  typedef DSC::TmpMatricesStorage<FieldType> TmpMatricesProviderType;

public:
  typedef typename BaseType::GridViewType GridViewType;
  typedef typename BaseType::EntityType EntityType;

  Codim0OperatorAccumulateFunctor(const GridViewType& grd_vw, const LocalOperatorType& local_op,
                                  const TestFunctionType& test_function, const AnsatzFunctionType& ansatz_function)
    : grid_view_(grd_vw)
    , local_operator_(local_op)
    , test_function_(test_function)
    , ansatz_function_(ansatz_function)
    , result_(0)
    , finalized_(false)
  {
    // can not use make_unique here, at least clang does not get it
    tmp_storage_ = std::unique_ptr<TmpMatricesProviderType>(
        new TmpMatricesProviderType({1, local_operator_.numTmpObjectsRequired()}, 1, 1));
  }

  virtual ~Codim0OperatorAccumulateFunctor() = default;

  FieldType compute_locally(const EntityType& entity)
  {
    assert(tmp_storage_->matrices().size() >= 2);
    assert(tmp_storage_->matrices()[0].size() >= 1);
    auto& local_operator_result = tmp_storage_->matrices()[0][0];
    auto& tmp_matrices          = tmp_storage_->matrices()[1];
    // get the local functions
    const auto local_test_function   = test_function_.local_function(entity);
    const auto local_ansatz_function = ansatz_function_.local_function(entity);
    // apply the local operator
    this->local_operator_.apply(*local_test_function, *local_ansatz_function, local_operator_result, tmp_matrices);
    assert(local_operator_result.rows() >= 1);
    assert(local_operator_result.cols() >= 1);
    return local_operator_result[0][0];
  } // ... compute_locally(...)

  virtual void apply_local(const EntityType& entity) override
  {
    *result_ += compute_locally(entity);
  }

  virtual void finalize() override
  {
    if (!finalized_) {
      finalized_result_ = result_.sum();
      finalized_result_ = grid_view_.comm().sum(finalized_result_);
      finalized_        = true;
    }
  } // ... finalize(...)

  FieldType result() const
  {
    if (!finalized_)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Call finalize() first!");
    return finalized_result_;
  }

private:
  const GridViewType& grid_view_;
  const LocalOperatorType& local_operator_;
  const TestFunctionType& test_function_;
  const AnsatzFunctionType& ansatz_function_;
  DS::PerThreadValue<FieldType> result_;
  std::unique_ptr<TmpMatricesProviderType> tmp_storage_;
  bool finalized_;
  FieldType finalized_result_;
}; // class Codim0OperatorAccumulateFunctor

} // namespace LocalAssembler
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH
<commit_msg>[assembler.local.codim0] make Codim0OperatorAccumulateFunctor copyable<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH
#define DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH

#include <vector>

#include <dune/common/dynmatrix.hh>
#include <dune/common/dynvector.hh>

#include <dune/stuff/common/memory.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/parallel/threadmanager.hh>
#include <dune/stuff/common/tmp-storage.hh>
#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/grid/walker/functors.hh>
#include <dune/stuff/la/container/interfaces.hh>

#include <dune/gdt/localoperator/interface.hh>
#include <dune/gdt/localfunctional/interface.hh>
#include <dune/gdt/spaces/interface.hh>

namespace Dune {
namespace GDT {
namespace LocalAssembler {

template <class LocalOperatorImp>
class Codim0Matrix
{
  static_assert(
      std::is_base_of<LocalOperator::Codim0Interface<typename LocalOperatorImp::Traits>, LocalOperatorImp>::value,
      "LocalOperatorImp has to be derived from LocalOperator::Codim0Interface!");

public:
  typedef LocalOperatorImp LocalOperatorType;

  explicit Codim0Matrix(const LocalOperatorType& op)
    : localOperator_(op)
  {
  }

  const LocalOperatorType& localOperator() const
  {
    return localOperator_;
  }

private:
  static const size_t numTmpObjectsRequired_ = 1;

public:
  std::vector<size_t> numTmpObjectsRequired() const
  {
    return {numTmpObjectsRequired_, localOperator_.numTmpObjectsRequired()};
  }

  /**
   *  \tparam T           Traits of the SpaceInterface implementation, representing the type of testSpace
   *  \tparam A           Traits of the SpaceInterface implementation, representing the type of ansatzSpace
   *  \tparam EntityType  A model of Dune::Entity< 0 >
   *  \tparam M           Traits of the Dune::Stuff::LA::Container::MatrixInterface implementation, representing the
   * type of systemMatrix
   *  \tparam R           RangeFieldType, i.e. double
   */
  template <class T, class A, class EntityType, class M, class R>
  void assembleLocal(const SpaceInterface<T>& testSpace, const SpaceInterface<A>& ansatzSpace, const EntityType& entity,
                     Dune::Stuff::LA::MatrixInterface<M, R>& systemMatrix,
                     std::vector<std::vector<Dune::DynamicMatrix<R>>>& tmpLocalMatricesContainer,
                     std::vector<Dune::DynamicVector<size_t>>& tmpIndicesContainer) const
  {
    // check
    assert(tmpLocalMatricesContainer.size() >= 1);
    assert(tmpLocalMatricesContainer[0].size() >= numTmpObjectsRequired_);
    assert(tmpLocalMatricesContainer[1].size() >= localOperator_.numTmpObjectsRequired());
    assert(tmpIndicesContainer.size() >= 2);
    // get and clear matrix
    Dune::DynamicMatrix<R>& localMatrix = tmpLocalMatricesContainer[0][0];
    localMatrix *= 0.0;
    auto& tmpOperatorMatrices = tmpLocalMatricesContainer[1];
    // apply local operator (result is in localMatrix)
    localOperator_.apply(
        testSpace.base_function_set(entity), ansatzSpace.base_function_set(entity), localMatrix, tmpOperatorMatrices);
    // write local matrix to global
    Dune::DynamicVector<size_t>& globalRows = tmpIndicesContainer[0];
    Dune::DynamicVector<size_t>& globalCols = tmpIndicesContainer[1];
    const size_t rows                       = testSpace.mapper().numDofs(entity);
    const size_t cols = ansatzSpace.mapper().numDofs(entity);
    assert(globalRows.size() >= rows);
    assert(globalCols.size() >= cols);
    testSpace.mapper().globalIndices(entity, globalRows);
    ansatzSpace.mapper().globalIndices(entity, globalCols);
    for (size_t ii = 0; ii < rows; ++ii) {
      const auto& localRow  = localMatrix[ii];
      const size_t globalII = globalRows[ii];
      for (size_t jj = 0; jj < cols; ++jj) {
        const size_t globalJJ = globalCols[jj];
        systemMatrix.add_to_entry(globalII, globalJJ, localRow[jj]);
      }
    } // write local matrix to global
  } // ... assembleLocal(...)

private:
  const LocalOperatorType& localOperator_;
}; // class Codim0Matrix

template <class LocalFunctionalImp>
class Codim0Vector
{
  static_assert(
      std::is_base_of<LocalFunctional::Codim0Interface<typename LocalFunctionalImp::Traits>, LocalFunctionalImp>::value,
      "LocalFunctionalImp has to be derived from LocalFunctional::Codim0Interface!");

public:
  typedef LocalFunctionalImp LocalFunctionalType;

  explicit Codim0Vector(const LocalFunctionalType& func)
    : localFunctional_(func)
  {
  }

  const LocalFunctionalType& localFunctional() const
  {
    return localFunctional_;
  }

private:
  static const size_t numTmpObjectsRequired_ = 1;

public:
  std::vector<size_t> numTmpObjectsRequired() const
  {
    return {numTmpObjectsRequired_, localFunctional_.numTmpObjectsRequired()};
  }

  /**
   *  \tparam T           Traits of the SpaceInterface implementation, representing the type of testSpace
   *  \tparam EntityType  A model of Dune::Entity< 0 >
   *  \tparam V           Traits of the Dune::Stuff::LA::Container::VectorInterface implementation, representing the
   * type of systemVector
   *  \tparam R           RangeFieldType, i.e. double
   */
  template <class T, class EntityType, class V, class R>
  void assembleLocal(const SpaceInterface<T>& testSpace, const EntityType& entity,
                     Dune::Stuff::LA::VectorInterface<V, R>& systemVector,
                     std::vector<std::vector<Dune::DynamicVector<R>>>& tmpLocalVectorContainer,
                     Dune::DynamicVector<size_t>& tmpIndices) const
  {
    // check
    assert(tmpLocalVectorContainer.size() >= 2);
    assert(tmpLocalVectorContainer[0].size() >= numTmpObjectsRequired_);
    assert(tmpLocalVectorContainer[1].size() >= localFunctional_.numTmpObjectsRequired());
    // get and clear vector
    auto& localVector = tmpLocalVectorContainer[0][0];
    localVector *= 0.0;
    auto& tmpFunctionalVectors = tmpLocalVectorContainer[1];
    // apply local functional (result is in localVector)
    localFunctional_.apply(testSpace.base_function_set(entity), localVector, tmpFunctionalVectors);
    // write local vector to global
    const size_t size = testSpace.mapper().numDofs(entity);
    assert(tmpIndices.size() >= size);
    testSpace.mapper().globalIndices(entity, tmpIndices);
    for (size_t ii = 0; ii < size; ++ii) {
      systemVector.add_to_entry(tmpIndices[ii], localVector[ii]);
    } // write local matrix to global
  } // ... assembleLocal(...)

private:
  const LocalFunctionalType& localFunctional_;
}; // class Codim0Vector

template <class GridViewImp, class LocalOperatorType, class TestFunctionType, class AnsatzFunctionType, class FieldType>
class Codim0OperatorAccumulateFunctor : public Stuff::Grid::Functor::Codim0<GridViewImp>
{
  static_assert(
      std::is_base_of<LocalOperator::Codim0Interface<typename LocalOperatorType::Traits>, LocalOperatorType>::value,
      "LocalOperatorType has to be derived from LocalOperator::Codim0Interface!");
  static_assert(Stuff::is_localizable_function<TestFunctionType>::value,
                "TestFunctionType has to be derived from Stuff::LocalizableFunctionInterface!");
  static_assert(Stuff::is_localizable_function<AnsatzFunctionType>::value,
                "AnsatzFunctionType has to be derived from Stuff::LocalizableFunctionInterface!");

  typedef Codim0OperatorAccumulateFunctor<GridViewImp, LocalOperatorType, TestFunctionType, AnsatzFunctionType,
                                          FieldType> ThisType;
  typedef Stuff::Grid::Functor::Codim0<GridViewImp> BaseType;
  typedef DSC::TmpMatricesStorage<FieldType> TmpMatricesProviderType;

public:
  typedef typename BaseType::GridViewType GridViewType;
  typedef typename BaseType::EntityType EntityType;

  Codim0OperatorAccumulateFunctor(const GridViewType& grd_vw, const LocalOperatorType& local_op,
                                  const TestFunctionType& test_function, const AnsatzFunctionType& ansatz_function)
    : grid_view_(grd_vw)
    , local_operator_(local_op)
    , test_function_(test_function)
    , ansatz_function_(ansatz_function)
    , result_(0)
    , finalized_(false)
  {
    // can not use make_unique here, at least clang does not get it
    tmp_storage_ = std::unique_ptr<TmpMatricesProviderType>(
        new TmpMatricesProviderType({1, local_operator_.numTmpObjectsRequired()}, 1, 1));
  }

  Codim0OperatorAccumulateFunctor(const ThisType& other)
    : grid_view_(other.grid_view_)
    , local_operator_(other.local_operator_)
    , test_function_(other.test_function_)
    , ansatz_function_(other.ansatz_function_)
    , result_(0)
    , finalized_(other.finalized_)
  {
    // can not use make_unique here, at least clang does not get it
    tmp_storage_ = std::unique_ptr<TmpMatricesProviderType>(
        new TmpMatricesProviderType({1, local_operator_.numTmpObjectsRequired()}, 1, 1));
    result_ = other.result_;
  }

  virtual ~Codim0OperatorAccumulateFunctor() = default;

  FieldType compute_locally(const EntityType& entity)
  {
    assert(tmp_storage_->matrices().size() >= 2);
    assert(tmp_storage_->matrices()[0].size() >= 1);
    auto& local_operator_result = tmp_storage_->matrices()[0][0];
    auto& tmp_matrices          = tmp_storage_->matrices()[1];
    // get the local functions
    const auto local_test_function   = test_function_.local_function(entity);
    const auto local_ansatz_function = ansatz_function_.local_function(entity);
    // apply the local operator
    this->local_operator_.apply(*local_test_function, *local_ansatz_function, local_operator_result, tmp_matrices);
    assert(local_operator_result.rows() >= 1);
    assert(local_operator_result.cols() >= 1);
    return local_operator_result[0][0];
  } // ... compute_locally(...)

  virtual void apply_local(const EntityType& entity) override
  {
    *result_ += compute_locally(entity);
  }

  virtual void finalize() override
  {
    if (!finalized_) {
      finalized_result_ = result_.sum();
      finalized_result_ = grid_view_.comm().sum(finalized_result_);
      finalized_        = true;
    }
  } // ... finalize(...)

  FieldType result() const
  {
    if (!finalized_)
      DUNE_THROW(Stuff::Exceptions::you_are_using_this_wrong, "Call finalize() first!");
    return finalized_result_;
  }

private:
  const GridViewType& grid_view_;
  const LocalOperatorType& local_operator_;
  const TestFunctionType& test_function_;
  const AnsatzFunctionType& ansatz_function_;
  DS::PerThreadValue<FieldType> result_;
  std::unique_ptr<TmpMatricesProviderType> tmp_storage_;
  bool finalized_;
  FieldType finalized_result_;
}; // class Codim0OperatorAccumulateFunctor

} // namespace LocalAssembler
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMLBER_LOCAL_CODIM0_HH
<|endoftext|>


<commit_before>/**
 * Copyright 2013 Truphone
 */
#include "ListCommand.h"

#include <QString>
#include <QList>
#include <QObject>

#include <bb/cascades/ListView>

#include "Connection.h"

using bb::cascades::ListView;

namespace truphone
{
namespace test
{
namespace cascades
{
    const QString ListCommand::CMD_NAME = "list";

    ListCommand::ListCommand(Connection * const socket,
                             QObject* parent)
        : Command(parent),
          client(socket),
          scenePane(bb::cascades::Application::instance()->scene())
    {
    }

    ListCommand::~ListCommand()
    {
    }

    bool ListCommand::executeCommand(QStringList * const arguments)
    {
        if (arguments->size() > 1)
        {
            const QString listViewName = arguments->first();
            arguments->removeFirst();
            ListView * const listView = scenePane->findChild<ListView*>(listViewName);
            if (listView)
            {
                const QString command = arguments->first();
                arguments->removeFirst();
                if (command == "count")
                {
                    const int s = listView->dataModel()->childCount(listView->rootIndexPath());
                    this->client->write(QString::number(s).toUtf8().constData());
                    this->client->write("\r\n");
                }
                else
                {
                    this->client->write("ERROR: Unknown list command\r\n");
                }
            }
            else
            {
                this->client->write("ERROR: Couldn't find the listview\r\n");
            }
        }
        else
        {
            this->client->write("ERROR: Not enough arguments, sleep <timeInMs>\r\n");
        }
        return false;
    }

    void ListCommand::showHelp()
    {
        this->client->write("> list....?\r\n");
    }
}  // namespace cascades
}  // namespace test
}  // namespace truphone
<commit_msg>Fix up the list count command.<commit_after>/**
 * Copyright 2013 Truphone
 */
#include "ListCommand.h"

#include <QString>
#include <QList>
#include <QObject>

#include <bb/cascades/ListView>

#include "Connection.h"

using bb::cascades::ListView;

namespace truphone
{
namespace test
{
namespace cascades
{
    const QString ListCommand::CMD_NAME = "list";

    ListCommand::ListCommand(Connection * const socket,
                             QObject* parent)
        : Command(parent),
          client(socket),
          scenePane(bb::cascades::Application::instance()->scene())
    {
    }

    ListCommand::~ListCommand()
    {
    }

    bool ListCommand::executeCommand(QStringList * const arguments)
    {
        bool ret = false;
        if (arguments->size() > 1)
        {
            const QString listViewName = arguments->first();
            arguments->removeFirst();
            ListView * const listView = scenePane->findChild<ListView*>(listViewName);
            if (listView)
            {
                const QString command = arguments->first();
                arguments->removeFirst();
                if (command == "count" && !arguments->isEmpty())
                {
                    bool ok = false;
                    const int expected = arguments->first().toInt(&ok);
                    if (ok)
                    {
                        const int actual =
                                listView->dataModel()->childCount(listView->rootIndexPath());
                        ret = (actual == expected);
                    }
                    else
                    {
                        this->client->write("ERROR: Expected list size wasn't an integer\r\n");
                    }
                }
                else
                {
                    this->client->write("ERROR: Unknown list command\r\n");
                }
            }
            else
            {
                this->client->write("ERROR: Couldn't find the listview\r\n");
            }
        }
        else
        {
            this->client->write("ERROR: Not enough arguments, sleep <timeInMs>\r\n");
        }
        return ret;
    }

    void ListCommand::showHelp()
    {
        this->client->write("> list <list> count <expectedSize>\r\n");
    }
}  // namespace cascades
}  // namespace test
}  // namespace truphone
<|endoftext|>