<commit_before>#ifndef GLOBAL_H_
#define GLOBAL_H_

typedef long double double64;
typedef long long int int64;
typedef unsigned long long int uint64;

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <functional>
#include <algorithm>

extern int
DEBUG_ENV,
EXPRESSION_STEPS,
PARSER_PRINT_INPUT,
PARSER_PRINT_TOKENS,
PARSER_PRINT_AS_EXPR,
PARSER_PRINT_OPERATOR_TOKENS,
TOKEN_OPERATOR_PRINT_CONSTRUCTION,
TEST_INPUT;
extern std::string INPUT;

void getConstants();

template<typename T, typename Lambda>
std::vector<std::vector<T> > splitVector(std::vector<T> origin, Lambda& shouldSplit) {
  std::vector<std::vector<T> > vec2d {std::vector<T>()};
  long long vec2dIndex = 0;
  for (T elem : origin) {
    vec2d[vec2dIndex].push_back(elem);
    if (shouldSplit(elem)) {
      vec2dIndex++;
      vec2d.push_back(std::vector<T>());
    }
  }
  return vec2d;
}

template<class T>
std::ostream& operator<<(std::ostream& os, std::vector<T>& vec) {
  for (unsigned int i = 0; i < vec.size(); ++i) os << vec[i] << std::endl;
  return os;
}

template <typename T>
bool contains(T element, std::vector<T> vec) {
  return std::find(vec.begin(), vec.end(), element) != vec.end();
}

template<typename T>
void print(T thing) {
  std::cout << thing;
}

template<typename T, typename... Args>
void print(T thing, Args... args) {
  print(thing);
  print(args...);
}

class SyntaxError: std::runtime_error {
private:
  std::string msg;
public:
  SyntaxError(unsigned int lines);
  SyntaxError(std::string msg, unsigned int lines);

  std::string getMessage();
};

class TypeError: std::runtime_error {
private:
  std::string msg;
public:
  TypeError();
  TypeError(std::string msg);

  std::string getMessage();
};

#endif /* GLOBAL_H_ */
<commit_msg>Added hash functions<commit_after>#ifndef GLOBAL_H_
#define GLOBAL_H_

typedef long double double64;
typedef long long int int64;
typedef unsigned long long int uint64;

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <functional>
#include <algorithm>

extern int
DEBUG_ENV,
EXPRESSION_STEPS,
PARSER_PRINT_INPUT,
PARSER_PRINT_TOKENS,
PARSER_PRINT_AS_EXPR,
PARSER_PRINT_OPERATOR_TOKENS,
TOKEN_OPERATOR_PRINT_CONSTRUCTION,
TEST_INPUT;
extern std::string INPUT;

void getConstants();

// Makes enums work in hashes
namespace std {
  template<class E>
  class hash {
    using sfinae = typename std::enable_if<std::is_enum<E>::value, E>::type;
  public:
    size_t operator()(const E&e) const {
      return std::hash<typename std::underlying_type<E>::type>()(e);
    }
  };
};

template<typename T>
std::size_t hash(T element) {
  return std::hash<T>()(element);
}

template<typename T, typename... HashTypes>
std::size_t hash(std::size_t init, T element, HashTypes... ht) {
  return hash(init ^ (hash<T>(element) + 0x9e3779b9 + (init << 6) + (init >> 2)), ht...);
}

template<typename T, typename... HashTypes>
std::size_t hash(T element, HashTypes... ht) {
  return hash(hash<T>(element), ht...);
}

template<typename T, typename Lambda>
std::vector<std::vector<T> > splitVector(std::vector<T> origin, Lambda& shouldSplit) {
  std::vector<std::vector<T> > vec2d {std::vector<T>()};
  long long vec2dIndex = 0;
  for (T elem : origin) {
    vec2d[vec2dIndex].push_back(elem);
    if (shouldSplit(elem)) {
      vec2dIndex++;
      vec2d.push_back(std::vector<T>());
    }
  }
  return vec2d;
}

template<class T>
std::ostream& operator<<(std::ostream& os, std::vector<T>& vec) {
  for (unsigned int i = 0; i < vec.size(); ++i) os << vec[i] << std::endl;
  return os;
}

template <typename T>
bool contains(T element, std::vector<T> vec) {
  return std::find(vec.begin(), vec.end(), element) != vec.end();
}

template<typename T>
void print(T thing) {
  std::cout << thing;
}

template<typename T, typename... Args>
void print(T thing, Args... args) {
  print(thing);
  print(args...);
}

class SyntaxError: std::runtime_error {
private:
  std::string msg;
public:
  SyntaxError(unsigned int lines);
  SyntaxError(std::string msg, unsigned int lines);

  std::string getMessage();
};

class TypeError: std::runtime_error {
private:
  std::string msg;
public:
  TypeError();
  TypeError(std::string msg);

  std::string getMessage();
};

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


<commit_before>#include <node.h>
#include "gn_scan.h"
#include "gn_file.h"

using namespace v8;

GNScan::GNScan() {};
GNScan::~GNScan() {
    groove_replaygainscan_destroy(scan);
    scan = NULL;
};

Persistent<Function> GNScan::constructor;

template <typename target_t, typename func_t>
static void AddGetter(target_t tpl, const char* name, func_t fn) {
    tpl->PrototypeTemplate()->SetAccessor(String::NewSymbol(name), fn);
}

template <typename target_t, typename func_t>
static void AddMethod(target_t tpl, const char* name, func_t fn) {
    tpl->PrototypeTemplate()->Set(String::NewSymbol(name),
            FunctionTemplate::New(fn)->GetFunction());
}

void GNScan::Init() {
    // Prepare constructor template
    Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
    tpl->SetClassName(String::NewSymbol("GrooveReplayGainScan"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
    // Methods
    AddMethod(tpl, "abort", Abort);

    constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> GNScan::New(const Arguments& args) {
    HandleScope scope;

    GNScan *obj = new GNScan();
    obj->Wrap(args.This());

    return scope.Close(args.This());
}

Handle<Value> GNScan::NewInstance() {
    HandleScope scope;
    return scope.Close(constructor->NewInstance());
}

Handle<Value> GNScan::Abort(const Arguments& args) {
    HandleScope scope;
    GNScan *gn_scan = node::ObjectWrap::Unwrap<GNScan>(args.This());
    gn_scan->scan->abort_request = 1;
    return scope.Close(Undefined());
}

struct ExecReq {
    uv_work_t req;
    GrooveReplayGainScan *scan;
    double gain;
    double peak;
    int result;
    int file_count;
    int result_count;
    Persistent<Function> file_progress_cb;
    Persistent<Function> file_complete_cb;
    Persistent<Function> end_cb;
    struct ExecFileReq *file_reqs;
    uv_mutex_t mutex;
};

struct ExecFileReq {
    ExecReq *req;
    GrooveFile *file;
    uv_async_t complete_async;
    uv_async_t progress_async;
    uv_rwlock_t rwlock;
    double progress;
    double gain;
    double peak;
};

static void MaybeDestroyReq(uv_handle_t *handle) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);
    ExecReq *r = req->req;

    uv_mutex_lock(&r->mutex);
    r->result_count += 1;
    bool done = r->result_count == r->file_count * 2;
    uv_mutex_unlock(&r->mutex);

    if (!done) return;

    for (int i = 0; i < r->file_count; i += 1) {
        uv_rwlock_destroy(&r->file_reqs[i].rwlock);
    }
    delete[] r->file_reqs;

    uv_mutex_destroy(&r->mutex);
    delete r;
}

static void MaybeCleanupReq(ExecReq *r) {
    uv_mutex_lock(&r->mutex);
    r->result_count += 1;
    bool done = r->result_count == r->file_count + 1;
    uv_mutex_unlock(&r->mutex);

    if (!done) return;

    r->result_count = 0;

    for (int i = 0; i < r->file_count; i += 1) {
        uv_close(reinterpret_cast<uv_handle_t*>(&r->file_reqs[i].complete_async), MaybeDestroyReq);
        uv_close(reinterpret_cast<uv_handle_t*>(&r->file_reqs[i].progress_async), MaybeDestroyReq);
    }

}

static void CompleteAsyncCallback(uv_async_t *handle, int status) {
    HandleScope scope;

    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);

    uv_rwlock_rdlock(&req->rwlock);
    GrooveFile *file = req->file;
    double gain = req->gain;
    double peak = req->peak;
    uv_rwlock_rdunlock(&req->rwlock);

    const unsigned argc = 3;
    Handle<Value> argv[argc];
    argv[0] = GNFile::NewInstance(file);
    argv[1] = Number::New(gain);
    argv[2] = Number::New(peak);

    TryCatch try_catch;
    req->req->file_complete_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    MaybeCleanupReq(req->req);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

static void ProgressAsyncCallback(uv_async_t *handle, int status) {
    HandleScope scope;

    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);

    uv_rwlock_rdlock(&req->rwlock);
    GrooveFile *file = req->file;
    double progress = req->progress;
    uv_rwlock_rdunlock(&req->rwlock);

    const unsigned argc = 2;
    Handle<Value> argv[argc];
    argv[0] = GNFile::NewInstance(file);
    argv[1] = Number::New(progress);

    TryCatch try_catch;
    req->req->file_progress_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

static void ExecFileProgress(void *userdata, double amount) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(userdata);

    uv_rwlock_wrlock(&req->rwlock);
    req->progress = amount;
    uv_rwlock_wrunlock(&req->rwlock);

    uv_async_send(&req->progress_async);
}

static void ExecFileComplete(void *userdata, double gain, double peak) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(userdata);

    uv_rwlock_wrlock(&req->rwlock);
    req->gain = gain;
    req->peak = peak;
    uv_rwlock_wrunlock(&req->rwlock);

    uv_async_send(&req->complete_async);
}

static void ExecAsync(uv_work_t *req) {
    ExecReq *r = reinterpret_cast<ExecReq *>(req->data);
    r->result = groove_replaygainscan_exec(r->scan, &r->gain, &r->peak);
}

