<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <getopt.h>
#include <cstring>

#include <less/less/LessTokenizer.h>
#include <less/less/LessParser.h>
#include <less/css/CssWriter.h>
#include <less/css/CssPrettyWriter.h>
#include <less/stylesheet/Stylesheet.h>
#include <less/css/IOException.h>
#include <less/lessstylesheet/LessStylesheet.h>

using namespace std;

/**
 * /main Less CSS compiler, implemented in C++.
 *
 */

void usage () {
  cout <<
    "Usage: lessc [OPTION]... [FILE]\n"
    "\n"
    "   FILE				Less source file. If not given, source \
is read from stdin.\n"
    "   -h, --help			Show this message and exit.\n"
    "       --version		Print the program name and version.\n"
    "\n"
    "   -o, --output=<FILE>		Send output to FILE\n"
    "   -f, --format			Format output CSS with newlines and \
indentation. By default the output is unformatted.\n"
    "\n"
    "   -m, --source-map=[FILE]	Generate a source map.\n"
    "       --source-map-rootpath=<PATH>   PATH is prepended to the \
source file references in the source map. \n"
    "       --source-map-basepath=<PATH>   PATH is removed from the \
source file references in the source map.\n"
    "       --rootpath=<PATH>           Prefix PATH to urls and import \
statements in output. \n"
    "   -I, --include-path=<FILE>       Specify paths to look for \
imported .less files.\n"
    "\n"
    "Example:\n"
    "   lessc in.less -o out.css\n"
    "\n"
    "Report bugs to: " PACKAGE_BUGREPORT "\n"
    PACKAGE_NAME " home page: <" PACKAGE_URL ">\n";
}

void version () {
  cout <<
    PACKAGE_STRING "\n"
    "Copyright 2012 Bram van der Kroef\n"
    "License: MIT License\n";
}

/**
 * Copy a given path to a new string and add a trailing slash if necessary.
 */
char* path_create(const char* path, size_t len) {
  size_t newlen = len +
    (path[len - 1] != '/' ? 1 : 0);
  char* p = new char[newlen + 1];
  std::strncpy(p, path, len);
  p[newlen - 1] = '/';
  p[newlen] = '\0';
  return p;
}

void path_parse_list(const char* path, std::list<const char*>& paths) {
  const char* start = path;
  const char* end = path;
  size_t len;

  while((end = std::strchr(start, ':')) != NULL) {
    len = (end - start);
    // skip empty paths
    if (len > 0)
      paths.push_back(path_create(start, len));

    start = end + 1;
  }
  len = std::strlen(start);
  if (len > 0)
    paths.push_back(path_create(start, len));
}

char* path_create_relative(const char* path, const char* relative) {
  const char* p_root;
  const char* r_root;
  size_t desc_n;
  char* ret, *ret_p;

  // strip common directories
  while ((p_root = strchr(path, '/')) != NULL &&
         (r_root = strchr(relative, '/')) != NULL &&
         p_root - path == r_root - relative &&
         strncmp(path, relative, p_root - path) == 0) {
    path = p_root + 1;
    relative = r_root + 1;
  }

  // count how many folders to go up.
  for (desc_n = 0; relative != NULL; desc_n++) {
    relative = strchr(relative + 1, '/');
  }
  desc_n--;

  ret = new char[strlen(path) + 3 * desc_n + 1];
  ret_p = ret;
  while (desc_n > 0) {
    memcpy(ret_p, "../", 3);
    ret_p += 3;
    desc_n--;
  }

  strcpy(ret_p, path);
  return ret;
}

bool parseInput(LessStylesheet &stylesheet,
                istream &in,
                const char* source,
                std::list<const char*> &sources,
                std::list<const char*> &includePaths) {
  std::list<const char*>::iterator i;

  LessTokenizer tokenizer(in, source);
  LessParser parser(tokenizer, sources);
  parser.includePaths = &includePaths;

  try{
    parser.parseStylesheet(stylesheet);
  } catch(ParseException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what() << endl;

    return false;
  } catch(exception* e) {
    cerr << " Error: " << e->what() << endl;

    return false;
  }

  return true;
}

bool processStylesheet (LessStylesheet &stylesheet,
                        Stylesheet &css) {
  ProcessingContext context;

  try{
    stylesheet.process(css, context);

  } catch(ParseException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what() << endl;
    return false;

  } catch(ValueException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what() << endl;
    return false;

  } catch(exception* e) {

    cerr << "Error: " << e->what() << endl;
    return false;
  }
  return true;
}

void writeOutput(Stylesheet &css,
                 const char* output,
                 bool formatoutput,
                 const char* rootpath,
                 std::list<const char*> &sources,
                 const char* sourcemap_file,
                 const char* sourcemap_rootpath,
                 const char* sourcemap_basepath) {
  ostream* out = &cout;
  CssWriter* writer;
  ostream* sourcemap_s = NULL;
  SourceMapWriter* sourcemap = NULL;
  char* tmp;
  std::list<const char*> relative_sources;
  std::list<const char*>::iterator it;
  size_t bp_l = 0;

  if (sourcemap_basepath != NULL)
    bp_l = strlen(sourcemap_basepath);

  if (strcmp(output, "-") != 0)
    out = new ofstream(output);

  if (sourcemap_file != NULL) {
    if (strcmp(sourcemap_file, "-") == 0) {
      if (strcmp(output, "-") == 0) {
        throw new IOException("source-map option requires that \
a file name is specified for either the source map or the css  \
output file.");
      } else {
        tmp = new char[strlen(output) + 5];
        sprintf(tmp, "%s.map", output);
        sourcemap_file = tmp;
      }
    }
    for (it = sources.begin(); it != sources.end(); it++) {
      if (sourcemap_basepath == NULL) {
        relative_sources.push_back(path_create_relative(*it, sourcemap_file));
      } else if (strncmp(*it, sourcemap_basepath, bp_l) == 0) {
        relative_sources.push_back(*it + bp_l);
      }
    }

    sourcemap_s = new ofstream(sourcemap_file);
    sourcemap = new SourceMapWriter(*sourcemap_s,
                                    sources,
                                    relative_sources,
                                    path_create_relative(output, sourcemap_file),
                                    sourcemap_rootpath);

    writer = formatoutput ? new CssPrettyWriter(*out, *sourcemap) :
      new CssWriter(*out, *sourcemap);
  } else {
    writer = formatoutput ? new CssPrettyWriter(*out) :
      new CssWriter(*out);
  }
  writer->rootpath = rootpath;

  css.write(*writer);

  if (sourcemap != NULL) {
    writer->writeSourceMapUrl(path_create_relative(sourcemap_file, output));

    sourcemap->close();
    delete sourcemap;
    if (sourcemap_s != NULL)
      delete sourcemap_s;
  }

  delete writer;
  *out << endl;
}

void writeDependencies(const char* output, const std::list<const char*> &sources) {
  std::list<const char *>::const_iterator i;

  cout << output << ": ";

  for (i = sources.begin(); i != sources.end(); i++) {
    if (i != sources.begin())
      cout << ", ";
    cout << (*i);
  }
  cout << endl;
}

int main(int argc, char * argv[]){
  istream* in = &cin;
  bool formatoutput = false;
  char* source = NULL;
  const char* output = "-";
  LessStylesheet stylesheet;
  std::list<const char*> sources;
  Stylesheet css;
  bool depends = false, lint = false;

  const char* sourcemap_file = NULL;

  const char* sourcemap_rootpath = NULL;
  const char* sourcemap_basepath = NULL;
  const char* rootpath = NULL;

  std::list<const char*> includePaths;

  static struct option long_options[] = {
    {"version",             no_argument,       0, 1},
    {"help",                no_argument,       0, 'h'},
    {"output",              required_argument, 0, 'o'},
    {"format",              no_argument,       0, 'f'},
    {"source-map",          optional_argument, 0, 'm'},
    {"source-map-rootpath", required_argument, 0, 2},
    {"source-map-basepath", required_argument, 0, 3},
    {"include-path",        required_argument, 0, 'I'},
    {"rootpath",            required_argument, 0, 4},
    {"depends",             no_argument,       0, 'M'},
    {"lint",                no_argument,       0, 'l'},
    {0,0,0,0}
  };

  try {
    int c, option_index;

    while((c = getopt_long(argc, argv, ":o:hfv:m::I:Ml", long_options, &option_index)) != -1) {
      switch (c) {
      case 1:
        version();
        return EXIT_SUCCESS;

      case 'h':
        usage();
        return EXIT_SUCCESS;

      case 'o':
        output = optarg;
        break;

      case 'f':
        formatoutput = true;
        break;

      case 'm':
        if (optarg)
          sourcemap_file = optarg;
        else
          sourcemap_file = "-";
        break;

      case 2:
        sourcemap_rootpath = path_create(optarg, std::strlen(optarg));
        break;

      case 3:
        sourcemap_basepath = path_create(optarg, std::strlen(optarg));
        break;

      case 'I':
        path_parse_list(optarg, includePaths);
        break;

      case 4:
        rootpath = path_create(optarg, std::strlen(optarg));
        break;

      case 'M':
        depends = true;
        break;

      case 'l':
        lint = true;
        break;

      default:
        cerr << "Unrecognized option. " << endl;
        usage();
        return EXIT_FAILURE;

      }
    }

    if (argc - optind >= 1) {

      source = new char[std::strlen(argv[optind]) + 1];
      std::strcpy(source, argv[optind]);

      in = new ifstream(source);
      if (in->fail() || in->bad())
        throw new IOException("Error opening file.");

    }  else {

      source = new char[2];
      std::strcpy(source, "-");

    }

    sources.push_back(source);

    if (parseInput(stylesheet, *in, source, sources, includePaths)) {
      if (depends) {
        writeDependencies(output, sources);
        return EXIT_SUCCESS;
      }

      if (!processStylesheet(stylesheet, css))
        return EXIT_FAILURE;

      if (lint)
        return EXIT_SUCCESS;

      writeOutput(css,
                  output,
                  formatoutput,
                  rootpath,
                  sources,
                  sourcemap_file,
                  sourcemap_rootpath,
                  sourcemap_basepath);
    } else
      return EXIT_FAILURE;
    delete [] source;

  } catch (IOException* e) {
    cerr << " Error: " << e->what() << endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<commit_msg>Adding --source-map-url option.<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <getopt.h>
#include <cstring>

#include <less/less/LessTokenizer.h>
#include <less/less/LessParser.h>
#include <less/css/CssWriter.h>
#include <less/css/CssPrettyWriter.h>
#include <less/stylesheet/Stylesheet.h>
#include <less/css/IOException.h>
#include <less/lessstylesheet/LessStylesheet.h>

using namespace std;

/**
 * /main Less CSS compiler, implemented in C++.
 *
 */

void usage () {
  cout <<
    "Usage: lessc [OPTION]... [FILE]\n"
    "\n"
    "   FILE				Less source file. If not given, source \
is read from stdin.\n"
    "   -h, --help			Show this message and exit.\n"
    "       --version		Print the program name and version.\n"
    "\n"
    "   -o, --output=<FILE>		Send output to FILE\n"
    "   -f, --format			Format output CSS with newlines and \
indentation. By default the output is unformatted.\n"
    "\n"
    "   -m, --source-map=[FILE]	Generate a source map.\n"
    "       --source-map-rootpath=<PATH>   PATH is prepended to the \
source file references in the source map. \n"
    "       --source-map-basepath=<PATH>   PATH is removed from the \
source file references in the source map.\n"
    "       --rootpath=<PATH>           Prefix PATH to urls and import \
statements in output. \n"
    "   -I, --include-path=<FILE>       Specify paths to look for \
imported .less files.\n"
    "\n"
    "Example:\n"
    "   lessc in.less -o out.css\n"
    "\n"
    "Report bugs to: " PACKAGE_BUGREPORT "\n"
    PACKAGE_NAME " home page: <" PACKAGE_URL ">\n";
}

void version () {
  cout <<
    PACKAGE_STRING "\n"
    "Copyright 2012 Bram van der Kroef\n"
    "License: MIT License\n";
}

/**
 * Copy a given path to a new string and add a trailing slash if necessary.
 */
char* path_create(const char* path, size_t len) {
  size_t newlen = len +
    (path[len - 1] != '/' ? 1 : 0);
  char* p = new char[newlen + 1];
  std::strncpy(p, path, len);
  p[newlen - 1] = '/';
  p[newlen] = '\0';
  return p;
}

void path_parse_list(const char* path, std::list<const char*>& paths) {
  const char* start = path;
  const char* end = path;
  size_t len;

  while((end = std::strchr(start, ':')) != NULL) {
    len = (end - start);
    // skip empty paths
    if (len > 0)
      paths.push_back(path_create(start, len));

    start = end + 1;
  }
  len = std::strlen(start);
  if (len > 0)
    paths.push_back(path_create(start, len));
}

char* path_create_relative(const char* path, const char* relative) {
  const char* p_root;
  const char* r_root;
  size_t desc_n;
  char* ret, *ret_p;

  // strip common directories
  while ((p_root = strchr(path, '/')) != NULL &&
         (r_root = strchr(relative, '/')) != NULL &&
         p_root - path == r_root - relative &&
         strncmp(path, relative, p_root - path) == 0) {
    path = p_root + 1;
    relative = r_root + 1;
  }

  // count how many folders to go up.
  for (desc_n = 0; relative != NULL; desc_n++) {
    relative = strchr(relative + 1, '/');
  }
  desc_n--;

  ret = new char[strlen(path) + 3 * desc_n + 1];
  ret_p = ret;
  while (desc_n > 0) {
    memcpy(ret_p, "../", 3);
    ret_p += 3;
    desc_n--;
  }

  strcpy(ret_p, path);
  return ret;
}

bool parseInput(LessStylesheet &stylesheet,
                istream &in,
                const char* source,
                std::list<const char*> &sources,
                std::list<const char*> &includePaths) {
  std::list<const char*>::iterator i;

  LessTokenizer tokenizer(in, source);
  LessParser parser(tokenizer, sources);
  parser.includePaths = &includePaths;

  try{
    parser.parseStylesheet(stylesheet);
  } catch(ParseException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what() << endl;

    return false;
  } catch(exception* e) {
    cerr << " Error: " << e->what() << endl;

    return false;
  }

  return true;
}

bool processStylesheet (LessStylesheet &stylesheet,
                        Stylesheet &css) {
  ProcessingContext context;

  try{
    stylesheet.process(css, context);

  } catch(ParseException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Parse Error: " << e->what() << endl;
    return false;

  } catch(ValueException* e) {

    cerr << e->getSource() << ": Line " << e->getLineNumber() << ", Column " <<
      e->getColumn() << " Error: " << e->what() << endl;
    return false;

  } catch(exception* e) {

    cerr << "Error: " << e->what() << endl;
    return false;
  }
  return true;
}

void writeOutput(Stylesheet &css,
                 const char* output,
                 bool formatoutput,
                 const char* rootpath,
                 std::list<const char*> &sources,
                 const char* sourcemap_file,
                 const char* sourcemap_rootpath,
                 const char* sourcemap_basepath,
                 const char* sourcemap_url) {
  ostream* out = &cout;
  CssWriter* writer;
  ostream* sourcemap_s = NULL;
  SourceMapWriter* sourcemap = NULL;
  char* tmp;
  std::list<const char*> relative_sources;
  std::list<const char*>::iterator it;
  size_t bp_l = 0;

  if (sourcemap_basepath != NULL)
    bp_l = strlen(sourcemap_basepath);

  if (strcmp(output, "-") != 0)
    out = new ofstream(output);

  if (sourcemap_file != NULL) {
    if (strcmp(sourcemap_file, "-") == 0) {
      if (strcmp(output, "-") == 0) {
        throw new IOException("source-map option requires that \
a file name is specified for either the source map or the css  \
output file.");
      } else {
        tmp = new char[strlen(output) + 5];
        sprintf(tmp, "%s.map", output);
        sourcemap_file = tmp;
      }
    }
    for (it = sources.begin(); it != sources.end(); it++) {
      if (sourcemap_basepath == NULL) {
        relative_sources.push_back(path_create_relative(*it, sourcemap_file));
      } else if (strncmp(*it, sourcemap_basepath, bp_l) == 0) {
        relative_sources.push_back(*it + bp_l);
      }
    }

    sourcemap_s = new ofstream(sourcemap_file);
    sourcemap = new SourceMapWriter(*sourcemap_s,
                                    sources,
                                    relative_sources,
                                    path_create_relative(output, sourcemap_file),
                                    sourcemap_rootpath);

    writer = formatoutput ? new CssPrettyWriter(*out, *sourcemap) :
      new CssWriter(*out, *sourcemap);
  } else {
    writer = formatoutput ? new CssPrettyWriter(*out) :
      new CssWriter(*out);
  }
  writer->rootpath = rootpath;

  css.write(*writer);

  if (sourcemap != NULL) {
    if (sourcemap_url != NULL)
      writer->writeSourceMapUrl(sourcemap_url);
    else
      writer->writeSourceMapUrl(path_create_relative(sourcemap_file, output));

    sourcemap->close();
    delete sourcemap;
    if (sourcemap_s != NULL)
      delete sourcemap_s;
  }

  delete writer;
  *out << endl;
}

void writeDependencies(const char* output, const std::list<const char*> &sources) {
  std::list<const char *>::const_iterator i;

  cout << output << ": ";

  for (i = sources.begin(); i != sources.end(); i++) {
    if (i != sources.begin())
      cout << ", ";
    cout << (*i);
  }
  cout << endl;
}

int main(int argc, char * argv[]){
  istream* in = &cin;
  bool formatoutput = false;
  char* source = NULL;
  const char* output = "-";
  LessStylesheet stylesheet;
  std::list<const char*> sources;
  Stylesheet css;
  bool depends = false, lint = false;

  const char* sourcemap_file = NULL;

  const char* sourcemap_rootpath = NULL;
  const char* sourcemap_basepath = NULL;
  const char* sourcemap_url = NULL;
  const char* rootpath = NULL;

  std::list<const char*> includePaths;

  static struct option long_options[] = {
    {"version",             no_argument,       0, 1},
    {"help",                no_argument,       0, 'h'},
    {"output",              required_argument, 0, 'o'},
    {"format",              no_argument,       0, 'f'},
    {"source-map",          optional_argument, 0, 'm'},
    {"source-map-rootpath", required_argument, 0, 2},
    {"source-map-basepath", required_argument, 0, 3},
    {"source-map-url",      required_argument, 0, 5},
    {"include-path",        required_argument, 0, 'I'},
    {"rootpath",            required_argument, 0, 4},
    {"depends",             no_argument,       0, 'M'},
    {"lint",                no_argument,       0, 'l'},
    {0,0,0,0}
  };

  try {
    int c, option_index;

    while((c = getopt_long(argc, argv, ":o:hfv:m::I:Ml", long_options, &option_index)) != -1) {
      switch (c) {
      case 1:
        version();
        return EXIT_SUCCESS;

      case 'h':
        usage();
        return EXIT_SUCCESS;

      case 'o':
        output = optarg;
        break;

      case 'f':
        formatoutput = true;
        break;

      case 'm':
        if (optarg)
          sourcemap_file = optarg;
        else
          sourcemap_file = "-";
        break;

      case 2:
        sourcemap_rootpath = path_create(optarg, std::strlen(optarg));
        break;

      case 3:
        sourcemap_basepath = path_create(optarg, std::strlen(optarg));
        break;

      case 5:
        sourcemap_url = path_create(optarg, std::strlen(optarg));
        break;

      case 'I':
        path_parse_list(optarg, includePaths);
        break;

      case 4:
        rootpath = path_create(optarg, std::strlen(optarg));
        break;

      case 'M':
        depends = true;
        break;

      case 'l':
        lint = true;
        break;

      default:
        cerr << "Unrecognized option. " << endl;
        usage();
        return EXIT_FAILURE;

      }
    }

    if (argc - optind >= 1) {

      source = new char[std::strlen(argv[optind]) + 1];
      std::strcpy(source, argv[optind]);

      in = new ifstream(source);
      if (in->fail() || in->bad())
        throw new IOException("Error opening file.");

    }  else {

      source = new char[2];
      std::strcpy(source, "-");

    }

    sources.push_back(source);

    if (parseInput(stylesheet, *in, source, sources, includePaths)) {
      if (depends) {
        writeDependencies(output, sources);
        return EXIT_SUCCESS;
      }

      if (!processStylesheet(stylesheet, css))
        return EXIT_FAILURE;

      if (lint)
        return EXIT_SUCCESS;

      writeOutput(css,
                  output,
                  formatoutput,
                  rootpath,
                  sources,
                  sourcemap_file,
                  sourcemap_rootpath,
                  sourcemap_basepath,
                  sourcemap_url);
    } else
      return EXIT_FAILURE;
    delete [] source;

  } catch (IOException* e) {
    cerr << " Error: " << e->what() << endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <typeinfo>
#include <cxxabi.h>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

static bool ZCM_DEBUG_ENABLED = (NULL != getenv("ZCM_DEBUG"));
#define ZCM_DEBUG(...) \
    do { \
        if (ZCM_DEBUG_ENABLED) \
            __ZCM_PRINT_OBFUSCATE__(std::cout, "ZCM-DEBUG: ", __VA_ARGS__, '\n'); \
    } while(0)

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(T* msg, uint64_t utime, void* usr);
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::mutex callbackLock;
    std::condition_variable callbackCv;
    T* callbackMsg = nullptr;
    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        std::unique_lock<std::mutex> lk(callbackLock);
        while (!done) {
            if (!callbackMsg) {
                callbackCv.wait(lk, [&](){ return callbackMsg != nullptr || done; });
                if (done) return;
            }
            onMsg(callbackMsg, getMsgUtime(callbackMsg), usr);
            // Intentionally not deleting callbackMsg as it is the
            // responsibility of the callback to delete the memory
            callbackMsg = nullptr;
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();

        if (callbackLock.try_lock()) {
            if (callbackMsg) delete callbackMsg;
            callbackMsg = new T(*_msg);
            callbackLock.unlock();
            callbackCv.notify_all();
        }
    }

    MessageTracker() {}

  public:
    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        if (hasUtime<T>::present == true) {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using 'utime' field of zcmtype ", name);
        } else {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using local system receive utime for ",
                      "tracking zcmtype ", name);
        }
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }

  private:
    // *****************************************************************************
    // Insanely hacky trick to determine at compile time if a zcmtype has a
    // field called "utime"
    template <typename F> struct hasUtime {
        struct Fallback { void* utime; }; // introduce member name "utime"
        struct Derived : F, Fallback {};

        template <typename C, C> struct ChT;

        template <typename C>
        static uint64_t _utime(ChT<void* Fallback::*, &C::utime>*, const F* msg)
        {
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
        };
        template <typename C>
        static uint64_t _utime(void*, ...)
        {
            va_list args;
            va_start(args, 1);
            const F* msg = va_arg(args, const F*);
            va_end(args);
            return msg->utime;
        }

        template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
        template<typename C> static char (&f(...))[2];

        static bool const present = sizeof(f<Derived>(0)) == 2;

        static uint64_t const utime(const F* msg)
        {
            return _utime<Derived>(0,msg);
        }
    };

    template<typename F>
    static inline std::string getType(const F t) { return typeid(t).name(); }

    static inline std::string demangle(std::string name)
    {
        int status = -4; // some arbitrary value to eliminate the compiler warning
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name.c_str(), NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }

    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o) { }

    template<typename First, typename ...Rest>
    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o, First && first, Rest && ...rest)
    {
        o << std::forward<First>(first);
        __ZCM_PRINT_OBFUSCATE__(o, std::forward<Rest>(rest)...);
    }
    // *****************************************************************************

};