static void ExecAfter(uv_work_t *req) {
    HandleScope scope;
    ExecReq *r = reinterpret_cast<ExecReq *>(req->data);

    const unsigned argc = 3;
    Handle<Value> argv[argc];
    if (r->result < 0) {
        argv[0] = Exception::Error(String::New("scan failed"));
        argv[1] = Null();
        argv[2] = Null();
    } else {
        argv[0] = Null();
        argv[1] = Number::New(r->gain);
        argv[2] = Number::New(r->peak);
    }
    TryCatch try_catch;
    r->end_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    MaybeCleanupReq(r);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

Handle<Value> GNScan::Create(const Arguments& args) {
    HandleScope scope;

    Local<Array> file_list = Local<Array>::Cast(args[0]);

    GrooveReplayGainScan *scan = groove_create_replaygainscan();
    scan->progress_interval = args[1]->NumberValue();
    if (!scan) {
        ThrowException(Exception::Error(String::New("unable to create replaygainscan")));
        return scope.Close(Undefined());
    }
    Local<Object> instance = GNScan::NewInstance()->ToObject();
    GNScan *gn_scan = node::ObjectWrap::Unwrap<GNScan>(instance);
    gn_scan->scan = scan;

    ExecReq *request = new ExecReq;
    request->file_count = file_list->Length();
    request->result_count = 0;
    request->req.data = request;
    request->scan = gn_scan->scan;
    request->scan->file_complete = ExecFileComplete;
    request->scan->file_progress = ExecFileProgress;
    request->file_progress_cb = Persistent<Function>::New(Local<Function>::Cast(args[2]));
    request->file_complete_cb = Persistent<Function>::New(Local<Function>::Cast(args[3]));
    request->end_cb = Persistent<Function>::New(Local<Function>::Cast(args[4]));
    request->file_reqs = new ExecFileReq[request->file_count];

    uv_mutex_init(&request->mutex);

    for (int i = 0; i < request->file_count; i += 1) {
        GNFile *gn_file = node::ObjectWrap::Unwrap<GNFile>(file_list->Get(i)->ToObject());
        ExecFileReq *file_request = &request->file_reqs[i];
        file_request->req = request;
        file_request->file = gn_file->file;

        uv_async_init(uv_default_loop(), &file_request->complete_async, CompleteAsyncCallback);
        uv_async_init(uv_default_loop(), &file_request->progress_async, ProgressAsyncCallback);

        uv_rwlock_init(&file_request->rwlock);

        file_request->complete_async.data = file_request;
        file_request->progress_async.data = file_request;

        groove_replaygainscan_add(scan, gn_file->file, file_request);
    }

    uv_queue_work(uv_default_loop(), &request->req, ExecAsync,
            (uv_after_work_cb)ExecAfter);

    return scope.Close(instance);
}
<commit_msg>more reliable replaygain scan cleanup<commit_after>#include <node.h>
#include "gn_scan.h"
#include "gn_file.h"

using namespace v8;

GNScan::GNScan() {};
GNScan::~GNScan() {};

Persistent<Function> GNScan::constructor;

template <typename target_t, typename func_t>
static void AddGetter(target_t tpl, const char* name, func_t fn) {
    tpl->PrototypeTemplate()->SetAccessor(String::NewSymbol(name), fn);
}

template <typename target_t, typename func_t>
static void AddMethod(target_t tpl, const char* name, func_t fn) {
    tpl->PrototypeTemplate()->Set(String::NewSymbol(name),
            FunctionTemplate::New(fn)->GetFunction());
}

void GNScan::Init() {
    // Prepare constructor template
    Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
    tpl->SetClassName(String::NewSymbol("GrooveReplayGainScan"));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
    // Methods
    AddMethod(tpl, "abort", Abort);

    constructor = Persistent<Function>::New(tpl->GetFunction());
}

Handle<Value> GNScan::New(const Arguments& args) {
    HandleScope scope;

    GNScan *obj = new GNScan();
    obj->Wrap(args.This());

    return scope.Close(args.This());
}

Handle<Value> GNScan::NewInstance() {
    HandleScope scope;
    return scope.Close(constructor->NewInstance());
}

Handle<Value> GNScan::Abort(const Arguments& args) {
    HandleScope scope;
    GNScan *gn_scan = node::ObjectWrap::Unwrap<GNScan>(args.This());
    gn_scan->scan->abort_request = 1;
    return scope.Close(Undefined());
}

struct ExecReq {
    uv_work_t req;
    GrooveReplayGainScan *scan;
    double gain;
    double peak;
    int result;
    int file_count;
    int result_count;
    Persistent<Function> file_progress_cb;
    Persistent<Function> file_complete_cb;
    Persistent<Function> end_cb;
    struct ExecFileReq *file_reqs;
    uv_mutex_t mutex;
};

struct ExecFileReq {
    ExecReq *req;
    GrooveFile *file;
    uv_async_t complete_async;
    uv_async_t progress_async;
    uv_rwlock_t rwlock;
    double progress;
    double gain;
    double peak;
};

static void MaybeDestroyReq(uv_handle_t *handle) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);
    ExecReq *r = req->req;

    uv_mutex_lock(&r->mutex);
    r->result_count += 1;
    bool done = r->result_count == r->file_count * 2;
    uv_mutex_unlock(&r->mutex);

    if (!done) return;

    for (int i = 0; i < r->file_count; i += 1) {
        uv_rwlock_destroy(&r->file_reqs[i].rwlock);
    }
    delete[] r->file_reqs;

    uv_mutex_destroy(&r->mutex);
    groove_replaygainscan_destroy(r->scan);
    delete r;
}

static void MaybeCleanupReq(ExecReq *r) {
    uv_mutex_lock(&r->mutex);
    r->result_count += 1;
    bool done = r->result_count == r->file_count + 1;
    uv_mutex_unlock(&r->mutex);

    if (!done) return;

    r->result_count = 0;

    for (int i = 0; i < r->file_count; i += 1) {
        uv_close(reinterpret_cast<uv_handle_t*>(&r->file_reqs[i].complete_async), MaybeDestroyReq);
        uv_close(reinterpret_cast<uv_handle_t*>(&r->file_reqs[i].progress_async), MaybeDestroyReq);
    }

}

static void CompleteAsyncCallback(uv_async_t *handle, int status) {
    HandleScope scope;

    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);

    uv_rwlock_rdlock(&req->rwlock);
    GrooveFile *file = req->file;
    double gain = req->gain;
    double peak = req->peak;
    uv_rwlock_rdunlock(&req->rwlock);

    const unsigned argc = 3;
    Handle<Value> argv[argc];
    argv[0] = GNFile::NewInstance(file);
    argv[1] = Number::New(gain);
    argv[2] = Number::New(peak);

    TryCatch try_catch;
    req->req->file_complete_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    MaybeCleanupReq(req->req);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

static void ProgressAsyncCallback(uv_async_t *handle, int status) {
    HandleScope scope;

    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(handle->data);

    uv_rwlock_rdlock(&req->rwlock);
    GrooveFile *file = req->file;
    double progress = req->progress;
    uv_rwlock_rdunlock(&req->rwlock);

    const unsigned argc = 2;
    Handle<Value> argv[argc];
    argv[0] = GNFile::NewInstance(file);
    argv[1] = Number::New(progress);

    TryCatch try_catch;
    req->req->file_progress_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

static void ExecFileProgress(void *userdata, double amount) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(userdata);

    uv_rwlock_wrlock(&req->rwlock);
    req->progress = amount;
    uv_rwlock_wrunlock(&req->rwlock);

    uv_async_send(&req->progress_async);
}

static void ExecFileComplete(void *userdata, double gain, double peak) {
    ExecFileReq *req = reinterpret_cast<ExecFileReq *>(userdata);

    uv_rwlock_wrlock(&req->rwlock);
    req->gain = gain;
    req->peak = peak;
    uv_rwlock_wrunlock(&req->rwlock);

    uv_async_send(&req->complete_async);
}

static void ExecAsync(uv_work_t *req) {
    ExecReq *r = reinterpret_cast<ExecReq *>(req->data);
    r->result = groove_replaygainscan_exec(r->scan, &r->gain, &r->peak);
}

static void ExecAfter(uv_work_t *req) {
    HandleScope scope;
    ExecReq *r = reinterpret_cast<ExecReq *>(req->data);

    const unsigned argc = 3;
    Handle<Value> argv[argc];
    if (r->result < 0) {
        argv[0] = Exception::Error(String::New("scan failed"));
        argv[1] = Null();
        argv[2] = Null();
    } else {
        argv[0] = Null();
        argv[1] = Number::New(r->gain);
        argv[2] = Number::New(r->peak);
    }
    TryCatch try_catch;
    r->end_cb->Call(Context::GetCurrent()->Global(), argc, argv);

    MaybeCleanupReq(r);

    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
}