#undef ZCM_DEBUG
<commit_msg>Namespaced message trackers<commit_after>#pragma once

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <typeinfo>
#include <cxxabi.h>
#include <sys/time.h>
#include <stdarg.h>

#include <zcm/zcm-cpp.hpp>
#include <zcm/util/circular.hpp>

static bool __ZCM_DEBUG_ENABLED__ = (NULL != getenv("ZCM_DEBUG"));
#define ZCM_DEBUG(...) \
    do { \
        if (__ZCM_DEBUG_ENABLED__) \
            __ZCM_PRINT_OBFUSCATE__(std::cout, "ZCM-DEBUG: ", __VA_ARGS__, '\n'); \
    } while(0)

namespace zcm {

template <typename T>
class MessageTracker
{
  public:
    typedef void (*callback)(T* msg, uint64_t utime, void* usr);
    static const bool NONBLOCKING = false;
    static const bool BLOCKING = true;

  protected:
    virtual uint64_t getMsgUtime(const T* msg)
    {
        return hasUtime<T>::utime(msg);
    }

    virtual T* interpolate(uint64_t utimeTarget,
                           const T* A, uint64_t utimeA,
                           const T* B, uint64_t utimeB)
    {
        return utimeTarget - utimeA < utimeB - utimeTarget ? new T(*A) : new T(*B);
    }

  private:
    zcm::ZCM* zcmLocal = nullptr;

    std::atomic_bool done {false};

    Circular<T> *buf;
    std::mutex bufLock;
    std::condition_variable newMsg;
    zcm::Subscription *s;

    std::mutex callbackLock;
    std::condition_variable callbackCv;
    T* callbackMsg = nullptr;
    std::thread *thr = nullptr;
    callback onMsg;
    void* usr;

    uint64_t maxTimeErr_us;

    void callbackThreadFunc()
    {
        std::unique_lock<std::mutex> lk(callbackLock);
        while (!done) {
            if (!callbackMsg) {
                callbackCv.wait(lk, [&](){ return callbackMsg != nullptr || done; });
                if (done) return;
            }
            onMsg(callbackMsg, getMsgUtime(callbackMsg), usr);
            // Intentionally not deleting callbackMsg as it is the
            // responsibility of the callback to delete the memory
            callbackMsg = nullptr;
        }
    }

    void handle(const zcm::ReceiveBuffer* rbuf, const std::string& chan, const T* _msg)
    {
        if (done)
            return;

        T* tmp = new T(*_msg);

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (buf->isFull())
                buf->removeFront();

            while (!buf->isEmpty()) {
                if (getMsgUtime(buf->front()) + maxTimeErr_us > getMsgUtime(_msg))
                    break;
                buf->removeFront();
            }

            buf->pushBack(tmp);
        }
        newMsg.notify_all();

        if (callbackLock.try_lock()) {
            if (callbackMsg) delete callbackMsg;
            callbackMsg = new T(*_msg);
            callbackLock.unlock();
            callbackCv.notify_all();
        }
    }

    MessageTracker() {}

  public:
    MessageTracker(zcm::ZCM* zcmLocal, std::string channel,
                   uint64_t maxTimeErr_us = 0.25e6, size_t maxMsgs = 1,
                   callback onMsg = nullptr, void* usr = nullptr)
        : zcmLocal(zcmLocal), maxTimeErr_us(maxTimeErr_us), onMsg(onMsg), usr(usr)
    {
        if (hasUtime<T>::present == true) {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using 'utime' field of zcmtype ", name);
        } else {
            T tmp;
            std::string name = demangle(getType(tmp));
            ZCM_DEBUG("Message trackers using local system receive utime for ",
                      "tracking zcmtype ", name);
        }
        buf = new Circular<T>(maxMsgs);
        if (onMsg != nullptr)
            thr = new std::thread(&MessageTracker<T>::callbackThreadFunc, this);
        s = zcmLocal->subscribe(channel, &MessageTracker<T>::handle, this);
    }

    virtual ~MessageTracker()
    {
        zcmLocal->unsubscribe(s);
        done = true;
        newMsg.notify_all();
        if (thr) {
            thr->join();
            delete thr;
        }
        while (!buf->isEmpty())
            buf->removeFront();
        delete buf;
    }

    // You must free the memory returned here
    virtual T* get(bool blocking = NONBLOCKING)
    {
        T* ret = nullptr;

        {
            std::unique_lock<std::mutex> lk(bufLock);
            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }
            if (!buf->isEmpty())
                ret = new T(*buf->back());
        }

        return ret;
    }

    virtual T* get(uint64_t utime, bool blocking = NONBLOCKING)
    {
        T *m0 = nullptr, *m1 = nullptr; // two poses bracketing the desired utime
        uint64_t m0Utime, m1Utime;

        {
            std::unique_lock<std::mutex> lk(bufLock);

            if (blocking == BLOCKING) {
                if (buf->isEmpty())
                    newMsg.wait(lk, [&]{ return !buf->isEmpty() || done; });
                if (done) return nullptr;
            }

            size_t size = buf->size();

            const T *_m0 = nullptr;
            const T *_m1 = nullptr;

            for (size_t i = 0; i < size; ++i) {
                const T* m = (*buf)[i];
                uint64_t mUtime = getMsgUtime(m);

                if (mUtime <= utime && (_m0 == nullptr || mUtime > m0Utime)) {
                    _m0 = m;
                    m0Utime = getMsgUtime(_m0);
                }

                if (mUtime >= utime && (_m1 == nullptr || mUtime < m1Utime)) {
                    _m1 = m;
                    m1Utime = getMsgUtime(_m1);
                }
            }

            if (_m0 != nullptr)
                m0 = new T(*_m0);

            if (_m1 != nullptr)
                m1 = new T(*_m1);

        }

        if (m0 && utime - m0Utime > maxTimeErr_us) {
            delete m0;
            m0 = nullptr;
        }

        if (m1 && m1Utime - utime > maxTimeErr_us) {
            delete m1;
            m1 = nullptr;
        }

        if (m0 && m1) {
            if (m0Utime == m1Utime) {
                delete m1;
                return m0;
            }

            T* elt = interpolate(utime, m0, m0Utime, m1, m1Utime);

            delete m0;
            delete m1;

            return elt;
        }

        if (m0) return m0;
        if (m1) return m1;

        return nullptr;
    }

  private:
    // *****************************************************************************
    // Insanely hacky trick to determine at compile time if a zcmtype has a
    // field called "utime"
    template <typename F> struct hasUtime {
        struct Fallback { void* utime; }; // introduce member name "utime"
        struct Derived : F, Fallback {};

        template <typename C, C> struct ChT;

        template <typename C>
        static uint64_t _utime(ChT<void* Fallback::*, &C::utime>*, const F* msg)
        {
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
        };
        template <typename C>
        static uint64_t _utime(void*, ...)
        {
            va_list args;
            va_start(args, 1);
            const F* msg = va_arg(args, const F*);
            va_end(args);
            return msg->utime;
        }

        template<typename C> static char (&f(ChT<int Fallback::*, &C::x>*))[1];
        template<typename C> static char (&f(...))[2];

        static bool const present = sizeof(f<Derived>(0)) == 2;

        static uint64_t const utime(const F* msg)
        {
            return _utime<Derived>(0,msg);
        }
    };

    template<typename F>
    static inline std::string getType(const F t) { return typeid(t).name(); }

    static inline std::string demangle(std::string name)
    {
        int status = -4; // some arbitrary value to eliminate the compiler warning
        std::unique_ptr<char, void(*)(void*)> res {
            abi::__cxa_demangle(name.c_str(), NULL, NULL, &status),
            std::free
        };
        return (status==0) ? res.get() : name ;
    }

    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o) { }

    template<typename First, typename ...Rest>
    static void __ZCM_PRINT_OBFUSCATE__(std::ostream& o, First && first, Rest && ...rest)
    {
        o << std::forward<First>(first);
        __ZCM_PRINT_OBFUSCATE__(o, std::forward<Rest>(rest)...);
    }
    // *****************************************************************************

};

}

#undef ZCM_DEBUG
<|endoftext|>


<commit_before>
#include "text.h"
#include <gl/vertex_buffer_data.h>
#include <gl/element_buffer_data.h>

namespace draw
{

std::map<std::shared_ptr<script::font>, text::GlyphPack> text::_font_glyph_cache;

////////////////////////////////////////

text::text( const std::shared_ptr<script::font> &font )
	: _font( font )
{
}

////////////////////////////////////////

void text::set_text( const std::string &utf8 )
{
	_update = true;
	_utf8 = utf8;
}

////////////////////////////////////////

void text::set_position( const gl::vec2 &p )
{
	_update = true;
	_pos = p;
}

////////////////////////////////////////

void text::set_color( const gl::color &c )
{
	_update = true;
	_color = c;
}

////////////////////////////////////////

void text::render( const gl::matrix4 &ortho )
{
	if ( _update )
		update();
	if ( _mesh.valid() )
	{
		auto x = _font_glyph_cache.find( _font );
		if ( x != _font_glyph_cache.end() )
		{
			std::shared_ptr<gl::texture> texture = x->second.texture;

			gl::matrix4 local = gl::matrix4::translation( _pos[0], _pos[1] );
			gl::api ogl;
			ogl.enable( gl::capability::BLEND );
			ogl.blend_func( gl::blend_style::SRC_ALPHA, gl::blend_style::ONE_MINUS_SRC_ALPHA );

			auto txt = texture->bind();

			auto b = _mesh.bind();
			b.set_uniform( _mat_pos, local * ortho );
			b.set_uniform( _col_pos, _color );
			b.set_uniform( _tex_pos, static_cast<int>( txt.unit() ) );
			b.draw();

			ogl.disable( gl::capability::BLEND );
		}
	}
}

////////////////////////////////////////

void text::update( void )
{
	_mesh.clear();
	if ( !_font || _utf8.empty() )
		return;

	_mesh = gl::mesh();
	// Create the geometry (with texture coordinates) for the text.
	gl::vertex_buffer_data<gl::vec2,gl::vec2> coords;
	gl::element_buffer_data tris;
	{
		auto add_point = [&]( float cx, float cy, float tx, float ty )
		{
			coords.push_back( { cx, cy }, { tx, ty } );
		};

		auto add_tri = [&]( size_t a, size_t b, size_t c )
		{
			tris.push_back( a, b, c );
		};

		auto reset = [&]( void )
		{
			coords.clear();
			tris.clear();
		};
		_font->render( add_point, add_tri, reset, base::point( 0.0, 0.0 ), _utf8 );
	}

	// Update the font texture if needed.
	auto x = _font_glyph_cache.find( _font );
	uint32_t curVer = _font->glyph_version();

	gl::api ogl;
	std::shared_ptr<gl::texture> texture;

	bool storeTex = true;
	if ( x != _font_glyph_cache.end() )
	{
		GlyphPack &pk = x->second;
		storeTex = pk.version != curVer;
		texture = pk.texture;
	}
	else
	{
		texture = ogl.new_texture( gl::texture::target::IMAGE_2D );
	}

	auto txt = texture->bind();

	if ( storeTex )
	{
		txt.set_wrapping( gl::wrapping::CLAMP_TO_EDGE );
//		txt.set_filters( gl::filter::NEAREST, gl::filter::NEAREST );
		txt.set_filters( gl::filter::LINEAR, gl::filter::LINEAR );
		txt.image_2d_red( gl::format::RED,
						  _font->bitmap_width(),
						  _font->bitmap_height(),
						  gl::image_type::UNSIGNED_BYTE,
						  _font->bitmap().data() );
		_font_glyph_cache[_font] = { _font->glyph_version(), texture };
	}

	_mesh.get_program().set(
		ogl.new_vertex_shader( R"SHADER(
#version 330
layout(location = 0) in vec2 vertex_pos;
layout(location = 1) in vec2 char_pos;
uniform mat4 matrix;
out vec2 tex_pos;
void main()
{
	tex_pos = char_pos;
	gl_Position = matrix * vec4( vertex_pos, 0.0, 1.0 );
}
)SHADER" ),
		ogl.new_fragment_shader( R"SHADER(
#version 330
in vec2 tex_pos;
out vec4 frag_color;
uniform vec4 color;
uniform sampler2D textTex;
void main()
{
	vec4 texColor = texture2D( textTex, tex_pos );
	frag_color = vec4( color.r, color.g, color.b, color.a * texColor.r );
}
)SHADER" )
							);

	{
		auto tbind = _mesh.bind();
		tbind.vertex_attribute( "vertex_pos", coords, 0 );
		tbind.vertex_attribute( "char_pos", coords, 1 );
		tbind.set_elements( tris );

		_mesh.add_triangles( tris.size() );
	}
	_mat_pos = _mesh.get_uniform_location( "matrix" );
	_col_pos = _mesh.get_uniform_location( "color" );
	_tex_pos = _mesh.get_uniform_location( "textTex" );
	_update = false;
/*
	if ( ! _text_program )
		_text_program = program( "text.vert", "text_bitmap.frag" );
	checkgl();

	use_program( _text_program );
	checkgl();

	auto ta = _text_array->bind();
	checkgl();

	enable( gl::capability::BLEND );
	blend_func( gl::blend_style::SRC_ALPHA, gl::blend_style::ONE_MINUS_SRC_ALPHA );

	ta.attrib_pointer( _text_program->get_attribute_location( "text_tex_coords" ),
					   _text_texture_vertices, _text_texcoord_buf, 2 );
	ta.attrib_pointer( _text_program->get_attribute_location( "text_out_coords" ),
					   _text_output_vertices, _text_coord_buf, 2 );
	_text_program->set_uniform( "text_tex", GLint(0) );
	_text_program->set_uniform( "color", c.get_fill_color() );
	_text_program->set_uniform( "mvp_matrix", current_matrix() );

	auto idc = _text_indices->bind( gl::buffer<uint16_t>::target::ELEMENT_ARRAY_BUFFER );

	idc.data( _text_idx_buf, gl::usage::STATIC_DRAW );
	idc.draw( gl::primitive::TRIANGLES, _text_idx_buf.size() );
//	ta.draw_indices( gl::primitive::TRIANGLES, _text_idx_buf );
	// is this safe in GL ES? It's fine for normal OpenGL, and is fewer indices...
//	ta.draw_indices( gl::primitive::QUADS, _text_idx_buf );
	checkgl();

	disable( gl::capability::BLEND );
	*/
}

////////////////////////////////////////

}

<commit_msg>don't use old function names in opengl 3.3<commit_after>
#include "text.h"
#include <gl/vertex_buffer_data.h>
#include <gl/element_buffer_data.h>

namespace draw
{

std::map<std::shared_ptr<script::font>, text::GlyphPack> text::_font_glyph_cache;

////////////////////////////////////////

text::text( const std::shared_ptr<script::font> &font )
	: _font( font )
{
}

////////////////////////////////////////

void text::set_text( const std::string &utf8 )
{
	_update = true;
	_utf8 = utf8;
}

////////////////////////////////////////

void text::set_position( const gl::vec2 &p )
{
	_update = true;
	_pos = p;
}

////////////////////////////////////////

void text::set_color( const gl::color &c )
{
	_update = true;
	_color = c;
}

////////////////////////////////////////

void text::render( const gl::matrix4 &ortho )
{
	if ( _update )
		update();
	if ( _mesh.valid() )
	{
		auto x = _font_glyph_cache.find( _font );
		if ( x != _font_glyph_cache.end() )
		{
			std::shared_ptr<gl::texture> texture = x->second.texture;

			gl::matrix4 local = gl::matrix4::translation( _pos[0], _pos[1] );
			gl::api ogl;
			ogl.enable( gl::capability::BLEND );
			ogl.blend_func( gl::blend_style::SRC_ALPHA, gl::blend_style::ONE_MINUS_SRC_ALPHA );

			auto txt = texture->bind();

			auto b = _mesh.bind();
			b.set_uniform( _mat_pos, local * ortho );
			b.set_uniform( _col_pos, _color );
			b.set_uniform( _tex_pos, static_cast<int>( txt.unit() ) );
			b.draw();

			ogl.disable( gl::capability::BLEND );
		}
	}
}

////////////////////////////////////////

void text::update( void )
{
	_mesh.clear();
	if ( !_font || _utf8.empty() )
		return;

	_mesh = gl::mesh();
	// Create the geometry (with texture coordinates) for the text.
	gl::vertex_buffer_data<gl::vec2,gl::vec2> coords;
	gl::element_buffer_data tris;
	{
		auto add_point = [&]( float cx, float cy, float tx, float ty )
		{
			coords.push_back( { cx, cy }, { tx, ty } );
		};

		auto add_tri = [&]( size_t a, size_t b, size_t c )
		{
			tris.push_back( a, b, c );
		};

		auto reset = [&]( void )
		{
			coords.clear();
			tris.clear();
		};
		_font->render( add_point, add_tri, reset, base::point( 0.0, 0.0 ), _utf8 );
	}

	// Update the font texture if needed.
	auto x = _font_glyph_cache.find( _font );
	uint32_t curVer = _font->glyph_version();

	gl::api ogl;
	std::shared_ptr<gl::texture> texture;

	bool storeTex = true;
	if ( x != _font_glyph_cache.end() )
	{
		GlyphPack &pk = x->second;
		storeTex = pk.version != curVer;
		texture = pk.texture;
	}
	else
	{
		texture = ogl.new_texture( gl::texture::target::IMAGE_2D );
	}

	auto txt = texture->bind();

	if ( storeTex )
	{
		txt.set_wrapping( gl::wrapping::CLAMP_TO_EDGE );
//		txt.set_filters( gl::filter::NEAREST, gl::filter::NEAREST );
		txt.set_filters( gl::filter::LINEAR, gl::filter::LINEAR );
		txt.image_2d_red( gl::format::RED,
						  _font->bitmap_width(),
						  _font->bitmap_height(),
						  gl::image_type::UNSIGNED_BYTE,
						  _font->bitmap().data() );
		_font_glyph_cache[_font] = { _font->glyph_version(), texture };
	}

	_mesh.get_program().set(
		ogl.new_vertex_shader( R"SHADER(
#version 330
layout(location = 0) in vec2 vertex_pos;
layout(location = 1) in vec2 char_pos;
uniform mat4 matrix;
out vec2 tex_pos;
void main()
{
	tex_pos = char_pos;
	gl_Position = matrix * vec4( vertex_pos, 0.0, 1.0 );
}
)SHADER" ),
		ogl.new_fragment_shader( R"SHADER(
#version 330
in vec2 tex_pos;
out vec4 frag_color;
uniform vec4 color;
uniform sampler2D textTex;
void main()
{
	vec4 texColor = texture( textTex, tex_pos );
	frag_color = vec4( color.r, color.g, color.b, color.a * texColor.r );
}
)SHADER" )
							);

	{
		auto tbind = _mesh.bind();
		tbind.vertex_attribute( "vertex_pos", coords, 0 );
		tbind.vertex_attribute( "char_pos", coords, 1 );
		tbind.set_elements( tris );

		_mesh.add_triangles( tris.size() );
	}
	_mat_pos = _mesh.get_uniform_location( "matrix" );
	_col_pos = _mesh.get_uniform_location( "color" );
	_tex_pos = _mesh.get_uniform_location( "textTex" );
	_update = false;
/*
	if ( ! _text_program )
		_text_program = program( "text.vert", "text_bitmap.frag" );
	checkgl();

	use_program( _text_program );
	checkgl();

	auto ta = _text_array->bind();
	checkgl();

	enable( gl::capability::BLEND );
	blend_func( gl::blend_style::SRC_ALPHA, gl::blend_style::ONE_MINUS_SRC_ALPHA );

	ta.attrib_pointer( _text_program->get_attribute_location( "text_tex_coords" ),
					   _text_texture_vertices, _text_texcoord_buf, 2 );
	ta.attrib_pointer( _text_program->get_attribute_location( "text_out_coords" ),
					   _text_output_vertices, _text_coord_buf, 2 );
	_text_program->set_uniform( "text_tex", GLint(0) );
	_text_program->set_uniform( "color", c.get_fill_color() );
	_text_program->set_uniform( "mvp_matrix", current_matrix() );

	auto idc = _text_indices->bind( gl::buffer<uint16_t>::target::ELEMENT_ARRAY_BUFFER );

	idc.data( _text_idx_buf, gl::usage::STATIC_DRAW );
	idc.draw( gl::primitive::TRIANGLES, _text_idx_buf.size() );
//	ta.draw_indices( gl::primitive::TRIANGLES, _text_idx_buf );
	// is this safe in GL ES? It's fine for normal OpenGL, and is fewer indices...
//	ta.draw_indices( gl::primitive::QUADS, _text_idx_buf );
	checkgl();

	disable( gl::capability::BLEND );
	*/
}

////////////////////////////////////////

}