Handle<Value> GNScan::Create(const Arguments& args) {
    HandleScope scope;

    Local<Array> file_list = Local<Array>::Cast(args[0]);

    GrooveReplayGainScan *scan = groove_create_replaygainscan();
    scan->progress_interval = args[1]->NumberValue();
    if (!scan) {
        ThrowException(Exception::Error(String::New("unable to create replaygainscan")));
        return scope.Close(Undefined());
    }
    Local<Object> instance = GNScan::NewInstance()->ToObject();
    GNScan *gn_scan = node::ObjectWrap::Unwrap<GNScan>(instance);
    gn_scan->scan = scan;

    ExecReq *request = new ExecReq;
    request->file_count = file_list->Length();
    request->result_count = 0;
    request->req.data = request;
    request->scan = gn_scan->scan;
    request->scan->file_complete = ExecFileComplete;
    request->scan->file_progress = ExecFileProgress;
    request->file_progress_cb = Persistent<Function>::New(Local<Function>::Cast(args[2]));
    request->file_complete_cb = Persistent<Function>::New(Local<Function>::Cast(args[3]));
    request->end_cb = Persistent<Function>::New(Local<Function>::Cast(args[4]));
    request->file_reqs = new ExecFileReq[request->file_count];

    uv_mutex_init(&request->mutex);

    for (int i = 0; i < request->file_count; i += 1) {
        GNFile *gn_file = node::ObjectWrap::Unwrap<GNFile>(file_list->Get(i)->ToObject());
        ExecFileReq *file_request = &request->file_reqs[i];
        file_request->req = request;
        file_request->file = gn_file->file;

        uv_async_init(uv_default_loop(), &file_request->complete_async, CompleteAsyncCallback);
        uv_async_init(uv_default_loop(), &file_request->progress_async, ProgressAsyncCallback);

        uv_rwlock_init(&file_request->rwlock);

        file_request->complete_async.data = file_request;
        file_request->progress_async.data = file_request;

        groove_replaygainscan_add(scan, gn_file->file, file_request);
    }

    uv_queue_work(uv_default_loop(), &request->req, ExecAsync,
            (uv_after_work_cb)ExecAfter);

    return scope.Close(instance);
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** v4l2copy.cpp
**
** Copy from a V4L2 capture device to an other V4L2 output device
**
** -------------------------------------------------------------------------*/

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <signal.h>

#include <fstream>

#include "logger.h"

#include "libyuv.h"

#include "V4l2Device.h"
#include "V4l2Capture.h"
#include "V4l2Output.h"

int stop=0;

/* ---------------------------------------------------------------------------
**  SIGINT handler
** -------------------------------------------------------------------------*/
void sighandler(int)
{
       printf("SIGINT\n");
       stop =1;
}

/* ---------------------------------------------------------------------------
**  main
** -------------------------------------------------------------------------*/
int main(int argc, char* argv[])
{
	int verbose=0;
	const char *in_devname = "/dev/video0";
	const char *out_devname = "/dev/video1";
	int c = 0;
	V4l2Access::IoType ioTypeIn  = V4l2Access::IOTYPE_MMAP;
	V4l2Access::IoType ioTypeOut = V4l2Access::IOTYPE_MMAP;
	std::string outFormatStr = "YU12";

	while ((c = getopt (argc, argv, "hv::" "o:" "rw")) != -1)
	{
		switch (c)
		{
			case 'v':	verbose = 1; if (optarg && *optarg=='v') verbose++;  break;
			case 'h':
			{
				std::cout << argv[0] << " [-v[v]] [-W width] [-H height] source_device dest_device" << std::endl;
				std::cout << "\t -v            : verbose " << std::endl;
				std::cout << "\t -vv           : very verbose " << std::endl;
				std::cout << "\t -o <format>   : output YUV format" << std::endl;
				std::cout << "\t -r            : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t -w            : V4L2 capture using write interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t source_device : V4L2 capture device (default "<< in_devname << ")" << std::endl;
				std::cout << "\t dest_device   : V4L2 capture device (default "<< out_devname << ")" << std::endl;
				exit(0);
			}
			case 'r':	ioTypeIn  = V4l2Access::IOTYPE_READWRITE; break;
			case 'w':	ioTypeOut = V4l2Access::IOTYPE_READWRITE; break;
			case 'o':       outFormatStr = optarg ; break;
			default:
				std::cout << "option :" << c << " is unknown" << std::endl;
				break;
		}
	}
	if (optind<argc)
	{
		in_devname = argv[optind];
		optind++;
	}
	if (optind<argc)
	{
		out_devname = argv[optind];
		optind++;
	}
	// complete the fourcc
	while (outFormatStr.size() < 4)
	{
		outFormatStr.append(" ");
	}

	// initialize log4cpp
	initLogger(verbose);

	// init V4L2 capture interface
	V4L2DeviceParameters param(in_devname, 0, 0, 0, 0,verbose);
	V4l2Capture* videoCapture = V4l2Capture::create(param, ioTypeIn);

	if (videoCapture == NULL)
	{
		LOG(WARN) << "Cannot create V4L2 capture interface for device:" << in_devname;
	}
	else
	{
		int informat =  videoCapture->getFormat();
		int width    =  videoCapture->getWidth();
		int height   =  videoCapture->getHeight();

		// init V4L2 output interface
		int outformat =  v4l2_fourcc(outFormatStr[0],outFormatStr[1],outFormatStr[2],outFormatStr[3]);
		V4L2DeviceParameters outparam(out_devname, outformat, videoCapture->getWidth(), videoCapture->getHeight(), 0,verbose);
		V4l2Output* videoOutput = V4l2Output::create(outparam, ioTypeOut);
		if (videoOutput == NULL)
		{
			LOG(WARN) << "Cannot create V4L2 output interface for device:" << out_devname;
		}
		else
		{
			// check output size
			if ( (videoOutput->getWidth() != width) || (videoOutput->getHeight() != height) )
			{
				LOG(WARN) << "Cannot rescale input:" << videoCapture->getWidth()  << "x" << videoCapture->getHeight() << " output:" << videoOutput->getWidth()  << "x" << videoOutput->getHeight();
			}
			else
			{
				// intermediate I420 image
				uint8 i420_p0[width*height];
				uint8 i420_p1[width*height/2];
				uint8 i420_p2[width*height/2];

				timeval tv;

				LOG(NOTICE) << "Start Copying from " << in_devname << " to " << out_devname;
				signal(SIGINT,sighandler);
				while (!stop)
				{
					tv.tv_sec=1;
					tv.tv_usec=0;
					int ret = videoCapture->isReadable(&tv);
					if (ret == 1)
					{
						char inbuffer[videoCapture->getBufferSize()];
						int rsize = videoCapture->read(inbuffer, sizeof(inbuffer));
						if (rsize == -1)
						{
							LOG(NOTICE) << "stop " << strerror(errno);
							stop=1;
						}
						else
						{
							libyuv::ConvertToI420((const uint8*)inbuffer, rsize,
								i420_p0, width,
								i420_p1, width/2,
								i420_p2, width/2,
								0, 0,
								width, height,
								width, height,
								libyuv::kRotate0, informat);

							char outBuffer[videoOutput->getBufferSize()];
							libyuv::ConvertFromI420(i420_p0, width,
									i420_p1, width/2,
									i420_p2, width/2,
									(uint8*)outBuffer, 0,
									width, height,
									outformat);

							int wsize = videoOutput->write(outBuffer, sizeof(outBuffer));
							LOG(DEBUG) << "Copied " << rsize << " " << wsize;
						}
					}
					else if (ret == -1)
					{
						LOG(NOTICE) << "stop " << strerror(errno);
						stop=1;
					}
				}
			}
			delete videoOutput;
		}
		delete videoCapture;
	}

	return 0;
}
<commit_msg>v4l2convert: use a default buffer size when V4L2 driver report buffersize=0<commit_after>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** v4l2copy.cpp
**
** Copy from a V4L2 capture device to an other V4L2 output device
**
** -------------------------------------------------------------------------*/

#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <signal.h>

#include <fstream>

#include "logger.h"

#include "libyuv.h"

#include "V4l2Device.h"
#include "V4l2Capture.h"
#include "V4l2Output.h"

int stop=0;

/* ---------------------------------------------------------------------------
**  SIGINT handler
** -------------------------------------------------------------------------*/
void sighandler(int)
{
       printf("SIGINT\n");
       stop =1;
}

/* ---------------------------------------------------------------------------
**  main
** -------------------------------------------------------------------------*/
int main(int argc, char* argv[])
{
	int verbose=0;
	const char *in_devname = "/dev/video0";
	const char *out_devname = "/dev/video1";
	int c = 0;
	V4l2Access::IoType ioTypeIn  = V4l2Access::IOTYPE_MMAP;
	V4l2Access::IoType ioTypeOut = V4l2Access::IOTYPE_MMAP;
	std::string outFormatStr = "YU12";

	while ((c = getopt (argc, argv, "hv::" "o:" "rw")) != -1)
	{
		switch (c)
		{
			case 'v':	verbose = 1; if (optarg && *optarg=='v') verbose++;  break;
			case 'h':
			{
				std::cout << argv[0] << " [-v[v]] [-r] [-w] [-o <format>] source_device dest_device" << std::endl;
				std::cout << "\t -v            : verbose " << std::endl;
				std::cout << "\t -vv           : very verbose " << std::endl;
				std::cout << "\t -o <format>   : output YUV format (default " << outFormatStr << ")" << std::endl;
				std::cout << "\t -r            : V4L2 capture using read interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t -w            : V4L2 capture using write interface (default use memory mapped buffers)" << std::endl;
				std::cout << "\t source_device : V4L2 capture device (default "<< in_devname << ")" << std::endl;
				std::cout << "\t dest_device   : V4L2 capture device (default "<< out_devname << ")" << std::endl;
				exit(0);
			}
			case 'r':	ioTypeIn  = V4l2Access::IOTYPE_READWRITE; break;
			case 'w':	ioTypeOut = V4l2Access::IOTYPE_READWRITE; break;
			case 'o':       outFormatStr = optarg ; break;
			default:
				std::cout << "option :" << c << " is unknown" << std::endl;
				break;
		}
	}
	if (optind<argc)
	{
		in_devname = argv[optind];
		optind++;
	}
	if (optind<argc)
	{
		out_devname = argv[optind];
		optind++;
	}
	// complete the fourcc
	while (outFormatStr.size() < 4)
	{
		outFormatStr.append(" ");
	}

	// initialize log4cpp
	initLogger(verbose);

	// init V4L2 capture interface
	V4L2DeviceParameters param(in_devname, 0, 0, 0, 0,verbose);
	V4l2Capture* videoCapture = V4l2Capture::create(param, ioTypeIn);

	if (videoCapture == NULL)
	{
		LOG(WARN) << "Cannot create V4L2 capture interface for device:" << in_devname;
	}
	else
	{
		int informat =  videoCapture->getFormat();
		int width    =  videoCapture->getWidth();
		int height   =  videoCapture->getHeight();

		// init V4L2 output interface
		int outformat =  v4l2_fourcc(outFormatStr[0],outFormatStr[1],outFormatStr[2],outFormatStr[3]);
		V4L2DeviceParameters outparam(out_devname, outformat, videoCapture->getWidth(), videoCapture->getHeight(), 0,verbose);
		V4l2Output* videoOutput = V4l2Output::create(outparam, ioTypeOut);
		if (videoOutput == NULL)
		{
			LOG(WARN) << "Cannot create V4L2 output interface for device:" << out_devname;
		}
		else
		{
			// check output size
			if ( (videoOutput->getWidth() != width) || (videoOutput->getHeight() != height) )
			{
				LOG(WARN) << "Cannot rescale input:" << videoCapture->getWidth()  << "x" << videoCapture->getHeight() << " output:" << videoOutput->getWidth()  << "x" << videoOutput->getHeight();
			}
			else
			{
				// intermediate I420 image
				uint8 i420_p0[width*height];
				uint8 i420_p1[width*height/2];
				uint8 i420_p2[width*height/2];

				timeval tv;

				LOG(NOTICE) << "Start Copying from " << in_devname << " to " << out_devname;
				signal(SIGINT,sighandler);
				while (!stop)
				{
					tv.tv_sec=1;
					tv.tv_usec=0;
					int ret = videoCapture->isReadable(&tv);
					if (ret == 1)
					{
						int bufferSize = videoCapture->getBufferSize();
						if (bufferSize == 0) {
							// for buggy drivers
							bufferSize = width*height*3;
						}
						char inbuffer[bufferSize];
						int rsize = videoCapture->read(inbuffer, sizeof(inbuffer));
						if (rsize == -1)
						{
							LOG(NOTICE) << "stop " << strerror(errno);
							stop=1;
						}
						else
						{
							libyuv::ConvertToI420((const uint8*)inbuffer, rsize,
								i420_p0, width,
								i420_p1, width/2,
								i420_p2, width/2,
								0, 0,
								width, height,
								width, height,
								libyuv::kRotate0, informat);

							char outBuffer[videoOutput->getBufferSize()];
							libyuv::ConvertFromI420(i420_p0, width,
									i420_p1, width/2,
									i420_p2, width/2,
									(uint8*)outBuffer, 0,
									width, height,
									outformat);

							int wsize = videoOutput->write(outBuffer, sizeof(outBuffer));
							LOG(DEBUG) << "Copied " << rsize << " " << wsize;
						}
					}
					else if (ret == -1)
					{
						LOG(NOTICE) << "stop " << strerror(errno);
						stop=1;
					}
				}
			}
			delete videoOutput;
		}
		delete videoCapture;
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
    vcflib C++ library for parsing and manipulating VCF files

    Copyright © 2010-2020 Erik Garrison
    Copyright © 2020      Pjotr Prins

    This software is published under the MIT License. See the LICENSE file.
*/

#include "Variant.h"
#include "BedReader.h"
#include <getopt.h>
#include "mt19937ar.h"
#include <sstream>
#include <iostream>
#include "convert.h"

using namespace std;
using namespace vcflib;

void printSummary(char** argv) {
    cerr << "usage: " << argv[0] << " [options] [<vcf file>]" << endl
         << endl
         << "options:" << endl
         << "    -r, --rate RATE          base sampling probability per locus" << endl
         << "    -s, --scale-by KEY       scale sampling likelihood by this Float info field" << endl
         << "    -p, --random-seed N      use this random seed (by default read from /dev/random)" << endl
         << "    -q, --pseudorandom-seed  use a pseudorandom seed (by default read from /dev/random)" << endl
         << endl
         << "Randomly sample sites from an input VCF file, which may be provided as stdin." << endl
         << "Scale the sampling probability by the field specified in KEY.  This may be" << endl
         << "used to provide uniform sampling across allele frequencies, for instance." << endl;
    cerr << endl << "Type: statistics" << endl << endl;

    exit(0);
}

int main(int argc, char** argv) {

    double rate = 1.0;
    int seed = 0;
    bool useprng = false;
    string scaleByKey;

    if (argc == 1)
        printSummary(argv);

    int c;
    while (true) {
        static struct option long_options[] =
            {
                {"help", no_argument, 0, 'h'},
                {"rate",  required_argument, 0, 'r'},
                {"scale-by",  required_argument, 0, 's'},
                {"random-seed",  required_argument, 0, 'p'},
                {"pseudorandom-seed",  required_argument, 0, 'q'},
                {0, 0, 0, 0}
            };

        int option_index = 0;
        c = getopt_long (argc, argv, "hqr:s:p:",
                         long_options, &option_index);

        if (c == -1)
            break;

        switch (c) {
        case 'r':
            rate = atof(optarg);
            break;

        case 's':
            scaleByKey = optarg;
            break;

        case 'p':
            seed = atoi(optarg);
            break;

        case 'q':
            useprng = true;
            break;

        case 'h':
            printSummary(argv);
            break;

        case '?':
            printSummary(argv);
            exit(1);
            break;

        default:
            abort ();
        }
    }

    VariantCallFile variantFile;
    string inputFilename;
    if (optind == argc - 1) {
        inputFilename = argv[optind];
        variantFile.open(inputFilename);
    } else {
        variantFile.open(std::cin);
    }

    if (!variantFile.is_open()) {
        cout << "could not open VCF file" << endl;
        return 1;
    }

    // seed prng with random bits from /dev/random
    if (!seed) {
        fstream random;
        if (useprng) {
            random.open("/dev/urandom", fstream::in);
        } else {
            random.open("/dev/random", fstream::in);
        }
        random.get((char*) &seed, sizeof(int));
        random.close();
    }

    init_genrand(seed);

    vector<string> args;
    for (int i = 0; i < argc; ++i) {
        args.push_back(argv[i]);
    }

    stringstream liness;
    liness << "##sampling=\"random sampling using "
           << join(args, " ")
           << " using random seed "
           << seed << "\"";
    variantFile.addHeaderLine(liness.str());

    cout << variantFile.header << endl;

    // check that we can use the scaling key
    if (!scaleByKey.empty()) {
        if (variantFile.infoTypes.find(scaleByKey) == variantFile.infoTypes.end()) {
            cerr << "could not find info key " << scaleByKey << endl;
            exit(1);
        } else {
            if (variantFile.infoTypes[scaleByKey] != FIELD_FLOAT) {
                cerr << "cannot use " << scaleByKey << " as a scaling factor, as it is not of type Float" << endl;
                exit(1);
            }
        }
    }

    Variant var(variantFile);
    while (variantFile.getNextVariant(var)) {
        double randN = genrand_real1();
        if (!scaleByKey.empty()) {
            if (var.info.find(scaleByKey) != var.info.end()) {
                double val;

                // hack, sum the values of interest if we have multiple values
                // really, this is only suitable for AF stuff
                vector<string>& vals = var.info[scaleByKey];
                for (vector<string>::iterator b = vals.begin(); b != vals.end(); ++b) {
                    double f;
                    convert(*b, f);
                    val += f;
                }
                val /= vals.size();

                if (val > 1) {
                    cerr << "cannot scale by " << scaleByKey << "=" << val << " as it is > 1" << endl;
                    exit(1);
                }
                randN *= val;
            }
        }
        if (randN < rate) {
            cout << var << endl;
        }
    }

    return 0;

}
<commit_msg>vcfrandomsample: initialize variable when calculating sum.<commit_after>/*
    vcflib C++ library for parsing and manipulating VCF files

    Copyright © 2010-2020 Erik Garrison
    Copyright © 2020      Pjotr Prins

    This software is published under the MIT License. See the LICENSE file.
*/

#include "Variant.h"
#include "BedReader.h"
#include <getopt.h>
#include "mt19937ar.h"
#include <sstream>
#include <iostream>
#include "convert.h"

using namespace std;
using namespace vcflib;

void printSummary(char** argv) {
    cerr << "usage: " << argv[0] << " [options] [<vcf file>]" << endl
         << endl
         << "options:" << endl
         << "    -r, --rate RATE          base sampling probability per locus" << endl
         << "    -s, --scale-by KEY       scale sampling likelihood by this Float info field" << endl
         << "    -p, --random-seed N      use this random seed (by default read from /dev/random)" << endl
         << "    -q, --pseudorandom-seed  use a pseudorandom seed (by default read from /dev/random)" << endl
         << endl
         << "Randomly sample sites from an input VCF file, which may be provided as stdin." << endl
         << "Scale the sampling probability by the field specified in KEY.  This may be" << endl
         << "used to provide uniform sampling across allele frequencies, for instance." << endl;
    cerr << endl << "Type: statistics" << endl << endl;

    exit(0);
}

int main(int argc, char** argv) {

    double rate = 1.0;
    int seed = 0;
    bool useprng = false;
    string scaleByKey;

    if (argc == 1)
        printSummary(argv);

    int c;
    while (true) {
        static struct option long_options[] =
            {
                {"help", no_argument, 0, 'h'},
                {"rate",  required_argument, 0, 'r'},
                {"scale-by",  required_argument, 0, 's'},
                {"random-seed",  required_argument, 0, 'p'},
                {"pseudorandom-seed",  required_argument, 0, 'q'},
                {0, 0, 0, 0}
            };

        int option_index = 0;
        c = getopt_long (argc, argv, "hqr:s:p:",
                         long_options, &option_index);

        if (c == -1)
            break;

        switch (c) {
        case 'r':
            rate = atof(optarg);
            break;

        case 's':
            scaleByKey = optarg;
            break;

        case 'p':
            seed = atoi(optarg);
            break;

        case 'q':
            useprng = true;
            break;

        case 'h':
            printSummary(argv);
            break;

        case '?':
            printSummary(argv);
            exit(1);
            break;

        default:
            abort ();
        }
    }

    VariantCallFile variantFile;
    string inputFilename;
    if (optind == argc - 1) {
        inputFilename = argv[optind];
        variantFile.open(inputFilename);
    } else {
        variantFile.open(std::cin);
    }

    if (!variantFile.is_open()) {
        cout << "could not open VCF file" << endl;
        return 1;
    }

    // seed prng with random bits from /dev/random
    if (!seed) {
        fstream random;
        if (useprng) {
            random.open("/dev/urandom", fstream::in);
        } else {
            random.open("/dev/random", fstream::in);
        }
        random.get((char*) &seed, sizeof(int));
        random.close();
    }

    init_genrand(seed);

    vector<string> args;
    for (int i = 0; i < argc; ++i) {
        args.push_back(argv[i]);
    }

    stringstream liness;
    liness << "##sampling=\"random sampling using "
           << join(args, " ")
           << " using random seed "
           << seed << "\"";
    variantFile.addHeaderLine(liness.str());

    cout << variantFile.header << endl;

    // check that we can use the scaling key
    if (!scaleByKey.empty()) {
        if (variantFile.infoTypes.find(scaleByKey) == variantFile.infoTypes.end()) {
            cerr << "could not find info key " << scaleByKey << endl;
            exit(1);
        } else {
            if (variantFile.infoTypes[scaleByKey] != FIELD_FLOAT) {
                cerr << "cannot use " << scaleByKey << " as a scaling factor, as it is not of type Float" << endl;
                exit(1);
            }
        }
    }

    Variant var(variantFile);
    while (variantFile.getNextVariant(var)) {
        double randN = genrand_real1();
        if (!scaleByKey.empty()) {
            if (var.info.find(scaleByKey) != var.info.end()) {
                double val = 0;

                // hack, sum the values of interest if we have multiple values
                // really, this is only suitable for AF stuff
                vector<string>& vals = var.info[scaleByKey];
                for (vector<string>::iterator b = vals.begin(); b != vals.end(); ++b) {
                    double f;
                    convert(*b, f);
                    val += f;
                }
                val /= vals.size();

                if (val > 1) {
                    cerr << "cannot scale by " << scaleByKey << "=" << val << " as it is > 1" << endl;
                    exit(1);
                }
                randN *= val;
            }
        }
        if (randN < rate) {
            cout << var << endl;
        }
    }

    return 0;

}
<|endoftext|>


<commit_before>/*
 * groups.cpp
 *
 *  Created on: 4 Apr 2016
 *      Author: nick
 */

#include <map>
#include <iterator>
#include "misc.h"
#include "groups.h"
#include "mpi.h"
#include "ndm.h"
#include "pthread.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

static std::map<int, SpecificGroup*> groups;
static NDM_Group groupCurrentId;
static int myGlobalRank, globalSize;
static pthread_mutex_t currentGroupId_mutex;

static void addGroupToDirectory(NDM_Group, int, int, int*);

void initialiseGroupDirectory() {
  pthread_mutex_init(&currentGroupId_mutex, NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &myGlobalRank);
  MPI_Comm_size(MPI_COMM_WORLD, &globalSize);
  groupCurrentId = NDM_GLOBAL_GROUP + 1;
  int* groupRanks = (int*)malloc(sizeof(int) * globalSize);
  int i;
  for (i = 0; i < globalSize; i++) groupRanks[i] = i;
  addGroupToDirectory(NDM_GLOBAL_GROUP, globalSize, myGlobalRank, groupRanks);
}

static void addGroupToDirectory(NDM_Group group, int groupSize, int myGroupRank, int* groupRanks) {
  SpecificGroup* newGroup = new SpecificGroup(group, groupSize, myGroupRank, groupRanks, 1);
  groups.insert(groups.end(), std::pair<int, SpecificGroup*>(group, newGroup));
}

NDM_Group addGroup(int numberEntries, int* groupRanks) {
  int* allocatedGroupRanks = (int*)malloc(sizeof(int) * numberEntries);
  memcpy(allocatedGroupRanks, groupRanks, sizeof(int) * numberEntries);
  int myRank = -1, i;
  for (i = 0; i < numberEntries; i++) {
    if (groupRanks[i] == myGlobalRank) myRank = i;
  }
  pthread_mutex_lock(&currentGroupId_mutex);
  int specificGroupId = groupCurrentId++;
  pthread_mutex_unlock(&currentGroupId_mutex);
  addGroupToDirectory(specificGroupId, numberEntries, myRank, allocatedGroupRanks);
  return specificGroupId;
}

NDM_Group createVirtualRanksInGroup(NDM_Group baseGroup, int numberVirtualRanksPerGroup) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* groupRanks = (int*)malloc(sizeof(int) * it->second->getGroupSize() * numberVirtualRanksPerGroup);
    int i, j;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      for (j = 0; j < numberVirtualRanksPerGroup; j++) {
        groupRanks[(i * numberVirtualRanksPerGroup) + j] = it->second->getGroupEntries()[i];
      }
    }
    SpecificGroup* newGroup =
        new SpecificGroup(specificGroupId, it->second->getGroupSize() * numberVirtualRanksPerGroup,
                          it->second->getGroupEntries()[it->second->getMyGroupRank()], groupRanks, numberVirtualRanksPerGroup);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createContiguousGroupWithStride(NDM_Group baseGroup, int number_contiguous_ranks, int stride) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int myBaseRank = it->second->getMyGroupRank(), myRank = -1;
    int numberOfGroups = ceil((double)it->second->getGroupSize() / (number_contiguous_ranks + stride));
    int correction = ((number_contiguous_ranks + stride) * numberOfGroups) - it->second->getGroupSize();
    if (correction > number_contiguous_ranks) correction = number_contiguous_ranks;
    int numberOfProcesses = (numberOfGroups * number_contiguous_ranks) - correction;
    int* groupRanks = (int*)malloc(sizeof(int) * numberOfProcesses);
    int i, j = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (i % (number_contiguous_ranks + stride) >= stride) {
        groupRanks[j] = it->second->getGroupEntries()[i];
        if (i == myBaseRank) myRank = j;
        j++;
      }
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, numberOfProcesses, myRank, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createDisjointGroup(NDM_Group groupA, NDM_Group groupB) {
  std::map<int, SpecificGroup*>::iterator itA = groups.find(groupA);
  std::map<int, SpecificGroup*>::iterator itB = groups.find(groupB);
  if (itA != groups.end() && itB != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* searchedRanks = (int*)malloc(sizeof(int) * (itA->second->getGroupSize() + itB->second->getGroupSize()));
    int i, j, actualSize = 0, myExistingRank = -1, myNewRank = -1;
    if (itA->second->getMyGroupRank() >= 0) {
      myExistingRank = itA->second->getGroupEntries()[itA->second->getMyGroupRank()];
    } else if (itB->second->getMyGroupRank() >= 0) {
      myExistingRank = itB->second->getGroupEntries()[itB->second->getMyGroupRank()];
    }
    for (i = 0; i < itA->second->getGroupSize(); i++) {
      for (j = 0; j < itB->second->getGroupSize(); j++) {
        if (itA->second->getGroupEntries()[i] == itB->second->getGroupEntries()[j]) break;
      }
      if (j == itB->second->getGroupSize()) {
        if (myExistingRank == itA->second->getGroupEntries()[i]) myNewRank = actualSize;
        searchedRanks[actualSize++] = itA->second->getGroupEntries()[i];
      }
    }

    for (i = 0; i < itB->second->getGroupSize(); i++) {
      for (j = 0; j < itA->second->getGroupSize(); j++) {
        if (itA->second->getGroupEntries()[i] == itB->second->getGroupEntries()[j]) break;
      }
      if (j == itA->second->getGroupSize()) {
        if (myExistingRank == itB->second->getGroupEntries()[i]) myNewRank = actualSize;
        searchedRanks[actualSize++] = itB->second->getGroupEntries()[i];
      }
    }

    searchedRanks = (int*)realloc(searchedRanks, sizeof(int) * actualSize);
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, actualSize, myNewRank, searchedRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing one of the groups provided not found");
    return -1;
  }
}

NDM_Group extractGroupBasedOnSizeAndRank(NDM_Group baseGroup, int size, int myrank) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);

    int* groupRanks = (int*)malloc(sizeof(int) * size);
    int i, startingPoint = size * (myrank / size),
           endPoint = it->second->getGroupSize() < startingPoint + size ? it->second->getGroupSize() : startingPoint + size;
    for (i = startingPoint; i < endPoint; i++) {
      groupRanks[i - startingPoint] = it->second->getGroupEntries()[i];
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, size, myrank - startingPoint, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

int getLocalNthGroupRank(NDM_Group group, int n) {
  if (n < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    int myGroupRank = it->second->getMyGroupRank();
    int i, occurances = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (it->second->getGroupEntries()[i] == myGroupRank) {
        if (occurances == n) return i;
        occurances++;
      }
    }
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getNumberDistinctProcesses(NDM_Group group) {
  if (group == NDM_GLOBAL_GROUP) {
    return globalSize;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      return it->second->getGroupSize() / it->second->getRanksPerProcess();
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int translateRankFromGroup(NDM_Group group, int groupRank) {
  if (groupRank < 0) raiseError("Negative group ranks is not allowed");
  if (group == NDM_GLOBAL_GROUP) {
    if (groupRank >= globalSize) raiseError("Group rank exceeds group size");
    return groupRank;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      if (groupRank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
      return it->second->getGroupToGlobalRank(groupRank);
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int isRankLocalToGroup(NDM_Group group, int rank) {
  if (rank < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    if (rank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
    return it->second->getGroupToGlobalRank(rank) == it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return 0;
}

int getGroupLocalSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getRanksPerProcess();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getMyGroupRank(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getGroupSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getGroupSize();
  } else {
    raiseError("Group not found");
  }
  return -1;
}
<commit_msg>Fix to incorrect size in extracting of groups<commit_after>/*
 * groups.cpp
 *
 *  Created on: 4 Apr 2016
 *      Author: nick
 */

#include <map>
#include <iterator>
#include "misc.h"
#include "groups.h"
#include "mpi.h"
#include "ndm.h"
#include "pthread.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

static std::map<int, SpecificGroup*> groups;
static NDM_Group groupCurrentId;
static int myGlobalRank, globalSize;
static pthread_mutex_t currentGroupId_mutex;

static void addGroupToDirectory(NDM_Group, int, int, int*);

void initialiseGroupDirectory() {
  pthread_mutex_init(&currentGroupId_mutex, NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &myGlobalRank);
  MPI_Comm_size(MPI_COMM_WORLD, &globalSize);
  groupCurrentId = NDM_GLOBAL_GROUP + 1;
  int* groupRanks = (int*)malloc(sizeof(int) * globalSize);
  int i;
  for (i = 0; i < globalSize; i++) groupRanks[i] = i;
  addGroupToDirectory(NDM_GLOBAL_GROUP, globalSize, myGlobalRank, groupRanks);
}

static void addGroupToDirectory(NDM_Group group, int groupSize, int myGroupRank, int* groupRanks) {
  SpecificGroup* newGroup = new SpecificGroup(group, groupSize, myGroupRank, groupRanks, 1);
  groups.insert(groups.end(), std::pair<int, SpecificGroup*>(group, newGroup));
}

NDM_Group addGroup(int numberEntries, int* groupRanks) {
  int* allocatedGroupRanks = (int*)malloc(sizeof(int) * numberEntries);
  memcpy(allocatedGroupRanks, groupRanks, sizeof(int) * numberEntries);
  int myRank = -1, i;
  for (i = 0; i < numberEntries; i++) {
    if (groupRanks[i] == myGlobalRank) myRank = i;
  }
  pthread_mutex_lock(&currentGroupId_mutex);
  int specificGroupId = groupCurrentId++;
  pthread_mutex_unlock(&currentGroupId_mutex);
  addGroupToDirectory(specificGroupId, numberEntries, myRank, allocatedGroupRanks);
  return specificGroupId;
}

NDM_Group createVirtualRanksInGroup(NDM_Group baseGroup, int numberVirtualRanksPerGroup) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* groupRanks = (int*)malloc(sizeof(int) * it->second->getGroupSize() * numberVirtualRanksPerGroup);
    int i, j;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      for (j = 0; j < numberVirtualRanksPerGroup; j++) {
        groupRanks[(i * numberVirtualRanksPerGroup) + j] = it->second->getGroupEntries()[i];
      }
    }
    SpecificGroup* newGroup =
        new SpecificGroup(specificGroupId, it->second->getGroupSize() * numberVirtualRanksPerGroup,
                          it->second->getGroupEntries()[it->second->getMyGroupRank()], groupRanks, numberVirtualRanksPerGroup);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createContiguousGroupWithStride(NDM_Group baseGroup, int number_contiguous_ranks, int stride) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int myBaseRank = it->second->getMyGroupRank(), myRank = -1;
    int numberOfGroups = ceil((double)it->second->getGroupSize() / (number_contiguous_ranks + stride));
    int correction = ((number_contiguous_ranks + stride) * numberOfGroups) - it->second->getGroupSize();
    if (correction > number_contiguous_ranks) correction = number_contiguous_ranks;
    int numberOfProcesses = (numberOfGroups * number_contiguous_ranks) - correction;
    int* groupRanks = (int*)malloc(sizeof(int) * numberOfProcesses);
    int i, j = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (i % (number_contiguous_ranks + stride) >= stride) {
        groupRanks[j] = it->second->getGroupEntries()[i];
        if (i == myBaseRank) myRank = j;
        j++;
      }
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, numberOfProcesses, myRank, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createDisjointGroup(NDM_Group groupA, NDM_Group groupB) {
  std::map<int, SpecificGroup*>::iterator itA = groups.find(groupA);
  std::map<int, SpecificGroup*>::iterator itB = groups.find(groupB);
  if (itA != groups.end() && itB != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* searchedRanks = (int*)malloc(sizeof(int) * (itA->second->getGroupSize() + itB->second->getGroupSize()));
    int i, j, actualSize = 0, myExistingRank = -1, myNewRank = -1;
    if (itA->second->getMyGroupRank() >= 0) {
      myExistingRank = itA->second->getGroupEntries()[itA->second->getMyGroupRank()];
    } else if (itB->second->getMyGroupRank() >= 0) {
      myExistingRank = itB->second->getGroupEntries()[itB->second->getMyGroupRank()];
    }
    for (i = 0; i < itA->second->getGroupSize(); i++) {
      for (j = 0; j < itB->second->getGroupSize(); j++) {
        if (itA->second->getGroupEntries()[i] == itB->second->getGroupEntries()[j]) break;
      }
      if (j == itB->second->getGroupSize()) {
        if (myExistingRank == itA->second->getGroupEntries()[i]) myNewRank = actualSize;
        searchedRanks[actualSize++] = itA->second->getGroupEntries()[i];
      }
    }

    for (i = 0; i < itB->second->getGroupSize(); i++) {
      for (j = 0; j < itA->second->getGroupSize(); j++) {
        if (itA->second->getGroupEntries()[i] == itB->second->getGroupEntries()[j]) break;
      }
      if (j == itA->second->getGroupSize()) {
        if (myExistingRank == itB->second->getGroupEntries()[i]) myNewRank = actualSize;
        searchedRanks[actualSize++] = itB->second->getGroupEntries()[i];
      }
    }

    searchedRanks = (int*)realloc(searchedRanks, sizeof(int) * actualSize);
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, actualSize, myNewRank, searchedRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing one of the groups provided not found");
    return -1;
  }
}

NDM_Group extractGroupBasedOnSizeAndRank(NDM_Group baseGroup, int size, int myrank) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);

    int i, startingPoint = size * (myrank / size),
           endPoint = it->second->getGroupSize() < startingPoint + size ? it->second->getGroupSize() : startingPoint + size;
    int* groupRanks = (int*)malloc(sizeof(int) * (endPoint - startingPoint));
    for (i = startingPoint; i < endPoint; i++) {
      groupRanks[i - startingPoint] = it->second->getGroupEntries()[i];
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, endPoint - startingPoint, myrank - startingPoint, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

int getLocalNthGroupRank(NDM_Group group, int n) {
  if (n < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    int myGroupRank = it->second->getMyGroupRank();
    int i, occurances = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (it->second->getGroupEntries()[i] == myGroupRank) {
        if (occurances == n) return i;
        occurances++;
      }
    }
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getNumberDistinctProcesses(NDM_Group group) {
  if (group == NDM_GLOBAL_GROUP) {
    return globalSize;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      return it->second->getGroupSize() / it->second->getRanksPerProcess();
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int translateRankFromGroup(NDM_Group group, int groupRank) {
  if (groupRank < 0) raiseError("Negative group ranks is not allowed");
  if (group == NDM_GLOBAL_GROUP) {
    if (groupRank >= globalSize) raiseError("Group rank exceeds group size");
    return groupRank;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      if (groupRank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
      return it->second->getGroupToGlobalRank(groupRank);
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int isRankLocalToGroup(NDM_Group group, int rank) {
  if (rank < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    if (rank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
    return it->second->getGroupToGlobalRank(rank) == it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return 0;
}

int getGroupLocalSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getRanksPerProcess();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getMyGroupRank(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getGroupSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getGroupSize();
  } else {
    raiseError("Group not found");
  }
  return -1;
}
<|endoftext|>


<commit_before>/*Copyright 2010 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include "myflattreemodel.h"

using namespace GUtil::QtUtil;

myFlatTreeModel::myFlatTreeModel(QObject *parent) :
    QAbstractProxyModel(parent)
{
}

void myFlatTreeModel::setSourceModel(QAbstractItemModel *m)
{
    QAbstractItemModel *curmodel = sourceModel();
    if(curmodel == m)
    {
        refreshSourceModel();
        return;
    }

    if(curmodel)
    {
        curmodel->disconnect(this, SLOT(source_model_about_to_be_reset()));
        curmodel->disconnect(this, SLOT(source_model_reset()));
        curmodel->disconnect(this, SLOT(source_model_data_changed(QModelIndex,QModelIndex)));
    }

    QAbstractProxyModel::setSourceModel(m);

    if(m)
    {
        // So we can reset ourself when something changes
        connect(m, SIGNAL(modelAboutToBeReset()), this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(modelReset()), this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsInserted(QModelIndex, int, int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsRemoved(QModelIndex, int, int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
                this, SLOT(source_model_data_changed(QModelIndex,QModelIndex)));

        _reset_model();
    }
}

void myFlatTreeModel::source_model_data_changed(const QModelIndex &ind1, const QModelIndex &ind2)
{
    emit dataChanged(mapFromSource(ind1), mapFromSource(ind2));
}

void myFlatTreeModel::source_model_about_to_be_reset()
{
    beginResetModel();
}

void myFlatTreeModel::source_model_reset()
{
    // This is an expensive operation, so we only do it once, storing
    //  the results we calculate for quick lookup while we refresh the indexes
    _refresh_child_record();

    _index_map_to_source.clear();
    _index_map_from_source.clear();
    _refresh_index_mapping();

    // To save memory we'll clear this map 'cause we don't use it after here
    _child_record.clear();

    endResetModel();
}

void myFlatTreeModel::refreshSourceModel()
{
    _reset_model();
}

void myFlatTreeModel::_reset_model()
{
    beginResetModel();
    source_model_reset();
}

void myFlatTreeModel::_refresh_child_record()
{
    _total_rows = 0;

    QAbstractItemModel *m = sourceModel();
    if(m)
    {
        for(int i = sourceModel()->rowCount() - 1; i >= 0; i--)
        {
            _total_rows += _count_child_indexes(m->index(i, 0));
        }
    }
}

QModelIndex myFlatTreeModel::mapToSource(const QModelIndex &proxyIndex) const
{
    return _index_map_to_source[proxyIndex.internalId()];
}

QModelIndex myFlatTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    int t = _index_map_from_source[sourceIndex.internalId()];
    if(t == 0 || !sourceIndex.isValid())
        return QModelIndex();
    return index(t, sourceIndex.column());
}

QModelIndex myFlatTreeModel::_map_from_source(const QModelIndex &sourceIndex)
{
    if(sourceModel())
        return index(_count_preceeding_indexes(sourceIndex) - 1, sourceIndex.column());
    return QModelIndex();
}

int myFlatTreeModel::_count_preceeding_indexes(const QModelIndex &ind) const
{
    if(!ind.isValid())
        return 0;

    QAbstractItemModel *m = sourceModel();
    int ret = 1;

    // Ascend the tree hierarchy towards the top and count all the indexes
    //  before me but still under the same parent
    for(int i = ind.row() - 1; i >= 0; i--)
    {
        ret += _child_record[m->index(i, 0, ind.parent()).internalId()];
    }

    // Then add in my parent's preceeding indeces
    ret += _count_preceeding_indexes(ind.parent());

    return ret;
}

int myFlatTreeModel::_count_child_indexes(const QModelIndex &ind)
{
    // Start with one to account for 'ind'
    int ret = 1;

    QAbstractItemModel *m = sourceModel();
    int children = m->rowCount(ind);
    for(int i = 0; i < children; i++)
    {
        ret += _count_child_indexes(m->index(i, 0, ind));
    }

    // Remember this result for later
    _child_record.insert(ind.internalId(), ret);

    return ret;
}

void myFlatTreeModel::_refresh_index_mapping(const QModelIndex &ind)
{
    QAbstractItemModel *sm = sourceModel();
    for(int i = sm->rowCount(ind) - 1; i >= 0; i--)
    {
        QModelIndex targ = sm->index(i, 0, ind);
        QModelIndex proxy_index = _map_from_source(targ);

        _index_map_to_source.insert(proxy_index.internalId(), QPersistentModelIndex(targ));
        _index_map_from_source.insert(targ.internalId(), proxy_index.row());

        _refresh_index_mapping(targ);
    }
}

QModelIndex myFlatTreeModel::parent(const QModelIndex &) const
{
    // We're a flat table
    return QModelIndex();
}

QModelIndex myFlatTreeModel::index(int row, int column, const QModelIndex &par) const
{
    if(par.isValid())
        return QModelIndex();

    // Use the row as a unique id
    return createIndex(row, column, row);
}

int myFlatTreeModel::rowCount(const QModelIndex &parent) const
{
    if(parent.isValid())
        return 0;

    return _total_rows;
}

int myFlatTreeModel::columnCount(const QModelIndex &parent) const
{
    QAbstractItemModel *m = sourceModel();
    if(m)
        return m->columnCount(mapToSource(parent));
    return 0;
}

QVariant myFlatTreeModel::data(const QModelIndex &proxyIndex, int role) const
{
    return mapToSource(proxyIndex).data(role);
}
<commit_msg>Fixed a bug, now it resets even when source model set to 0<commit_after>/*Copyright 2010 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include "myflattreemodel.h"

using namespace GUtil::QtUtil;

myFlatTreeModel::myFlatTreeModel(QObject *parent) :
    QAbstractProxyModel(parent)
{
}

void myFlatTreeModel::setSourceModel(QAbstractItemModel *m)
{
    QAbstractItemModel *curmodel = sourceModel();
    if(curmodel == m)
    {
        refreshSourceModel();
        return;
    }

    if(curmodel)
    {
        curmodel->disconnect(this, SLOT(source_model_about_to_be_reset()));
        curmodel->disconnect(this, SLOT(source_model_reset()));
        curmodel->disconnect(this, SLOT(source_model_data_changed(QModelIndex,QModelIndex)));
    }

    QAbstractProxyModel::setSourceModel(m);

    if(m)
    {
        // So we can reset ourself when something changes
        connect(m, SIGNAL(modelAboutToBeReset()), this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(modelReset()), this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsInserted(QModelIndex, int, int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsRemoved(QModelIndex, int, int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
                this, SLOT(source_model_about_to_be_reset()));
        connect(m, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
                this, SLOT(source_model_reset()));

        connect(m, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
                this, SLOT(source_model_data_changed(QModelIndex,QModelIndex)));
    }

    _reset_model();
}

void myFlatTreeModel::source_model_data_changed(const QModelIndex &ind1, const QModelIndex &ind2)
{
    emit dataChanged(mapFromSource(ind1), mapFromSource(ind2));
}

void myFlatTreeModel::source_model_about_to_be_reset()
{
    beginResetModel();
}

void myFlatTreeModel::source_model_reset()
{
    // This is an expensive operation, so we only do it once, storing
    //  the results we calculate for quick lookup while we refresh the indexes
    _refresh_child_record();

    _index_map_to_source.clear();
    _index_map_from_source.clear();
    _refresh_index_mapping();

    // To save memory we'll clear this map 'cause we don't use it after here
    _child_record.clear();

    endResetModel();
}

void myFlatTreeModel::refreshSourceModel()
{
    _reset_model();
}

void myFlatTreeModel::_reset_model()
{
    beginResetModel();
    source_model_reset();
}

void myFlatTreeModel::_refresh_child_record()
{
    _total_rows = 0;

    QAbstractItemModel *m = sourceModel();
    if(m)
    {
        for(int i = sourceModel()->rowCount() - 1; i >= 0; i--)
        {
            _total_rows += _count_child_indexes(m->index(i, 0));
        }
    }
}

QModelIndex myFlatTreeModel::mapToSource(const QModelIndex &proxyIndex) const
{
    return _index_map_to_source[proxyIndex.internalId()];
}

QModelIndex myFlatTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    int t = _index_map_from_source[sourceIndex.internalId()];
    if(t == 0 || !sourceIndex.isValid())
        return QModelIndex();
    return index(t, sourceIndex.column());
}

QModelIndex myFlatTreeModel::_map_from_source(const QModelIndex &sourceIndex)
{
    if(sourceModel())
        return index(_count_preceeding_indexes(sourceIndex) - 1, sourceIndex.column());
    return QModelIndex();
}

int myFlatTreeModel::_count_preceeding_indexes(const QModelIndex &ind) const
{
    if(!ind.isValid())
        return 0;

    QAbstractItemModel *m = sourceModel();
    int ret = 1;

    // Ascend the tree hierarchy towards the top and count all the indexes
    //  before me but still under the same parent
    for(int i = ind.row() - 1; i >= 0; i--)
    {
        ret += _child_record[m->index(i, 0, ind.parent()).internalId()];
    }

    // Then add in my parent's preceeding indeces
    ret += _count_preceeding_indexes(ind.parent());

    return ret;
}

int myFlatTreeModel::_count_child_indexes(const QModelIndex &ind)
{
    // Start with one to account for 'ind'
    int ret = 1;

    QAbstractItemModel *m = sourceModel();
    int children = m->rowCount(ind);
    for(int i = 0; i < children; i++)
    {
        ret += _count_child_indexes(m->index(i, 0, ind));
    }

    // Remember this result for later
    _child_record.insert(ind.internalId(), ret);

    return ret;
}

void myFlatTreeModel::_refresh_index_mapping(const QModelIndex &ind)
{
    QAbstractItemModel *sm = sourceModel();
    if(sm)
    {
        for(int i = sm->rowCount(ind) - 1; i >= 0; i--)
        {
            QModelIndex targ = sm->index(i, 0, ind);
            QModelIndex proxy_index = _map_from_source(targ);

            _index_map_to_source.insert(proxy_index.internalId(), QPersistentModelIndex(targ));
            _index_map_from_source.insert(targ.internalId(), proxy_index.row());

            _refresh_index_mapping(targ);
        }
    }
}

QModelIndex myFlatTreeModel::parent(const QModelIndex &) const
{
    // We're a flat table
    return QModelIndex();
}

QModelIndex myFlatTreeModel::index(int row, int column, const QModelIndex &par) const
{
    if(par.isValid())
        return QModelIndex();

    // Use the row as a unique id
    return createIndex(row, column, row);
}

int myFlatTreeModel::rowCount(const QModelIndex &parent) const
{
    if(parent.isValid())
        return 0;

    return _total_rows;
}

int myFlatTreeModel::columnCount(const QModelIndex &parent) const
{
    QAbstractItemModel *m = sourceModel();
    if(m)
        return m->columnCount(mapToSource(parent));
    return 0;
}

QVariant myFlatTreeModel::data(const QModelIndex &proxyIndex, int role) const
{
    return mapToSource(proxyIndex).data(role);
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTextBox.h"
#include "../core/SkGlyphCache.h"
#include "SkUtils.h"
#include "SkAutoKern.h"

static inline int is_ws(int c)
{
    return !((c - 1) >> 5);
}

static size_t linebreak(const char text[], const char stop[], const SkPaint& paint, SkScalar margin)
{
    const char* start = text;

    SkAutoGlyphCache    ac(paint, NULL);
    SkGlyphCache*       cache = ac.getCache();
    SkFixed             w = 0;
    SkFixed             limit = SkScalarToFixed(margin);
    SkAutoKern          autokern;

    const char* word_start = text;
    int         prevWS = true;

    while (text < stop)
    {
        const char* prevText = text;
        SkUnichar   uni = SkUTF8_NextUnichar(&text);
        int         currWS = is_ws(uni);
        const SkGlyph&  glyph = cache->getUnicharMetrics(uni);

        if (!currWS && prevWS)
            word_start = prevText;
        prevWS = currWS;

        w += autokern.adjust(glyph) + glyph.fAdvanceX;
        if (w > limit)
        {
            if (currWS) // eat the rest of the whitespace
            {
                while (text < stop && is_ws(SkUTF8_ToUnichar(text)))
                    text += SkUTF8_CountUTF8Bytes(text);
            }
            else    // backup until a whitespace (or 1 char)
            {
                if (word_start == start)
                {
                    if (prevText > start)
                        text = prevText;
                }
                else
                    text = word_start;
            }
            break;
        }
    }
    return text - start;
}

int SkTextLineBreaker::CountLines(const char text[], size_t len, const SkPaint& paint, SkScalar width)
{
    const char* stop = text + len;
    int         count = 0;

    if (width > 0)
    {
        do {
            count += 1;
            text += linebreak(text, stop, paint, width);
        } while (text < stop);
    }
    return count;
}

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

SkTextBox::SkTextBox()
{
    fBox.setEmpty();
    fSpacingMul = SK_Scalar1;
    fSpacingAdd = 0;
    fMode = kLineBreak_Mode;
    fSpacingAlign = kStart_SpacingAlign;
}

void SkTextBox::setMode(Mode mode)
{
    SkASSERT((unsigned)mode < kModeCount);
    fMode = SkToU8(mode);
}

void SkTextBox::setSpacingAlign(SpacingAlign align)
{
    SkASSERT((unsigned)align < kSpacingAlignCount);
    fSpacingAlign = SkToU8(align);
}

void SkTextBox::getBox(SkRect* box) const
{
    if (box)
        *box = fBox;
}

void SkTextBox::setBox(const SkRect& box)
{
    fBox = box;
}

void SkTextBox::setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
{
    fBox.set(left, top, right, bottom);
}

void SkTextBox::getSpacing(SkScalar* mul, SkScalar* add) const
{
    if (mul)
        *mul = fSpacingMul;
    if (add)
        *add = fSpacingAdd;
}

void SkTextBox::setSpacing(SkScalar mul, SkScalar add)
{
    fSpacingMul = mul;
    fSpacingAdd = add;
}

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

void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint)
{
    SkASSERT(canvas && &paint && (text || len == 0));

    SkScalar marginWidth = fBox.width();

    if (marginWidth <= 0 || len == 0)
        return;

    const char* textStop = text + len;

    SkScalar                x, y, scaledSpacing, height, fontHeight;
    SkPaint::FontMetrics    metrics;

    switch (paint.getTextAlign()) {
    case SkPaint::kLeft_Align:
        x = 0;
        break;
    case SkPaint::kCenter_Align:
        x = SkScalarHalf(marginWidth);
        break;
    default:
        x = marginWidth;
        break;
    }
    x += fBox.fLeft;

    fontHeight = paint.getFontMetrics(&metrics);
    scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd;
    height = fBox.height();

    //  compute Y position for first line
    {
        SkScalar textHeight = fontHeight;

        if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign)
        {
            int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth);
            SkASSERT(count > 0);
            textHeight += scaledSpacing * (count - 1);
        }

        switch (fSpacingAlign) {
        case kStart_SpacingAlign:
            y = 0;
            break;
        case kCenter_SpacingAlign:
            y = SkScalarHalf(height - textHeight);
            break;
        default:
            SkASSERT(fSpacingAlign == kEnd_SpacingAlign);
            y = height - textHeight;
            break;
        }
        y += fBox.fTop - metrics.fAscent;
    }

    for (;;)
    {
        len = linebreak(text, textStop, paint, marginWidth);
        if (y + metrics.fDescent + metrics.fLeading > 0)
            canvas->drawText(text, len, x, y, paint);
        text += len;
        if (text >= textStop)
            break;
        y += scaledSpacing;
        if (y + metrics.fAscent >= height)
            break;
    }
}

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

void SkTextBox::setText(const char text[], size_t len, const SkPaint& paint) {
    fText = text;
    fLen = len;
    fPaint = &paint;
}

void SkTextBox::draw(SkCanvas* canvas) {
    this->draw(canvas, fText, fLen, *fPaint);
}

int SkTextBox::countLines() const {
    return SkTextLineBreaker::CountLines(fText, fLen, *fPaint, fBox.width());
}

SkScalar SkTextBox::getTextHeight() const {
    SkScalar spacing = SkScalarMul(fPaint->getTextSize(), fSpacingMul) + fSpacingAdd;
    return this->countLines() * spacing;
}

<commit_msg>SkTextBox to use public interfaces for line layout. https://codereview.appspot.com/6438044/<commit_after>/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTextBox.h"
#include "SkUtils.h"

static inline int is_ws(int c)
{
    return !((c - 1) >> 5);
}

static size_t linebreak(const char text[], const char stop[], const SkPaint& paint, SkScalar margin)
{
    return paint.breakText(text, stop - text, margin);
}

int SkTextLineBreaker::CountLines(const char text[], size_t len, const SkPaint& paint, SkScalar width)
{
    const char* stop = text + len;
    int         count = 0;

    if (width > 0)
    {
        do {
            count += 1;
            text += linebreak(text, stop, paint, width);
        } while (text < stop);
    }
    return count;
}

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

SkTextBox::SkTextBox()
{
    fBox.setEmpty();
    fSpacingMul = SK_Scalar1;
    fSpacingAdd = 0;
    fMode = kLineBreak_Mode;
    fSpacingAlign = kStart_SpacingAlign;
}

void SkTextBox::setMode(Mode mode)
{
    SkASSERT((unsigned)mode < kModeCount);
    fMode = SkToU8(mode);
}

void SkTextBox::setSpacingAlign(SpacingAlign align)
{
    SkASSERT((unsigned)align < kSpacingAlignCount);
    fSpacingAlign = SkToU8(align);
}

void SkTextBox::getBox(SkRect* box) const
{
    if (box)
        *box = fBox;
}

void SkTextBox::setBox(const SkRect& box)
{
    fBox = box;
}

void SkTextBox::setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
{
    fBox.set(left, top, right, bottom);
}

void SkTextBox::getSpacing(SkScalar* mul, SkScalar* add) const
{
    if (mul)
        *mul = fSpacingMul;
    if (add)
        *add = fSpacingAdd;
}

void SkTextBox::setSpacing(SkScalar mul, SkScalar add)
{
    fSpacingMul = mul;
    fSpacingAdd = add;
}

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

void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint)
{
    SkASSERT(canvas && &paint && (text || len == 0));

    SkScalar marginWidth = fBox.width();

    if (marginWidth <= 0 || len == 0)
        return;

    const char* textStop = text + len;

    SkScalar                x, y, scaledSpacing, height, fontHeight;
    SkPaint::FontMetrics    metrics;

    switch (paint.getTextAlign()) {
    case SkPaint::kLeft_Align:
        x = 0;
        break;
    case SkPaint::kCenter_Align:
        x = SkScalarHalf(marginWidth);
        break;
    default:
        x = marginWidth;
        break;
    }
    x += fBox.fLeft;

    fontHeight = paint.getFontMetrics(&metrics);
    scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd;
    height = fBox.height();

    //  compute Y position for first line
    {
        SkScalar textHeight = fontHeight;

        if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign)
        {
            int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth);
            SkASSERT(count > 0);
            textHeight += scaledSpacing * (count - 1);
        }

        switch (fSpacingAlign) {
        case kStart_SpacingAlign:
            y = 0;
            break;
        case kCenter_SpacingAlign:
            y = SkScalarHalf(height - textHeight);
            break;
        default:
            SkASSERT(fSpacingAlign == kEnd_SpacingAlign);
            y = height - textHeight;
            break;
        }
        y += fBox.fTop - metrics.fAscent;
    }

    for (;;)
    {
        len = linebreak(text, textStop, paint, marginWidth);
        if (y + metrics.fDescent + metrics.fLeading > 0)
            canvas->drawText(text, len, x, y, paint);
        text += len;
        if (text >= textStop)
            break;
        y += scaledSpacing;
        if (y + metrics.fAscent >= height)
            break;
    }
}

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

void SkTextBox::setText(const char text[], size_t len, const SkPaint& paint) {
    fText = text;
    fLen = len;
    fPaint = &paint;
}

void SkTextBox::draw(SkCanvas* canvas) {
    this->draw(canvas, fText, fLen, *fPaint);
}

int SkTextBox::countLines() const {
    return SkTextLineBreaker::CountLines(fText, fLen, *fPaint, fBox.width());
}

SkScalar SkTextBox::getTextHeight() const {
    SkScalar spacing = SkScalarMul(fPaint->getTextSize(), fSpacingMul) + fSpacingAdd;
    return this->countLines() * spacing;
}

<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/egl_sync.h"

#include "tensorflow/lite/delegates/gpu/gl/gl_call.h"

namespace tflite {
namespace gpu {
namespace cl {

namespace {

bool HasExtension(EGLDisplay display, const char* extension) {
  const char* extensions = eglQueryString(display, EGL_EXTENSIONS);
  return extensions && std::strstr(extensions, extension);
}

bool IsEglFenceSyncSupported(EGLDisplay display) {
  static bool supported = HasExtension(display, "EGL_KHR_fence_sync");
  return supported;
}

bool IsEglWaitSyncSupported(EGLDisplay display) {
  static bool supported = HasExtension(display, "EGL_KHR_wait_sync");
  return supported;
}

}  // anonymous namespace

absl::Status EglSync::NewFence(EGLDisplay display, EglSync* sync) {
  static auto* egl_create_sync_khr =
      reinterpret_cast<decltype(&eglCreateSyncKHR)>(
          eglGetProcAddress("eglCreateSyncKHR"));
  if (!IsEglFenceSyncSupported(display) || egl_create_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    return absl::InternalError(
        "Not supported / bad EGL implementation: eglCreateSyncKHR.");
  }
  EGLSyncKHR egl_sync;
  RETURN_IF_ERROR(TFLITE_GPU_CALL_EGL(*egl_create_sync_khr, &egl_sync, display,
                                      EGL_SYNC_FENCE_KHR, nullptr));
  if (egl_sync == EGL_NO_SYNC_KHR) {
    return absl::InternalError("Returned empty KHR EGL sync");
  }
  *sync = EglSync(display, egl_sync);
  return absl::OkStatus();
}

EglSync& EglSync::operator=(EglSync&& sync) {
  if (this != &sync) {
    Invalidate();
    std::swap(sync_, sync.sync_);
    display_ = sync.display_;
  }
  return *this;
}

void EglSync::Invalidate() {
  if (sync_ != EGL_NO_SYNC_KHR) {
    static auto* egl_destroy_sync_khr =
        reinterpret_cast<decltype(&eglDestroySyncKHR)>(
            eglGetProcAddress("eglDestroySyncKHR"));
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    if (IsEglFenceSyncSupported(display_) && egl_destroy_sync_khr) {
      // Note: we're doing nothing when the function pointer is nullptr, or the
      // call returns EGL_FALSE.
      (*egl_destroy_sync_khr)(display_, sync_);
    }
    sync_ = EGL_NO_SYNC_KHR;
  }
}

absl::Status EglSync::ServerWait() {
  static auto* egl_wait_sync_khr = reinterpret_cast<decltype(&eglWaitSyncKHR)>(
      eglGetProcAddress("eglWaitSyncKHR"));
  if (!IsEglWaitSyncSupported(display_) || egl_wait_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_wait_sync
    return absl::InternalError("Not supported: eglWaitSyncKHR.");
  }
  EGLint result;
  RETURN_IF_ERROR(
      TFLITE_GPU_CALL_EGL(*egl_wait_sync_khr, &result, display_, sync_, 0));
  return result == EGL_TRUE ? absl::OkStatus()
                            : absl::InternalError("eglWaitSync failed");
}

absl::Status EglSync::ClientWait() {
  static auto* egl_client_wait_sync_khr =
      reinterpret_cast<decltype(&eglClientWaitSyncKHR)>(
          eglGetProcAddress("eglClientWaitSyncKHR"));
  if (!IsEglFenceSyncSupported(display_) ||
      egl_client_wait_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    return absl::InternalError("Not supported: eglClientWaitSyncKHR.");
  }
  EGLint result;
  // TODO(akulik): make it active wait for better performance
  RETURN_IF_ERROR(
      TFLITE_GPU_CALL_EGL(*egl_client_wait_sync_khr, &result, display_, sync_,
                          EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
  return result == EGL_CONDITION_SATISFIED_KHR
             ? absl::OkStatus()
             : absl::InternalError("eglClientWaitSync failed");
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>tflite/egl_sync: Return early if extensions are not supported<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/egl_sync.h"

#include "tensorflow/lite/delegates/gpu/gl/gl_call.h"

namespace tflite {
namespace gpu {
namespace cl {

namespace {

bool HasExtension(EGLDisplay display, const char* extension) {
  const char* extensions = eglQueryString(display, EGL_EXTENSIONS);
  return extensions && std::strstr(extensions, extension);
}

absl::Status IsEglFenceSyncSupported(EGLDisplay display) {
  static bool supported = HasExtension(display, "EGL_KHR_fence_sync");
  if (supported) {
    return absl::OkStatus();
  }
  return absl::InternalError("Not supported: EGL_KHR_fence_sync");
}

absl::Status IsEglWaitSyncSupported(EGLDisplay display) {
  static bool supported = HasExtension(display, "EGL_KHR_wait_sync");
  if (supported) {
    return absl::OkStatus();
  }
  return absl::InternalError("Not supported: EGL_KHR_wait_sync");
}

}  // anonymous namespace

absl::Status EglSync::NewFence(EGLDisplay display, EglSync* sync) {
  RETURN_IF_ERROR(IsEglFenceSyncSupported(display));
  static auto* egl_create_sync_khr =
      reinterpret_cast<decltype(&eglCreateSyncKHR)>(
          eglGetProcAddress("eglCreateSyncKHR"));
  if (egl_create_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    return absl::InternalError(
        "Not supported / bad EGL implementation: eglCreateSyncKHR.");
  }
  EGLSyncKHR egl_sync;
  RETURN_IF_ERROR(TFLITE_GPU_CALL_EGL(*egl_create_sync_khr, &egl_sync, display,
                                      EGL_SYNC_FENCE_KHR, nullptr));
  if (egl_sync == EGL_NO_SYNC_KHR) {
    return absl::InternalError("Returned empty KHR EGL sync");
  }
  *sync = EglSync(display, egl_sync);
  return absl::OkStatus();
}

EglSync& EglSync::operator=(EglSync&& sync) {
  if (this != &sync) {
    Invalidate();
    std::swap(sync_, sync.sync_);
    display_ = sync.display_;
  }
  return *this;
}

void EglSync::Invalidate() {
  if (sync_ != EGL_NO_SYNC_KHR) {
    static auto* egl_destroy_sync_khr =
        reinterpret_cast<decltype(&eglDestroySyncKHR)>(
            eglGetProcAddress("eglDestroySyncKHR"));
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    if (IsEglFenceSyncSupported(display_).ok() && egl_destroy_sync_khr) {
      // Note: we're doing nothing when the function pointer is nullptr, or the
      // call returns EGL_FALSE.
      (*egl_destroy_sync_khr)(display_, sync_);
    }
    sync_ = EGL_NO_SYNC_KHR;
  }
}

absl::Status EglSync::ServerWait() {
  RETURN_IF_ERROR(IsEglWaitSyncSupported(display_));
  static auto* egl_wait_sync_khr = reinterpret_cast<decltype(&eglWaitSyncKHR)>(
      eglGetProcAddress("eglWaitSyncKHR"));
  if (egl_wait_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_wait_sync
    return absl::InternalError("Not supported: eglWaitSyncKHR.");
  }
  EGLint result;
  RETURN_IF_ERROR(
      TFLITE_GPU_CALL_EGL(*egl_wait_sync_khr, &result, display_, sync_, 0));
  return result == EGL_TRUE ? absl::OkStatus()
                            : absl::InternalError("eglWaitSync failed");
}

absl::Status EglSync::ClientWait() {
  RETURN_IF_ERROR(IsEglFenceSyncSupported(display_));
  static auto* egl_client_wait_sync_khr =
      reinterpret_cast<decltype(&eglClientWaitSyncKHR)>(
          eglGetProcAddress("eglClientWaitSyncKHR"));
  if (egl_client_wait_sync_khr == nullptr) {
    // Needs extension: EGL_KHR_fence_sync (EGL) / GL_OES_EGL_sync (OpenGL ES).
    return absl::InternalError("Not supported: eglClientWaitSyncKHR.");
  }
  EGLint result;
  // TODO(akulik): make it active wait for better performance
  RETURN_IF_ERROR(
      TFLITE_GPU_CALL_EGL(*egl_client_wait_sync_khr, &result, display_, sync_,
                          EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR));
  return result == EGL_CONDITION_SATISFIED_KHR
             ? absl::OkStatus()
             : absl::InternalError("eglClientWaitSync failed");
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>#include <Halide.h>
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x, y, z, w;
    Image<int> full(800, 600, 10, 10);

    buffer_t cropped = *full.raw_buffer();
    cropped.host = (uint8_t *)&(full(40, 80, 2, 4));
    cropped.min[0] = 0;
    cropped.min[1] = 0;
    cropped.min[2] = 0;
    cropped.min[3] = 0;
    cropped.extent[0] = 128;
    cropped.extent[1] = 96;
    cropped.extent[2] = 3;
    cropped.extent[3] = 3;
    cropped.stride[0] *= 2;
    cropped.stride[1] *= 2;
    cropped.stride[2] *= 2;
    cropped.stride[3] *= 2;
    Buffer out(Int(32), &cropped);

    Func f;

    f(x, y, z, w) = 3*x + 2*y + z + 4*w;
    f.gpu_tile(x, y, 16, 16);
    f.output_buffer().set_stride(0, Expr());
    f.realize(out);

    // Put some data in the full host buffer.
    lambda(x, y, z, w, 4*x + 3*y + 2*z + w).realize(full);

    // Copy back the output subset from the GPU.
    out.copy_to_host();

    for (int w = 0; w < full.extent(3); ++w) {
        for (int z = 0; z < full.extent(2); ++z) {
            for (int y = 0; y < full.extent(1); ++y) {
                for (int x = 0; x < full.extent(0); ++x) {
                    int correct = 4*x + 3*y + 2*z + w;

                    int w_ = (w - 4)/2;
                    int z_ = (z - 2)/2;
                    int y_ = (y - 80)/2;
                    int x_ = (x - 40)/2;

                    if (cropped.min[3] <= w_ && w_ < cropped.min[3] + cropped.extent[3] &&
                        cropped.min[2] <= z_ && z_ < cropped.min[2] + cropped.extent[2] &&
                        cropped.min[1] <= y_ && y_ < cropped.min[1] + cropped.extent[1] &&
                        cropped.min[0] <= x_ && x_ < cropped.min[0] + cropped.extent[0] &&
                        x % 2 == 0 && y % 2 == 0 && z % 2 == 0 && w % 2 == 0) {
                        correct = 3*x_ + 2*y_ + z_ + 4*w_;
                    }
                    if (full(x, y, z, w) != correct) {
                        printf("Error! Incorrect value %i != %i at %i, %i, %i, %i\n", full(x, y, z, w), correct, x, y, z, w);
                        return -1;
                    }
                }
            }
        }
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Made test run on smaller subset to avoid very large numbers of copies.<commit_after>#include <Halide.h>
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    Var x, y, z, w;
    Image<int> full(80, 60, 10, 10);

    buffer_t cropped = *full.raw_buffer();
    cropped.host = (uint8_t *)&(full(4, 8, 2, 4));
    cropped.min[0] = 0;
    cropped.min[1] = 0;
    cropped.min[2] = 0;
    cropped.min[3] = 0;
    cropped.extent[0] = 16;
    cropped.extent[1] = 16;
    cropped.extent[2] = 3;
    cropped.extent[3] = 3;
    cropped.stride[0] *= 2;
    cropped.stride[1] *= 2;
    cropped.stride[2] *= 2;
    cropped.stride[3] *= 2;
    Buffer out(Int(32), &cropped);

    Func f;

    f(x, y, z, w) = 3*x + 2*y + z + 4*w;
    f.gpu_tile(x, y, 16, 16);
    f.output_buffer().set_stride(0, Expr());
    f.realize(out);

    // Put some data in the full host buffer.
    lambda(x, y, z, w, 4*x + 3*y + 2*z + w).realize(full);

    // Copy back the output subset from the GPU.
    out.copy_to_host();

    for (int w = 0; w < full.extent(3); ++w) {
        for (int z = 0; z < full.extent(2); ++z) {
            for (int y = 0; y < full.extent(1); ++y) {
                for (int x = 0; x < full.extent(0); ++x) {
                    int correct = 4*x + 3*y + 2*z + w;

                    int w_ = (w - 4)/2;
                    int z_ = (z - 2)/2;
                    int y_ = (y - 8)/2;
                    int x_ = (x - 4)/2;

                    if (cropped.min[3] <= w_ && w_ < cropped.min[3] + cropped.extent[3] &&
                        cropped.min[2] <= z_ && z_ < cropped.min[2] + cropped.extent[2] &&
                        cropped.min[1] <= y_ && y_ < cropped.min[1] + cropped.extent[1] &&
                        cropped.min[0] <= x_ && x_ < cropped.min[0] + cropped.extent[0] &&
                        x % 2 == 0 && y % 2 == 0 && z % 2 == 0 && w % 2 == 0) {
                        correct = 3*x_ + 2*y_ + z_ + 4*w_;
                    }
                    if (full(x, y, z, w) != correct) {
                        printf("Error! Incorrect value %i != %i at %i, %i, %i, %i\n", full(x, y, z, w), correct, x, y, z, w);
                        return -1;
                    }
                }
            }
        }
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>