<|endoftext|>


<commit_before>#include <type_traits>
#include <algorithm>

#include "Tools/Exception/exception.hpp"

#include "Modem_optical.hpp"

using namespace aff3ct;
using namespace aff3ct::module;

template <typename B, typename R, typename Q>
Modem_optical<B,R,Q>
::Modem_optical(const int N,
                tools::User_pdf_noise_generator<R> *noise_generator_p0,
                tools::User_pdf_noise_generator<R> *noise_generator_p1,
                const R ROP,
                const int n_frames)
: Modem<B,R,Q>(N, (R)-1, n_frames),
  noise_generator_p0(noise_generator_p0),
  noise_generator_p1(noise_generator_p1)
{
	const std::string name = "Modem_optical";
	this->set_name(name);

	this->set_sigma(ROP);

	if (noise_generator_p0 == nullptr)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "'noise_generator_p0' can't be NULL.");

	if (noise_generator_p1 == nullptr)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "'noise_generator_p1' can't be NULL.");
}

template <typename B, typename R, typename Q>
Modem_optical<B,R,Q>
::~Modem_optical()
{
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::set_sigma(const R ROP)
{
	this->rop = ROP;
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::_modulate(const B *X_N1, R *X_N2, const int frame_id)
{
	auto size = (unsigned int)(this->N);
	for (unsigned i = 0; i < size; i++)
		X_N2[i] = X_N1[i] ? (R)1 : (R)0;
}

template <typename B,typename R, typename Q>
void Modem_optical<B,R,Q>
::_filter(const R *Y_N1, R *Y_N2, const int frame_id)
{
	std::copy(Y_N1, Y_N1 + this->N_fil, Y_N2);
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::_demodulate(const Q *Y_N1, Q *Y_N2, const int frame_id)
{
	if (!std::is_same<R,Q>::value)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (!std::is_floating_point<Q>::value)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	const Q min_value = 1e-10; // when prob_1 ou prob_0 = 0;

	auto dist0  = noise_generator_p0->get_distribution(this->rop);
	auto pdf_x0 = dist0->get_pdf_x();
	auto pdf_y0 = dist0->get_pdf_y();

	auto dist1 = noise_generator_p1->get_distribution(this->rop);
	// auto pdf_x1 = dist1->get_pdf_x(); // shall be same than pdf_x0
	auto pdf_y1 = dist1->get_pdf_y();

	unsigned x0_pos;
	for (auto i = 0; i < this->N_fil; i++)
	{
		// find the position of the first x that is above the receiver val
		auto x0_above = std::lower_bound(pdf_x0.begin(), pdf_x0.end(), Y_N1[i]);

		if (x0_above == pdf_x0.end()) // if last
			x0_pos = pdf_x0.size() - 1;
		else if (x0_above == pdf_x0.begin()) // if first
			x0_pos = 0;
		else
		{
			x0_pos = std::distance(pdf_x0.begin(), x0_above);

			auto x0_below = x0_above - 1;

			// find which between x_below and x_above is the nearest of Y_N1[i]
			x0_pos = (Y_N1[i] - *x0_below) < (Y_N1[i] - *x0_above) ? x0_pos - 1 : x0_pos;
		}

		// then get the matching probabilities
		auto prob_0 = pdf_y0[x0_pos] == (Q)0 ? min_value : pdf_y0[x0_pos];
		auto prob_1 = pdf_y1[x0_pos] == (Q)0 ? min_value : pdf_y1[x0_pos]; // pdf_x1 shall be same than pdf_x0

		Y_N2[i] = std::log(prob_0/prob_1);
	}
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template class aff3ct::module::Modem_optical<B_8,R_8,R_8>;
template class aff3ct::module::Modem_optical<B_8,R_8,Q_8>;
template class aff3ct::module::Modem_optical<B_16,R_16,R_16>;
template class aff3ct::module::Modem_optical<B_16,R_16,Q_16>;
template class aff3ct::module::Modem_optical<B_32,R_32,R_32>;
template class aff3ct::module::Modem_optical<B_64,R_64,R_64>;
#else
template class aff3ct::module::Modem_optical<B,R,Q>;
#if !defined(PREC_32_BIT) && !defined(PREC_64_BIT)
template class aff3ct::module::Modem_optical<B,R,R>;
#endif
#endif
// ==================================================================================== explicit template instantiation
<commit_msg>Optimize Modem optical modulation with mipp<commit_after>#include <type_traits>
#include <algorithm>
#include <mipp.h>

#include "Tools/Exception/exception.hpp"

#include "Modem_optical.hpp"

using namespace aff3ct;
using namespace aff3ct::module;

template <typename B, typename R, typename Q>
Modem_optical<B,R,Q>
::Modem_optical(const int N,
                tools::User_pdf_noise_generator<R> *noise_generator_p0,
                tools::User_pdf_noise_generator<R> *noise_generator_p1,
                const R ROP,
                const int n_frames)
: Modem<B,R,Q>(N, (R)-1, n_frames),
  noise_generator_p0(noise_generator_p0),
  noise_generator_p1(noise_generator_p1)
{
	const std::string name = "Modem_optical";
	this->set_name(name);

	this->set_sigma(ROP);

	if (noise_generator_p0 == nullptr)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "'noise_generator_p0' can't be NULL.");

	if (noise_generator_p1 == nullptr)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "'noise_generator_p1' can't be NULL.");
}

template <typename B, typename R, typename Q>
Modem_optical<B,R,Q>
::~Modem_optical()
{
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::set_sigma(const R ROP)
{
	this->rop = ROP;
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::_modulate(const B *X_N1, R *X_N2, const int frame_id)
{
	for (int i = 0; i < this->N; i++)
		X_N2[i] = X_N1[i] ? (R)1 : (R)0;
}

namespace aff3ct
{
namespace module
{
template <>
void Modem_optical<int,float,float>
::_modulate(const int *X_N1, float *X_N2, const int frame_id)
{
	using B = int;
	using R = float;

	unsigned size = (unsigned int)(this->N);

	const auto vec_loop_size = (size / mipp::nElReg<B>()) * mipp::nElReg<B>();
	const mipp::Reg<R> Rone  = (R)1.0;
	const mipp::Reg<R> Rzero = (R)0.0;
	const mipp::Reg<B> Bzero = (B)0;

	for (unsigned i = 0; i < vec_loop_size; i += mipp::nElReg<B>())
	{
		const auto x1b = mipp::Reg<B>(&X_N1[i]);
		const auto x2r = mipp::blend(Rone, Rzero, x1b != Bzero);
		x2r.store(&X_N2[i]);
	}

	for (unsigned i = vec_loop_size; i < size; i++)
		X_N2[i] = X_N1[i] ? (R)1 : (R)0;
}
}
}

template <typename B,typename R, typename Q>
void Modem_optical<B,R,Q>
::_filter(const R *Y_N1, R *Y_N2, const int frame_id)
{
	std::copy(Y_N1, Y_N1 + this->N_fil, Y_N2);
}

template <typename B, typename R, typename Q>
void Modem_optical<B,R,Q>
::_demodulate(const Q *Y_N1, Q *Y_N2, const int frame_id)
{
	if (!std::is_same<R,Q>::value)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'R' and 'Q' have to be the same.");

	if (!std::is_floating_point<Q>::value)
		throw tools::invalid_argument(__FILE__, __LINE__, __func__, "Type 'Q' has to be float or double.");

	const Q min_value = 1e-10; // when prob_1 ou prob_0 = 0;

	auto dist0  = noise_generator_p0->get_distribution(this->rop);
	auto pdf_x0 = dist0->get_pdf_x();
	auto pdf_y0 = dist0->get_pdf_y();

	auto dist1 = noise_generator_p1->get_distribution(this->rop);
	// auto pdf_x1 = dist1->get_pdf_x(); // shall be same than pdf_x0
	auto pdf_y1 = dist1->get_pdf_y();

	unsigned x0_pos;
	for (auto i = 0; i < this->N_fil; i++)
	{
		// find the position of the first x that is above the receiver val
		auto x0_above = std::lower_bound(pdf_x0.begin(), pdf_x0.end(), Y_N1[i]);

		if (x0_above == pdf_x0.end()) // if last
			x0_pos = pdf_x0.size() - 1;
		else if (x0_above == pdf_x0.begin()) // if first
			x0_pos = 0;
		else
		{
			x0_pos = std::distance(pdf_x0.begin(), x0_above);

			auto x0_below = x0_above - 1;

			// find which between x_below and x_above is the nearest of Y_N1[i]
			x0_pos = (Y_N1[i] - *x0_below) < (Y_N1[i] - *x0_above) ? x0_pos - 1 : x0_pos;
		}

		// then get the matching probabilities
		auto prob_0 = pdf_y0[x0_pos] == (Q)0 ? min_value : pdf_y0[x0_pos];
		auto prob_1 = pdf_y1[x0_pos] == (Q)0 ? min_value : pdf_y1[x0_pos]; // pdf_x1 shall be same than pdf_x0

		Y_N2[i] = std::log(prob_0/prob_1);
	}
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template class aff3ct::module::Modem_optical<B_8,R_8,R_8>;
template class aff3ct::module::Modem_optical<B_8,R_8,Q_8>;
template class aff3ct::module::Modem_optical<B_16,R_16,R_16>;
template class aff3ct::module::Modem_optical<B_16,R_16,Q_16>;
template class aff3ct::module::Modem_optical<B_32,R_32,R_32>;
template class aff3ct::module::Modem_optical<B_64,R_64,R_64>;
#else
template class aff3ct::module::Modem_optical<B,R,Q>;
#if !defined(PREC_32_BIT) && !defined(PREC_64_BIT)
template class aff3ct::module::Modem_optical<B,R,R>;
#endif
#endif
// ==================================================================================== explicit template instantiation
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "ServerLoad.h"

#include <cassert>

namespace facebook {
namespace memcache {

namespace {

// Constant used to convert from raw load to percent load.
constexpr uint32_t kPercentLoadNormalizer = 10e4; // 10,000
constexpr uint32_t kMaxRawLoad = kPercentLoadNormalizer * 100;

} // anonymous namespace

ServerLoad::ServerLoad(uint32_t rawLoad) noexcept : load_(rawLoad) {
  assert(load_ <= kMaxRawLoad);
}

/* static */
ServerLoad ServerLoad::fromPercentLoad(double percentLoad) noexcept {
  constexpr double kEpsilon = 1e-6;

  assert(percentLoad > (0.0 - kEpsilon));
  assert(percentLoad < (100.0 + kEpsilon));

  uint32_t rawLoad;
  if (percentLoad < (0.0 + kEpsilon)) {
    rawLoad = 0;
  } else if (percentLoad > (100.0 - kEpsilon)) {
    rawLoad = kMaxRawLoad;
  } else {
    rawLoad = static_cast<uint32_t>(percentLoad * kPercentLoadNormalizer);
  }

  return ServerLoad(rawLoad);
}

/* static */
const ServerLoad ServerLoad::zero() noexcept {
  static const ServerLoad emptyServerLoad(0);
  return emptyServerLoad;
}

double ServerLoad::percentLoad() const noexcept {
  return static_cast<double>(load_) / kPercentLoadNormalizer;
}

} // memcache
} // facebook
<commit_msg>Fix crash in ServerLoad on garbage data<commit_after>/*
 *  Copyright (c) 2017, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "ServerLoad.h"

#include <cassert>

namespace facebook {
namespace memcache {

namespace {

// Constant used to convert from raw load to percent load.
constexpr uint32_t kPercentLoadNormalizer = 10e4; // 10,000
constexpr uint32_t kMaxRawLoad = kPercentLoadNormalizer * 100;

} // anonymous namespace

ServerLoad::ServerLoad(uint32_t rawLoad) noexcept
    : load_(rawLoad > kMaxRawLoad ? 0 : rawLoad) {}

/* static */
ServerLoad ServerLoad::fromPercentLoad(double percentLoad) noexcept {
  constexpr double kEpsilon = 1e-6;

  assert(percentLoad > (0.0 - kEpsilon));
  assert(percentLoad < (100.0 + kEpsilon));

  uint32_t rawLoad;
  if (percentLoad < (0.0 + kEpsilon)) {
    rawLoad = 0;
  } else if (percentLoad > (100.0 - kEpsilon)) {
    rawLoad = kMaxRawLoad;
  } else {
    rawLoad = static_cast<uint32_t>(percentLoad * kPercentLoadNormalizer);
  }

  return ServerLoad(rawLoad);
}

/* static */
const ServerLoad ServerLoad::zero() noexcept {
  static const ServerLoad emptyServerLoad(0);
  return emptyServerLoad;
}

double ServerLoad::percentLoad() const noexcept {
  return static_cast<double>(load_) / kPercentLoadNormalizer;
}

} // memcache
} // facebook
<|endoftext|>


<commit_before>#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_Count.hh>
#include <qpdf/Pl_Discard.hh>
#include <stdlib.h>

typedef unsigned char* uc;

int main()
{
    try
    {
	Pl_Discard discard;
	Pl_Count count("count", &discard);
	Pl_Buffer bp1("bp1", &count);
	bp1.write((uc)"12345", 5);
	bp1.write((uc)"67890", 5);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	bp1.write((uc)"abcde", 5);
	bp1.write((uc)"fghij", 6);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	Buffer* b = bp1.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;
	bp1.write((uc)"qwert", 5);
	bp1.write((uc)"yuiop", 6);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	b = bp1.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;

	Pl_Buffer bp2("bp2");
	bp2.write((uc)"moo", 3);
	bp2.write((uc)"quack", 6);
	try
	{
	    delete bp2.getBuffer();
	}
	catch (std::exception& e)
	{
	    std::cout << e.what() << std::endl;
	}
	bp2.finish();
	b = bp2.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;
    }
    catch (std::exception& e)
    {
	std::cout << "unexpected exception: " << e.what() << std::endl;
	exit(2);
    }

    std::cout << "done" << std::endl;
    return 0;
}
<commit_msg>add test case to buffer test suite<commit_after>#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_Count.hh>
#include <qpdf/Pl_Discard.hh>
#include <stdlib.h>
#include <stdexcept>

typedef unsigned char* uc;

int main()
{
    try
    {
	Pl_Discard discard;
	Pl_Count count("count", &discard);
	Pl_Buffer bp1("bp1", &count);
	bp1.write((uc)"12345", 5);
	bp1.write((uc)"67890", 5);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	bp1.write((uc)"abcde", 5);
	bp1.write((uc)"fghij", 6);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	Buffer* b = bp1.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;
	bp1.write((uc)"qwert", 5);
	bp1.write((uc)"yuiop", 6);
	bp1.finish();
	std::cout << "count: " << count.getCount() << std::endl;
	b = bp1.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;

	Pl_Buffer bp2("bp2");
	bp2.write((uc)"moo", 3);
	bp2.write((uc)"quack", 6);
	try
	{
	    delete bp2.getBuffer();
	}
	catch (std::exception& e)
	{
	    std::cout << e.what() << std::endl;
	}
	bp2.finish();
	b = bp2.getBuffer();
	std::cout << "size: " << b->getSize() << std::endl;
	std::cout << "data: " << b->getBuffer() << std::endl;
	delete b;

	unsigned char lbuf[10];
	Buffer b1(lbuf, 10);
	if (! ((b1.getBuffer() == lbuf) &&
	       (b1.getSize() == 10)))
	{
	    throw std::logic_error("hand-created buffer is not as expected");
	}
    }
    catch (std::exception& e)
    {
	std::cout << "unexpected exception: " << e.what() << std::endl;
	exit(2);
    }

    std::cout << "done" << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>/*
 * A auto-growing buffer you can write to.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "growing_buffer.hxx"
#include "pool.hxx"
#include "util/ConstBuffer.hxx"
#include "util/WritableBuffer.hxx"

#include <assert.h>
#include <string.h>

struct buffer {
    struct buffer *next;
    size_t length;
    char data[sizeof(size_t)];
};

struct GrowingBuffer {
    struct pool *pool;

#ifndef NDEBUG
    size_t initial_size;
#endif

    size_t size;
    struct buffer *current, *tail, first;
};

GrowingBuffer *gcc_malloc
growing_buffer_new(struct pool *pool, size_t initial_size)
{
    GrowingBuffer *gb = (GrowingBuffer *)
        p_malloc(pool, sizeof(*gb) - sizeof(gb->first.data) + initial_size);

    gb->pool = pool;

#ifndef NDEBUG
    gb->initial_size = initial_size;
#endif

    gb->size = initial_size;
    gb->current = &gb->first;
    gb->tail = &gb->first;
    gb->first.next = nullptr;
    gb->first.length = 0;

    return gb;
}

static void
growing_buffer_append_buffer(GrowingBuffer *gb, struct buffer *buffer)
{
    assert(gb != nullptr);
    assert(buffer != nullptr);
    assert(buffer->next == nullptr);

    gb->tail->next = buffer;
    gb->tail = buffer;
}

void *
growing_buffer_write(GrowingBuffer *gb, size_t length)
{
    struct buffer *buffer = gb->tail;
    void *ret;

    assert(gb->size > 0);

    if (buffer->length + length > gb->size) {
        if (gb->size < length)
            gb->size = length; /* XXX round up? */
        buffer = (struct buffer *)
            p_malloc(gb->pool,
                     sizeof(*buffer) - sizeof(buffer->data) + gb->size);
        buffer->next = nullptr;
        buffer->length = 0;

        growing_buffer_append_buffer(gb, buffer);
    }

    assert(buffer->length + length <= gb->size);

    ret = buffer->data + buffer->length;
    buffer->length += length;

    return ret;
}

void
growing_buffer_write_buffer(GrowingBuffer *gb, const void *p, size_t length)
{
    memcpy(growing_buffer_write(gb, length), p, length);
}

void
growing_buffer_write_string(GrowingBuffer *gb, const char *p)
{
    growing_buffer_write_buffer(gb, p, strlen(p));
}

void
growing_buffer_cat(GrowingBuffer *dest, GrowingBuffer *src)
{
    dest->tail->next = &src->first;
    dest->tail = src->tail;
    dest->size = src->size;
}

size_t
growing_buffer_size(const GrowingBuffer *gb)
{
    size_t size = 0;

    for (const struct buffer *buffer = &gb->first;
         buffer != nullptr; buffer = buffer->next)
        size += buffer->length;

    return size;
}

GrowingBufferReader::GrowingBufferReader(const GrowingBuffer &gb)
#ifndef NDEBUG
    :growing_buffer(&gb)
#endif
{
    assert(gb.first.length > 0 || gb.first.next == nullptr ||
           (gb.first.next != nullptr &&
            gb.size > gb.initial_size &&
            gb.first.next->length > gb.initial_size));

    buffer = &gb.first;
    if (buffer->length == 0 && buffer->next != nullptr)
        buffer = buffer->next;

    position = 0;
}

void
GrowingBufferReader::Update()
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    if (position == buffer->length &&
        buffer->next != nullptr) {
        /* the reader was at the end of all buffers, but then a new
           buffer was appended */
        buffer = buffer->next;
        position = 0;
    }
}

bool
GrowingBufferReader::IsEOF() const
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    return position == buffer->length;
}

size_t
GrowingBufferReader::Available() const
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    size_t available = buffer->length - position;
    for (const struct buffer *b = buffer->next; b != nullptr; b = b->next) {
        assert(b->length > 0);

        available += b->length;
    }

    return available;
}

ConstBuffer<void>
GrowingBufferReader::Read() const
{
    assert(buffer != nullptr);

    const struct buffer *b = buffer;

    if (b->length == 0 && b->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(b == &growing_buffer->first);
        assert(position == 0);

        b = b->next;
    }

    if (position >= b->length) {
        assert(position == b->length);
        assert(buffer->next == nullptr);
        return nullptr;
    }

    return { b->data + position, b->length - position };
}

void
GrowingBufferReader::Consume(size_t length)
{
    assert(buffer != nullptr);

    if (length == 0)
        return;

    if (buffer->length == 0 && buffer->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(buffer == &growing_buffer->first);
        assert(position == 0);

        buffer = buffer->next;
    }

    position += length;

    assert(position <= buffer->length);

    if (position >= buffer->length) {
        if (buffer->next == nullptr)
            return;

        buffer = buffer->next;
        position = 0;
    }
}

ConstBuffer<void>
GrowingBufferReader::PeekNext() const
{
    assert(buffer != nullptr);

    const struct buffer *b = buffer;

    if (b->length == 0 && b->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(b == &growing_buffer->first);
        assert(position == 0);

        b = b->next;
    }

    b = b->next;

    if (b == nullptr)
        return nullptr;

    return { b->data, b->length };
}

void
GrowingBufferReader::Skip(size_t length)
{
    assert(buffer != nullptr);

    while (length > 0) {
        size_t remaining = buffer->length - position;
        if (length < remaining ||
            (length == remaining && buffer->next == nullptr)) {
            position += length;
            return;
        }

        length -= remaining;

        if (buffer->next == nullptr) {
            assert(position + remaining == length);
            position = length;
            return;
        }

        assert(buffer->next != nullptr);
        buffer = buffer->next;
        position = 0;
    }
}

static void *
growing_buffer_copy(void *dest0, const GrowingBuffer *gb)
{
    unsigned char *dest = (unsigned char *)dest0;

    for (const struct buffer *buffer = &gb->first; buffer != nullptr;
         buffer = buffer->next) {
        memcpy(dest, buffer->data, buffer->length);
        dest += buffer->length;
    }

    return dest;
}

WritableBuffer<void>
growing_buffer_dup(const GrowingBuffer *gb, struct pool *pool)
{
    size_t length;

    length = growing_buffer_size(gb);
    if (length == 0)
        return nullptr;

    void *dest = p_malloc(pool, length);
    growing_buffer_copy(dest, gb);

    return { dest, length };
}
<commit_msg>growing_buffer: move internal functions into struct GrowingBuffer<commit_after>/*
 * A auto-growing buffer you can write to.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "growing_buffer.hxx"
#include "pool.hxx"
#include "util/ConstBuffer.hxx"
#include "util/WritableBuffer.hxx"

#include <assert.h>
#include <string.h>

struct buffer {
    struct buffer *next;
    size_t length;
    char data[sizeof(size_t)];
};

struct GrowingBuffer {
    struct pool *pool;

#ifndef NDEBUG
    size_t initial_size;
#endif

    size_t size;
    struct buffer *current, *tail, first;

    void AppendBuffer(struct buffer &buffer);

    void CopyTo(void *dest) const;
};

GrowingBuffer *gcc_malloc
growing_buffer_new(struct pool *pool, size_t initial_size)
{
    GrowingBuffer *gb = (GrowingBuffer *)
        p_malloc(pool, sizeof(*gb) - sizeof(gb->first.data) + initial_size);

    gb->pool = pool;

#ifndef NDEBUG
    gb->initial_size = initial_size;
#endif

    gb->size = initial_size;
    gb->current = &gb->first;
    gb->tail = &gb->first;
    gb->first.next = nullptr;
    gb->first.length = 0;

    return gb;
}

void
GrowingBuffer::AppendBuffer(struct buffer &buffer)
{
    assert(buffer.next == nullptr);

    tail->next = &buffer;
    tail = &buffer;
}

void *
growing_buffer_write(GrowingBuffer *gb, size_t length)
{
    struct buffer *buffer = gb->tail;
    void *ret;

    assert(gb->size > 0);

    if (buffer->length + length > gb->size) {
        if (gb->size < length)
            gb->size = length; /* XXX round up? */
        buffer = (struct buffer *)
            p_malloc(gb->pool,
                     sizeof(*buffer) - sizeof(buffer->data) + gb->size);
        buffer->next = nullptr;
        buffer->length = 0;

        gb->AppendBuffer(*buffer);
    }

    assert(buffer->length + length <= gb->size);

    ret = buffer->data + buffer->length;
    buffer->length += length;

    return ret;
}

void
growing_buffer_write_buffer(GrowingBuffer *gb, const void *p, size_t length)
{
    memcpy(growing_buffer_write(gb, length), p, length);
}

void
growing_buffer_write_string(GrowingBuffer *gb, const char *p)
{
    growing_buffer_write_buffer(gb, p, strlen(p));
}

void
growing_buffer_cat(GrowingBuffer *dest, GrowingBuffer *src)
{
    dest->tail->next = &src->first;
    dest->tail = src->tail;
    dest->size = src->size;
}

size_t
growing_buffer_size(const GrowingBuffer *gb)
{
    size_t size = 0;

    for (const struct buffer *buffer = &gb->first;
         buffer != nullptr; buffer = buffer->next)
        size += buffer->length;

    return size;
}

GrowingBufferReader::GrowingBufferReader(const GrowingBuffer &gb)
#ifndef NDEBUG
    :growing_buffer(&gb)
#endif
{
    assert(gb.first.length > 0 || gb.first.next == nullptr ||
           (gb.first.next != nullptr &&
            gb.size > gb.initial_size &&
            gb.first.next->length > gb.initial_size));

    buffer = &gb.first;
    if (buffer->length == 0 && buffer->next != nullptr)
        buffer = buffer->next;

    position = 0;
}

void
GrowingBufferReader::Update()
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    if (position == buffer->length &&
        buffer->next != nullptr) {
        /* the reader was at the end of all buffers, but then a new
           buffer was appended */
        buffer = buffer->next;
        position = 0;
    }
}

bool
GrowingBufferReader::IsEOF() const
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    return position == buffer->length;
}

size_t
GrowingBufferReader::Available() const
{
    assert(buffer != nullptr);
    assert(position <= buffer->length);

    size_t available = buffer->length - position;
    for (const struct buffer *b = buffer->next; b != nullptr; b = b->next) {
        assert(b->length > 0);

        available += b->length;
    }

    return available;
}

ConstBuffer<void>
GrowingBufferReader::Read() const
{
    assert(buffer != nullptr);

    const struct buffer *b = buffer;

    if (b->length == 0 && b->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(b == &growing_buffer->first);
        assert(position == 0);

        b = b->next;
    }

    if (position >= b->length) {
        assert(position == b->length);
        assert(buffer->next == nullptr);
        return nullptr;
    }

    return { b->data + position, b->length - position };
}

void
GrowingBufferReader::Consume(size_t length)
{
    assert(buffer != nullptr);

    if (length == 0)
        return;

    if (buffer->length == 0 && buffer->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(buffer == &growing_buffer->first);
        assert(position == 0);

        buffer = buffer->next;
    }

    position += length;

    assert(position <= buffer->length);

    if (position >= buffer->length) {
        if (buffer->next == nullptr)
            return;

        buffer = buffer->next;
        position = 0;
    }
}

ConstBuffer<void>
GrowingBufferReader::PeekNext() const
{
    assert(buffer != nullptr);

    const struct buffer *b = buffer;

    if (b->length == 0 && b->next != nullptr) {
        /* skip the empty first buffer that was too small */
        assert(b == &growing_buffer->first);
        assert(position == 0);

        b = b->next;
    }

    b = b->next;

    if (b == nullptr)
        return nullptr;

    return { b->data, b->length };
}

void
GrowingBufferReader::Skip(size_t length)
{
    assert(buffer != nullptr);

    while (length > 0) {
        size_t remaining = buffer->length - position;
        if (length < remaining ||
            (length == remaining && buffer->next == nullptr)) {
            position += length;
            return;
        }

        length -= remaining;

        if (buffer->next == nullptr) {
            assert(position + remaining == length);
            position = length;
            return;
        }

        assert(buffer->next != nullptr);
        buffer = buffer->next;
        position = 0;
    }
}

void
GrowingBuffer::CopyTo(void *_dest) const
{
    unsigned char *dest = (unsigned char *)_dest;

    for (const struct buffer *buffer = &first; buffer != nullptr;
         buffer = buffer->next) {
        memcpy(dest, buffer->data, buffer->length);
        dest += buffer->length;
    }
}

WritableBuffer<void>
growing_buffer_dup(const GrowingBuffer *gb, struct pool *pool)
{
    size_t length;

    length = growing_buffer_size(gb);
    if (length == 0)
        return nullptr;

    void *dest = p_malloc(pool, length);
    gb->CopyTo(dest);

    return { dest, length };
}
<|endoftext|>


<commit_before>/**
 * Kryvos - Encrypts and decrypts files.
 * Copyright (C) 2014, 2015 Andrew Dolby
 *
 * This file is part of Kryvos.
 *
 * Kryvos 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 3 of the License, or
 * (at your option) any later version.
 *
 * Kryvos 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 Kryvos.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contact : andrewdolby@gmail.com
 */

#ifndef KRYVOS_GUI_MAINWINDOW_HPP_
#define KRYVOS_GUI_MAINWINDOW_HPP_

#include "settings/Settings.hpp"
#include "gui/SettingsFrame.hpp"
#include "gui/HeaderFrame.hpp"
#include "gui/FileListFrame.hpp"
#include "gui/MessageFrame.hpp"
#include "gui/PasswordFrame.hpp"
#include "gui/ControlButtonFrame.hpp"
#include "utility/pimpl.h"
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>

/*!
 * \brief The MainWindow class is the main window for the application.
 */
class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  /*!
   * \brief MainWindow Constructs the application's main window.
   * \param parent Widget parent of this main window
   */
  explicit MainWindow(Settings* settings = nullptr, QWidget* parent = nullptr);

  /*!
   * \brief ~MainWindow Destroys the application's main window.
   */
  virtual ~MainWindow();

 signals:
  /*!
   * \brief encrypt Emitted when the user provides all required data for
   * encryption and clicks the Encrypt push button.
   * \param passphrase String representing the user supplied passphrase
   * \param inputFileNames List of input file strings
   * \param algorithmName String representing the current algorithm.
   * Example: "AES-128/GCM" will encrypt files with AES 128-bit key size in
   * Gallois Counter Mode.
   * \param keySize Key size
   */
  void encrypt(const QString& passphrase,
               const QStringList& inputFileNames,
               const QString& algorithmName,
               const std::size_t& keySize);

  /*!
   * \brief decrypt Emitted when the user provides all required data for
   * decryption and clicks the Decrypt push button.
   * \param passphrase String representing the user supplied passphrase
   * \param inputFileNames List of input file strings
   */
  void decrypt(const QString& passphrase, const QStringList& inputFileNames);

  /*!
   * \brief pauseCipher Emitted when the user toggles the Pause push button.
   * \param pause Boolean representing the pause status
   */
  void pauseCipher(const bool pause);

  /*!
   * \brief stopCipher Emitted when the user clicks the Clear Files push button.
   */
  void abortCipher();

  /*!
   * \brief stopFile Emitted when the user clicks a remove file button.
   */
  void stopFile(const QString& fileName);

 public slots:
  /*!
   * \brief addFiles Executed when the Add Files toolbar push button is clicked.
   */
  void addFiles();

  /*!
   * \brief removeFiles Executed when the Remove All Files toolbar push
   * button is clicked.
   */
  void removeFiles();

  /*!
   * \brief processFiles Executed when the encrypt or decrypt push button is
   * clicked. Starts the encryption or decryption operation using the passphrase
   * from the password line edit, the file list from the file list model, and
   * the algorithm name from the settings panel.
   * \param cryptFlag Boolean representing encrypt (true) or decrypt (false)
   */
  void processFiles(const bool cryptFlag);

  /*!
   * \brief updateProgress Executed when the cipher operation progress is
   * updated. Updates the progress bar for the item at the specified index.
   * \param index Integer representing the file list index to update
   * \param percent Integer representing the current progress in percent
   */
  void updateProgress(const QString& path, const qint64 percent);

  /*!
   * \brief updateStatusMessage Executed when a message should be displayed to
   * the user. Updates the message text edit text to the message.
   * \param message String representing the message.
   */
  void updateStatusMessage(const QString& message);

  /*!
   * \brief updateError Executed when a cipher operation fails.
   * \param index Integer representing the file list index to update
   * \param message String representing the error message
   */
  void updateError(const QString& path, const QString& message);

  /*!
   * \brief updateBusyStatus Executed when the cipher operation updates its busy
   * status. Stores the status to allow the GUI to decide when the user can
   * request new encryption events.
   * \param busy Boolean representing the busy status
   */
  void updateBusyStatus(const bool busy);

  /*!
   * \brief updateCipher Executed when the cipher is updated by the user in the
   * settings frame.
   * \param newCipher String representing the new cipher
   */
  void updateCipher(const QString& newCipher);

  /*!
   * \brief updateKeySize Executed when the key size is updated by the user in
   * the settings frame.
   * \param keySize Key size in bits
   */
  void updateKeySize(const std::size_t& keySize);

  /*!
   * \brief updateCipher Executed when the mode of operation is updated by the
   * user in the settings frame.
   * \param newCipher String representing the new mode of operation
   */
  void updateModeOfOperation(const QString& newMode);

 protected:
  /*!
   * \brief loadStyleSheet Attempts to load a Qt stylesheet from the local
   * themes folder with the name specified in the local settings file. If the
   * load fails, the method will load the default stylesheet from the
   * application resources.
   * \param styleFile String representing the name of the stylesheet without
   * a file extension
   * \param defaultFile String containing the name of the default stylesheet,
   * which will be used if the selected stylesheet file doesn't exist
   * \return String containing the stylesheet file contents
   */
  QString loadStyleSheet(const QString& styleFile,
                         const QString& defaultFile) const;

 protected:
  SettingsFrame* settingsFrame;
  HeaderFrame* headerFrame;
  FileListFrame* fileListFrame;
  MessageFrame* messageFrame;
  PasswordFrame* passwordFrame;
  ControlButtonFrame* controlButtonFrame;
  QVBoxLayout* contentLayout;

 private:
  class MainWindowPrivate;
  pimpl<MainWindowPrivate> m;
};

#endif // KRYVOS_GUI_MAINWINDOW_HPP_
<commit_msg>Update documentation<commit_after>/**
 * Kryvos - Encrypts and decrypts files.
 * Copyright (C) 2014, 2015 Andrew Dolby
 *
 * This file is part of Kryvos.
 *
 * Kryvos 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 3 of the License, or
 * (at your option) any later version.
 *
 * Kryvos 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 Kryvos.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contact : andrewdolby@gmail.com
 */

#ifndef KRYVOS_GUI_MAINWINDOW_HPP_
#define KRYVOS_GUI_MAINWINDOW_HPP_

#include "settings/Settings.hpp"
#include "gui/SettingsFrame.hpp"
#include "gui/HeaderFrame.hpp"
#include "gui/FileListFrame.hpp"
#include "gui/MessageFrame.hpp"
#include "gui/PasswordFrame.hpp"
#include "gui/ControlButtonFrame.hpp"
#include "utility/pimpl.h"
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QVBoxLayout>

/*!
 * \brief The MainWindow class is the main window for the application.
 */
class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  /*!
   * \brief MainWindow Constructs the application's main window.
   * \param parent Widget parent of this main window
   */
  explicit MainWindow(Settings* settings = nullptr, QWidget* parent = nullptr);

  /*!
   * \brief ~MainWindow Destroys the application's main window.
   */
  virtual ~MainWindow();

 signals:
  /*!
   * \brief encrypt Emitted when the user provides all required data for
   * encryption and clicks the Encrypt push button.
   * \param passphrase String representing the user supplied passphrase
   * \param inputFileNames List of input file strings
   * \param algorithmName String representing the current algorithm.
   * Example: "AES-128/GCM" will encrypt files with AES 128-bit key size in
   * Gallois Counter Mode.
   * \param keySize Key size
   */
  void encrypt(const QString& passphrase,
               const QStringList& inputFileNames,
               const QString& algorithmName,
               const std::size_t& keySize);

  /*!
   * \brief decrypt Emitted when the user provides all required data for
   * decryption and clicks the Decrypt push button.
   * \param passphrase String representing the user supplied passphrase
   * \param inputFileNames List of input file strings
   */
  void decrypt(const QString& passphrase, const QStringList& inputFileNames);

  /*!
   * \brief pauseCipher Emitted when the user toggles the Pause push button.
   * \param pause Boolean representing the pause status
   */
  void pauseCipher(const bool pause);

  /*!
   * \brief abortCipher Emitted when the user clicks the Clear Files push
   * button.
   */
  void abortCipher();

  /*!
   * \brief stopFile Emitted when the user clicks a remove file button.
   */
  void stopFile(const QString& fileName);

 public slots:
  /*!
   * \brief addFiles Executed when the Add Files toolbar push button is clicked.
   */
  void addFiles();

  /*!
   * \brief removeFiles Executed when the Remove All Files toolbar push
   * button is clicked.
   */
  void removeFiles();

  /*!
   * \brief processFiles Executed when the encrypt or decrypt push button is
   * clicked. Starts the encryption or decryption operation using the passphrase
   * from the password line edit, the file list from the file list model, and
   * the algorithm name from the settings panel.
   * \param cryptFlag Boolean representing encrypt (true) or decrypt (false)
   */
  void processFiles(const bool cryptFlag);

  /*!
   * \brief updateProgress Executed when the cipher operation progress is
   * updated. Updates the progress bar for the item at the specified index.
   * \param index Integer representing the file list index to update
   * \param percent Integer representing the current progress in percent
   */
  void updateProgress(const QString& path, const qint64 percent);

  /*!
   * \brief updateStatusMessage Executed when a message should be displayed to
   * the user. Updates the message text edit text to the message.
   * \param message String representing the message.
   */
  void updateStatusMessage(const QString& message);

  /*!
   * \brief updateError Executed when a cipher operation fails.
   * \param index Integer representing the file list index to update
   * \param message String representing the error message
   */
  void updateError(const QString& path, const QString& message);

  /*!
   * \brief updateBusyStatus Executed when the cipher operation updates its busy
   * status. Stores the status to allow the GUI to decide when the user can
   * request new encryption.
   * \param busy Boolean representing the busy status
   */
  void updateBusyStatus(const bool busy);

  /*!
   * \brief updateCipher Executed when the cipher is updated by the user in the
   * settings frame.
   * \param newCipher String representing the new cipher
   */
  void updateCipher(const QString& newCipher);

  /*!
   * \brief updateKeySize Executed when the key size is updated by the user in
   * the settings frame.
   * \param keySize Key size in bits
   */
  void updateKeySize(const std::size_t& keySize);

  /*!
   * \brief updateCipher Executed when the mode of operation is updated by the
   * user in the settings frame.
   * \param newCipher String representing the new mode of operation
   */
  void updateModeOfOperation(const QString& newMode);

 protected:
  /*!
   * \brief loadStyleSheet Attempts to load a Qt stylesheet from the local
   * themes folder with the name specified in the local settings file. If the
   * load fails, the method will load the default stylesheet from the
   * application resources.
   * \param styleFile String representing the name of the stylesheet without
   * a file extension
   * \param defaultFile String containing the name of the default stylesheet,
   * which will be used if the selected stylesheet file doesn't exist
   * \return String containing the stylesheet file contents
   */
  QString loadStyleSheet(const QString& styleFile,
                         const QString& defaultFile) const;

 protected:
  SettingsFrame* settingsFrame;
  HeaderFrame* headerFrame;
  FileListFrame* fileListFrame;
  MessageFrame* messageFrame;
  PasswordFrame* passwordFrame;
  ControlButtonFrame* controlButtonFrame;
  QVBoxLayout* contentLayout;

 private:
  class MainWindowPrivate;
  pimpl<MainWindowPrivate> m;
};

#endif // KRYVOS_GUI_MAINWINDOW_HPP_
<|endoftext|>