<commit_before>#include "nixexpr.hh"
#include "parser.hh"
#include "hash.hh"
#include "util.hh"
#include "nixexpr-ast.hh"

#include <cstdlib>

using namespace nix;

struct Env;
struct Value;

typedef std::map<string, Value> Bindings;

struct Env
{
    Env * up;
    Bindings bindings;
};

typedef enum {
    tInt = 1,
    tAttrs,
    tThunk,
    tLambda,
    tCopy
} ValueType;

struct Value
{
    ValueType type;
    union
    {
        int integer;
        Bindings * attrs;
        struct {
            Env * env;
            Expr expr;
        } thunk;
        struct {
            Env * env;
            Pattern pat;
            Expr body;
        } lambda;
        Value * val;
    };
};

std::ostream & operator << (std::ostream & str, Value & v)
{
    switch (v.type) {
    case tInt:
        str << v.integer;
        break;
    case tAttrs:
        str << "{ ";
        foreach (Bindings::iterator, i, *v.attrs)
            str << i->first << " = " << i->second << "; ";
        str << "}";
        break;
    case tThunk:
        str << "<CODE>";
        break;
    case tLambda:
        str << "<LAMBDA>";
        break;
    default:
        abort();
    }
    return str;
}

static void eval(Env * env, Expr e, Value & v);

void forceValue(Value & v)
{
    if (v.type == tThunk) eval(v.thunk.env, v.thunk.expr, v);
    else if (v.type == tCopy) {
        forceValue(*v.val);
        v = *v.val;
    }
}

Value * lookupVar(Env * env, const string & name)
{
    for ( ; env; env = env->up) {
        Bindings::iterator i = env->bindings.find(name);
        if (i != env->bindings.end()) return &i->second;
    }
    throw Error("undefined variable");
}

unsigned long nrValues = 0;

unsigned long nrEnvs = 0;

Env * allocEnv()
{
    nrEnvs++;
    return new Env;
}

static void eval(Env * env, Expr e, Value & v)
{
    printMsg(lvlError, format("eval: %1%") % e);

    ATerm name;
    if (matchVar(e, name)) {
        Value * v2 = lookupVar(env, aterm2String(name));
        forceValue(*v2);
        v = *v2;
        return;
    }

    int n;
    if (matchInt(e, n)) {
        v.type = tInt;
        v.integer = n;
        return;
    }

    ATermList es;
    if (matchAttrs(e, es)) {
        v.type = tAttrs;
        v.attrs = new Bindings;
        ATerm e2, pos;
        for (ATermIterator i(es); i; ++i) {
            if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
            Value & v2 = (*v.attrs)[aterm2String(name)];
            nrValues++;
            v2.type = tThunk;
            v2.thunk.env = env;
            v2.thunk.expr = e2;
        }
        return;
    }

    ATermList rbnds, nrbnds;
    if (matchRec(e, rbnds, nrbnds)) {
        Env * env2 = allocEnv();
        env2->up = env;

        v.type = tAttrs;
        v.attrs = &env2->bindings;
        ATerm name, e2, pos;
        for (ATermIterator i(rbnds); i; ++i) {
            if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
            Value & v2 = env2->bindings[aterm2String(name)];
            nrValues++;
            v2.type = tThunk;
            v2.thunk.env = env2;
            v2.thunk.expr = e2;
        }

        return;
    }

    Expr e2;
    if (matchSelect(e, e2, name)) {
        eval(env, e2, v);
        if (v.type != tAttrs) throw TypeError("expected attribute set");
        Bindings::iterator i = v.attrs->find(aterm2String(name));
        if (i == v.attrs->end()) throw TypeError("attribute not found");
        forceValue(i->second);
        v = i->second;
        return;
    }

    Pattern pat; Expr body; Pos pos;
    if (matchFunction(e, pat, body, pos)) {
        v.type = tLambda;
        v.lambda.env = env;
        v.lambda.pat = pat;
        v.lambda.body = body;
        return;
    }

    Expr fun, arg;
    if (matchCall(e, fun, arg)) {
        eval(env, fun, v);
        if (v.type != tLambda) throw TypeError("expected function");

        Env * env2 = allocEnv();
        env2->up = env;

        ATermList formals; ATerm ellipsis;

        if (matchVarPat(v.lambda.pat, name)) {
            Value & vArg = env2->bindings[aterm2String(name)];
            vArg.type = tThunk;
            vArg.thunk.env = env;
            vArg.thunk.expr = arg;
        }

        else if (matchAttrsPat(v.lambda.pat, formals, ellipsis, name)) {
            Value * vArg;
            Value vArg_;

            if (name == sNoAlias)
                vArg = &vArg_;
            else
                vArg = &env2->bindings[aterm2String(name)];

            eval(env, arg, *vArg);
            if (vArg->type != tAttrs) throw TypeError("expected attribute set");

            for (ATermIterator i(formals); i; ++i) {
                Expr name, def;
                DefaultValue def2;
                if (!matchFormal(*i, name, def2)) abort(); /* can't happen */

                Bindings::iterator j = vArg->attrs->find(aterm2String(name));
                if (j == vArg->attrs->end())
                    throw TypeError(format("the argument named `%1%' required by the function is missing")
                    % aterm2String(name));

                Value & v = env2->bindings[aterm2String(name)];
                v.type = tCopy;
                v.val = &j->second;
            }
        }

        else abort();

        eval(env2, v.lambda.body, v);
        return;
    }

    abort();
}

void doTest(string s)
{
    EvalState state;
    Expr e = parseExprFromString(state, s, "/");
    printMsg(lvlError, format(">>>>> %1%") % e);
    Value v;
    eval(0, e, v);
    printMsg(lvlError, format("result: %1%") % v);
}

void run(Strings args)
{
    printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value));

    doTest("123");
    doTest("{ x = 1; y = 2; }");
    doTest("{ x = 1; y = 2; }.y");
    doTest("rec { x = 1; y = x; }.y");
    doTest("(x: x) 1");
    doTest("(x: y: y) 1 2");
    doTest("x: x");
    doTest("({x, y}: x) { x = 1; y = 2; }");
    doTest("({x, y}@args: args.x) { x = 1; y = 2; }");
    doTest("(args@{x, y}: args.x) { x = 1; y = 2; }");

    //Expr e = parseExprFromString(state, "let x = \"a\"; in x + \"b\"", "/");
    //Expr e = parseExprFromString(state, "(x: x + \"b\") \"a\"", "/");
    //Expr e = parseExprFromString(state, "\"a\" + \"b\"", "/");
    //Expr e = parseExprFromString(state, "\"a\" + \"b\"", "/");

    printMsg(lvlError, format("alloced %1% values") % nrValues);
    printMsg(lvlError, format("alloced %1% environments") % nrEnvs);
}

void printHelp()
{
}

string programId = "eval-test";
<commit_msg>* Implement `...' and default function arguments.<commit_after>#include "nixexpr.hh"
#include "parser.hh"
#include "hash.hh"
#include "util.hh"
#include "nixexpr-ast.hh"

#include <cstdlib>

using namespace nix;

struct Env;
struct Value;

typedef std::map<string, Value> Bindings;

struct Env
{
    Env * up;
    Bindings bindings;
};

typedef enum {
    tInt = 1,
    tAttrs,
    tThunk,
    tLambda,
    tCopy
} ValueType;

struct Value
{
    ValueType type;
    union
    {
        int integer;
        Bindings * attrs;
        struct {
            Env * env;
            Expr expr;
        } thunk;
        struct {
            Env * env;
            Pattern pat;
            Expr body;
        } lambda;
        Value * val;
    };
};

std::ostream & operator << (std::ostream & str, Value & v)
{
    switch (v.type) {
    case tInt:
        str << v.integer;
        break;
    case tAttrs:
        str << "{ ";
        foreach (Bindings::iterator, i, *v.attrs)
            str << i->first << " = " << i->second << "; ";
        str << "}";
        break;
    case tThunk:
        str << "<CODE>";
        break;
    case tLambda:
        str << "<LAMBDA>";
        break;
    default:
        abort();
    }
    return str;
}

static void eval(Env * env, Expr e, Value & v);

void forceValue(Value & v)
{
    if (v.type == tThunk) eval(v.thunk.env, v.thunk.expr, v);
    else if (v.type == tCopy) {
        forceValue(*v.val);
        v = *v.val;
    }
}

Value * lookupVar(Env * env, const string & name)
{
    for ( ; env; env = env->up) {
        Bindings::iterator i = env->bindings.find(name);
        if (i != env->bindings.end()) return &i->second;
    }
    throw Error("undefined variable");
}

unsigned long nrValues = 0;

unsigned long nrEnvs = 0;

Env * allocEnv()
{
    nrEnvs++;
    return new Env;
}

static void eval(Env * env, Expr e, Value & v)
{
    printMsg(lvlError, format("eval: %1%") % e);

    ATerm name;
    if (matchVar(e, name)) {
        Value * v2 = lookupVar(env, aterm2String(name));
        forceValue(*v2);
        v = *v2;
        return;
    }

    int n;
    if (matchInt(e, n)) {
        v.type = tInt;
        v.integer = n;
        return;
    }

    ATermList es;
    if (matchAttrs(e, es)) {
        v.type = tAttrs;
        v.attrs = new Bindings;
        ATerm e2, pos;
        for (ATermIterator i(es); i; ++i) {
            if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
            Value & v2 = (*v.attrs)[aterm2String(name)];
            nrValues++;
            v2.type = tThunk;
            v2.thunk.env = env;
            v2.thunk.expr = e2;
        }
        return;
    }

    ATermList rbnds, nrbnds;
    if (matchRec(e, rbnds, nrbnds)) {
        Env * env2 = allocEnv();
        env2->up = env;

        v.type = tAttrs;
        v.attrs = &env2->bindings;
        ATerm name, e2, pos;
        for (ATermIterator i(rbnds); i; ++i) {
            if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */
            Value & v2 = env2->bindings[aterm2String(name)];
            nrValues++;
            v2.type = tThunk;
            v2.thunk.env = env2;
            v2.thunk.expr = e2;
        }

        return;
    }

    Expr e2;
    if (matchSelect(e, e2, name)) {
        eval(env, e2, v);
        if (v.type != tAttrs) throw TypeError("expected attribute set");
        Bindings::iterator i = v.attrs->find(aterm2String(name));
        if (i == v.attrs->end()) throw TypeError("attribute not found");
        forceValue(i->second);
        v = i->second;
        return;
    }

    Pattern pat; Expr body; Pos pos;
    if (matchFunction(e, pat, body, pos)) {
        v.type = tLambda;
        v.lambda.env = env;
        v.lambda.pat = pat;
        v.lambda.body = body;
        return;
    }

    Expr fun, arg;
    if (matchCall(e, fun, arg)) {
        eval(env, fun, v);
        if (v.type != tLambda) throw TypeError("expected function");

        Env * env2 = allocEnv();
        env2->up = env;

        ATermList formals; ATerm ellipsis;

        if (matchVarPat(v.lambda.pat, name)) {
            Value & vArg = env2->bindings[aterm2String(name)];
            vArg.type = tThunk;
            vArg.thunk.env = env;
            vArg.thunk.expr = arg;
        }

        else if (matchAttrsPat(v.lambda.pat, formals, ellipsis, name)) {
            Value * vArg;
            Value vArg_;

            if (name == sNoAlias)
                vArg = &vArg_;
            else
                vArg = &env2->bindings[aterm2String(name)];

            eval(env, arg, *vArg);
            if (vArg->type != tAttrs) throw TypeError("expected attribute set");

            /* For each formal argument, get the actual argument.  If
               there is no matching actual argument but the formal
               argument has a default, use the default. */
            unsigned int attrsUsed = 0;
            for (ATermIterator i(formals); i; ++i) {
                Expr name, def;
                DefaultValue def2;
                if (!matchFormal(*i, name, def2)) abort(); /* can't happen */

                Bindings::iterator j = vArg->attrs->find(aterm2String(name));

                Value & v = env2->bindings[aterm2String(name)];

                if (j == vArg->attrs->end()) {
                    if (!matchDefaultValue(def2, def)) def = 0;
                    if (def == 0) throw TypeError(format("the argument named `%1%' required by the function is missing")
                        % aterm2String(name));
                    v.type = tThunk;
                    v.thunk.env = env2;
                    v.thunk.expr = def;
                } else {
                    attrsUsed++;
                    v.type = tCopy;
                    v.val = &j->second;
                }

            }

            /* Check that each actual argument is listed as a formal
               argument (unless the attribute match specifies a
               `...').  TODO: show the names of the
               expected/unexpected arguments. */
            if (ellipsis == eFalse && attrsUsed != vArg->attrs->size())
                throw TypeError("function called with unexpected argument");
        }

        else abort();

        eval(env2, v.lambda.body, v);
        return;
    }

    abort();
}

void doTest(string s)
{
    EvalState state;
    Expr e = parseExprFromString(state, s, "/");
    printMsg(lvlError, format(">>>>> %1%") % e);
    Value v;
    eval(0, e, v);
    printMsg(lvlError, format("result: %1%") % v);
}

void run(Strings args)
{
    printMsg(lvlError, format("size of value: %1% bytes") % sizeof(Value));

    doTest("123");
    doTest("{ x = 1; y = 2; }");
    doTest("{ x = 1; y = 2; }.y");
    doTest("rec { x = 1; y = x; }.y");
    doTest("(x: x) 1");
    doTest("(x: y: y) 1 2");
    doTest("x: x");
    doTest("({x, y}: x) { x = 1; y = 2; }");
    doTest("({x, y}@args: args.x) { x = 1; y = 2; }");
    doTest("(args@{x, y}: args.x) { x = 1; y = 2; }");
    doTest("({x ? 1}: x) { }");
    doTest("({x ? 1, y ? x}: y) { x = 2; }");
    doTest("({x, y, ...}: x) { x = 1; y = 2; z = 3; }");
    doTest("({x, y, ...}@args: args.z) { x = 1; y = 2; z = 3; }");

    //Expr e = parseExprFromString(state, "let x = \"a\"; in x + \"b\"", "/");
    //Expr e = parseExprFromString(state, "(x: x + \"b\") \"a\"", "/");
    //Expr e = parseExprFromString(state, "\"a\" + \"b\"", "/");
    //Expr e = parseExprFromString(state, "\"a\" + \"b\"", "/");

    printMsg(lvlError, format("alloced %1% values") % nrValues);
    printMsg(lvlError, format("alloced %1% environments") % nrEnvs);
}

void printHelp()
{
}

string programId = "eval-test";
<|endoftext|>


<commit_before>#include "download.hh"
#include "util.hh"
#include "globals.hh"
#include "hash.hh"
#include "store-api.hh"

#include <curl/curl.h>

#include <iostream>

namespace nix {

double getTime()
{
    struct timeval tv;
    gettimeofday(&tv, 0);
    return tv.tv_sec + (tv.tv_usec / 1000000.0);
}

struct CurlDownloader : public Downloader
{
    CURL * curl;
    string data;
    string etag, status, expectedETag;

    struct curl_slist * requestHeaders;

    bool showProgress;
    double prevProgressTime{0}, startTime{0};
    unsigned int moveBack{1};

    size_t writeCallback(void * contents, size_t size, size_t nmemb)
    {
        size_t realSize = size * nmemb;
        data.append((char *) contents, realSize);
        return realSize;
    }

    static size_t writeCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
    {
        return ((CurlDownloader *) userp)->writeCallback(contents, size, nmemb);
    }

    size_t headerCallback(void * contents, size_t size, size_t nmemb)
    {
        size_t realSize = size * nmemb;
        string line = string((char *) contents, realSize);
        printMsg(lvlVomit, format("got header: %1%") % trim(line));
        if (line.compare(0, 5, "HTTP/") == 0) { // new response starts
            etag = "";
            auto ss = tokenizeString<vector<string>>(line, " ");
            status = ss.size() >= 2 ? ss[1] : "";
        } else {
            auto i = line.find(':');
            if (i != string::npos) {
                string name = trim(string(line, 0, i));
                if (name == "ETag") { // FIXME: case
                    etag = trim(string(line, i + 1));
                    /* Hack to work around a GitHub bug: it sends
                       ETags, but ignores If-None-Match. So if we get
                       the expected ETag on a 200 response, then shut
                       down the connection because we already have the
                       data. */
                    printMsg(lvlDebug, format("got ETag: %1%") % etag);
                    if (etag == expectedETag && status == "200") {
                        printMsg(lvlDebug, format("shutting down on 200 HTTP response with expected ETag"));
                        return 0;
                    }
                }
            }
        }
        return realSize;
    }

    static size_t headerCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
    {
        return ((CurlDownloader *) userp)->headerCallback(contents, size, nmemb);
    }

    int progressCallback(double dltotal, double dlnow)
    {
        if (showProgress) {
            double now = getTime();
            if (prevProgressTime <= now - 1) {
                string s = (format(" [%1$.0f/%2$.0f KiB, %3$.1f KiB/s]")
                    % (dlnow / 1024.0)
                    % (dltotal / 1024.0)
                    % (now == startTime ? 0 : dlnow / 1024.0 / (now - startTime))).str();
                std::cerr << "\e[" << moveBack << "D" << s;
                moveBack = s.size();
                std::cerr.flush();
                prevProgressTime = now;
            }
        }
        return _isInterrupted;
    }

    static int progressCallbackWrapper(void * userp, double dltotal, double dlnow, double ultotal, double ulnow)
    {
        return ((CurlDownloader *) userp)->progressCallback(dltotal, dlnow);
    }

    CurlDownloader()
    {
        requestHeaders = 0;

        curl = curl_easy_init();
        if (!curl) throw nix::Error("unable to initialize curl");
    }

    ~CurlDownloader()
    {
        if (curl) curl_easy_cleanup(curl);
        if (requestHeaders) curl_slist_free_all(requestHeaders);
    }

    bool fetch(const string & url, const DownloadOptions & options)
    {
        showProgress =
            options.showProgress == DownloadOptions::yes ||
            (options.showProgress == DownloadOptions::automatic && isatty(STDERR_FILENO));

        curl_easy_reset(curl);

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, ("Nix/" + nixVersion).c_str());
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) this);

        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *) this);

        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *) this);
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        if (options.verifyTLS)
            curl_easy_setopt(curl, CURLOPT_CAINFO, getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt").c_str());
        else {
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
        }

        data.clear();

        if (requestHeaders) {
            curl_slist_free_all(requestHeaders);
            requestHeaders = 0;
        }

        if (!options.expectedETag.empty()) {
            this->expectedETag = options.expectedETag;
            requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + options.expectedETag).c_str());
        }

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, requestHeaders);

        if (options.head)
            curl_easy_setopt(curl, CURLOPT_NOBODY, 1);

        if (showProgress) {
            std::cerr << (format("downloading ‘%1%’... ") % url);
            std::cerr.flush();
            startTime = getTime();
        }

        CURLcode res = curl_easy_perform(curl);
        if (showProgress)
            //std::cerr << "\e[" << moveBack << "D\e[K\n";
            std::cerr << "\n";
        checkInterrupt();
        if (res == CURLE_WRITE_ERROR && etag == options.expectedETag) return false;

        long httpStatus = -1;
        if (res == CURLE_HTTP_RETURNED_ERROR)
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStatus);

        if (res != CURLE_OK) {
            long httpStatus = 0;
            Error err =
                httpStatus == 404 ? NotFound :
                httpStatus == 403 ? Forbidden : Misc;
            throw DownloadError(err, format("unable to download ‘%1%’: %2% (%3%)")
                % url % curl_easy_strerror(res) % res);
        }

        if (httpStatus == 304) return false;

        return true;
    }

    DownloadResult download(string url, const DownloadOptions & options) override
    {
        DownloadResult res;
        if (fetch(url, options)) {
            res.cached = false;
            res.data = data;
        } else
            res.cached = true;
        res.etag = etag;
        return res;
    }
};

ref<Downloader> makeDownloader()
{
    return make_ref<CurlDownloader>();
}

Path Downloader::downloadCached(ref<Store> store, const string & url, bool unpack)
{
    Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
    createDirs(cacheDir);

    string urlHash = printHash32(hashString(htSHA256, url));

    Path dataFile = cacheDir + "/" + urlHash + ".info";
    Path fileLink = cacheDir + "/" + urlHash + "-file";

    Path storePath;

    string expectedETag;

    int ttl = settings.get("tarball-ttl", 60 * 60);
    bool skip = false;

    if (pathExists(fileLink) && pathExists(dataFile)) {
        storePath = readLink(fileLink);
        store->addTempRoot(storePath);
        if (store->isValidPath(storePath)) {
            auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
            if (ss.size() >= 3 && ss[0] == url) {
                time_t lastChecked;
                if (string2Int(ss[2], lastChecked) && lastChecked + ttl >= time(0))
                    skip = true;
                else if (!ss[1].empty()) {
                    printMsg(lvlDebug, format("verifying previous ETag ‘%1%’") % ss[1]);
                    expectedETag = ss[1];
                }
            }
        } else
            storePath = "";
    }

    string name;
    auto p = url.rfind('/');
    if (p != string::npos) name = string(url, p + 1);

    if (!skip) {

        try {
            DownloadOptions options;
            options.expectedETag = expectedETag;
            auto res = download(url, options);

            if (!res.cached)
                storePath = store->addTextToStore(name, res.data, PathSet(), false);

            assert(!storePath.empty());
            replaceSymlink(storePath, fileLink);

            writeFile(dataFile, url + "\n" + res.etag + "\n" + std::to_string(time(0)) + "\n");
        } catch (DownloadError & e) {
            if (storePath.empty()) throw;
            printMsg(lvlError, format("warning: %1%; using cached result") % e.msg());
        }
    }

    if (unpack) {
        Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
        Path unpackedStorePath;
        if (pathExists(unpackedLink)) {
            unpackedStorePath = readLink(unpackedLink);
            store->addTempRoot(unpackedStorePath);
            if (!store->isValidPath(unpackedStorePath))
                unpackedStorePath = "";
        }
        if (unpackedStorePath.empty()) {
            printMsg(lvlInfo, format("unpacking ‘%1%’...") % url);
            Path tmpDir = createTempDir();
            AutoDelete autoDelete(tmpDir, true);
            // FIXME: this requires GNU tar for decompression.
            runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"}, "");
            unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false);
        }
        replaceSymlink(unpackedStorePath, unpackedLink);
        return unpackedStorePath;
    }

    return storePath;
}

bool isUri(const string & s)
{
    size_t pos = s.find("://");
    if (pos == string::npos) return false;
    string scheme(s, 0, pos);
    return scheme == "http" || scheme == "https" || scheme == "file";
}

}
<commit_msg>CurlDownloader: Fix HTTP error processing<commit_after>#include "download.hh"
#include "util.hh"
#include "globals.hh"
#include "hash.hh"
#include "store-api.hh"

#include <curl/curl.h>

#include <iostream>

namespace nix {

double getTime()
{
    struct timeval tv;
    gettimeofday(&tv, 0);
    return tv.tv_sec + (tv.tv_usec / 1000000.0);
}

struct CurlDownloader : public Downloader
{
    CURL * curl;
    string data;
    string etag, status, expectedETag;

    struct curl_slist * requestHeaders;

    bool showProgress;
    double prevProgressTime{0}, startTime{0};
    unsigned int moveBack{1};

    size_t writeCallback(void * contents, size_t size, size_t nmemb)
    {
        size_t realSize = size * nmemb;
        data.append((char *) contents, realSize);
        return realSize;
    }

    static size_t writeCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
    {
        return ((CurlDownloader *) userp)->writeCallback(contents, size, nmemb);
    }

    size_t headerCallback(void * contents, size_t size, size_t nmemb)
    {
        size_t realSize = size * nmemb;
        string line = string((char *) contents, realSize);
        printMsg(lvlVomit, format("got header: %1%") % trim(line));
        if (line.compare(0, 5, "HTTP/") == 0) { // new response starts
            etag = "";
            auto ss = tokenizeString<vector<string>>(line, " ");
            status = ss.size() >= 2 ? ss[1] : "";
        } else {
            auto i = line.find(':');
            if (i != string::npos) {
                string name = trim(string(line, 0, i));
                if (name == "ETag") { // FIXME: case
                    etag = trim(string(line, i + 1));
                    /* Hack to work around a GitHub bug: it sends
                       ETags, but ignores If-None-Match. So if we get
                       the expected ETag on a 200 response, then shut
                       down the connection because we already have the
                       data. */
                    printMsg(lvlDebug, format("got ETag: %1%") % etag);
                    if (etag == expectedETag && status == "200") {
                        printMsg(lvlDebug, format("shutting down on 200 HTTP response with expected ETag"));
                        return 0;
                    }
                }
            }
        }
        return realSize;
    }

    static size_t headerCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
    {
        return ((CurlDownloader *) userp)->headerCallback(contents, size, nmemb);
    }

    int progressCallback(double dltotal, double dlnow)
    {
        if (showProgress) {
            double now = getTime();
            if (prevProgressTime <= now - 1) {
                string s = (format(" [%1$.0f/%2$.0f KiB, %3$.1f KiB/s]")
                    % (dlnow / 1024.0)
                    % (dltotal / 1024.0)
                    % (now == startTime ? 0 : dlnow / 1024.0 / (now - startTime))).str();
                std::cerr << "\e[" << moveBack << "D" << s;
                moveBack = s.size();
                std::cerr.flush();
                prevProgressTime = now;
            }
        }
        return _isInterrupted;
    }

    static int progressCallbackWrapper(void * userp, double dltotal, double dlnow, double ultotal, double ulnow)
    {
        return ((CurlDownloader *) userp)->progressCallback(dltotal, dlnow);
    }

    CurlDownloader()
    {
        requestHeaders = 0;

        curl = curl_easy_init();
        if (!curl) throw nix::Error("unable to initialize curl");
    }

    ~CurlDownloader()
    {
        if (curl) curl_easy_cleanup(curl);
        if (requestHeaders) curl_slist_free_all(requestHeaders);
    }

    bool fetch(const string & url, const DownloadOptions & options)
    {
        showProgress =
            options.showProgress == DownloadOptions::yes ||
            (options.showProgress == DownloadOptions::automatic && isatty(STDERR_FILENO));

        curl_easy_reset(curl);

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, ("Nix/" + nixVersion).c_str());
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);

        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) this);

        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *) this);

        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallbackWrapper);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *) this);
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);

        curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());

        if (options.verifyTLS)
            curl_easy_setopt(curl, CURLOPT_CAINFO, getEnv("SSL_CERT_FILE", "/etc/ssl/certs/ca-certificates.crt").c_str());
        else {
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
        }

        data.clear();

        if (requestHeaders) {
            curl_slist_free_all(requestHeaders);
            requestHeaders = 0;
        }

        if (!options.expectedETag.empty()) {
            this->expectedETag = options.expectedETag;
            requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + options.expectedETag).c_str());
        }

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, requestHeaders);

        if (options.head)
            curl_easy_setopt(curl, CURLOPT_NOBODY, 1);

        if (showProgress) {
            std::cerr << (format("downloading ‘%1%’... ") % url);
            std::cerr.flush();
            startTime = getTime();
        }

        CURLcode res = curl_easy_perform(curl);
        if (showProgress)
            //std::cerr << "\e[" << moveBack << "D\e[K\n";
            std::cerr << "\n";
        checkInterrupt();
        if (res == CURLE_WRITE_ERROR && etag == options.expectedETag) return false;

        long httpStatus = -1;
        if (res == CURLE_HTTP_RETURNED_ERROR)
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStatus);

        if (res != CURLE_OK) {
            Error err =
                httpStatus == 404 ? NotFound :
                httpStatus == 403 ? Forbidden : Misc;
            throw DownloadError(err, format("unable to download ‘%1%’: %2% (%3%)")
                % url % curl_easy_strerror(res) % res);
        }

        if (httpStatus == 304) return false;

        return true;
    }

    DownloadResult download(string url, const DownloadOptions & options) override
    {
        DownloadResult res;
        if (fetch(url, options)) {
            res.cached = false;
            res.data = data;
        } else
            res.cached = true;
        res.etag = etag;
        return res;
    }
};

ref<Downloader> makeDownloader()
{
    return make_ref<CurlDownloader>();
}

Path Downloader::downloadCached(ref<Store> store, const string & url, bool unpack)
{
    Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
    createDirs(cacheDir);

    string urlHash = printHash32(hashString(htSHA256, url));

    Path dataFile = cacheDir + "/" + urlHash + ".info";
    Path fileLink = cacheDir + "/" + urlHash + "-file";

    Path storePath;

    string expectedETag;

    int ttl = settings.get("tarball-ttl", 60 * 60);
    bool skip = false;

    if (pathExists(fileLink) && pathExists(dataFile)) {
        storePath = readLink(fileLink);
        store->addTempRoot(storePath);
        if (store->isValidPath(storePath)) {
            auto ss = tokenizeString<vector<string>>(readFile(dataFile), "\n");
            if (ss.size() >= 3 && ss[0] == url) {
                time_t lastChecked;
                if (string2Int(ss[2], lastChecked) && lastChecked + ttl >= time(0))
                    skip = true;
                else if (!ss[1].empty()) {
                    printMsg(lvlDebug, format("verifying previous ETag ‘%1%’") % ss[1]);
                    expectedETag = ss[1];
                }
            }
        } else
            storePath = "";
    }

    string name;
    auto p = url.rfind('/');
    if (p != string::npos) name = string(url, p + 1);

    if (!skip) {

        try {
            DownloadOptions options;
            options.expectedETag = expectedETag;
            auto res = download(url, options);

            if (!res.cached)
                storePath = store->addTextToStore(name, res.data, PathSet(), false);

            assert(!storePath.empty());
            replaceSymlink(storePath, fileLink);

            writeFile(dataFile, url + "\n" + res.etag + "\n" + std::to_string(time(0)) + "\n");
        } catch (DownloadError & e) {
            if (storePath.empty()) throw;
            printMsg(lvlError, format("warning: %1%; using cached result") % e.msg());
        }
    }

    if (unpack) {
        Path unpackedLink = cacheDir + "/" + baseNameOf(storePath) + "-unpacked";
        Path unpackedStorePath;
        if (pathExists(unpackedLink)) {
            unpackedStorePath = readLink(unpackedLink);
            store->addTempRoot(unpackedStorePath);
            if (!store->isValidPath(unpackedStorePath))
                unpackedStorePath = "";
        }
        if (unpackedStorePath.empty()) {
            printMsg(lvlInfo, format("unpacking ‘%1%’...") % url);
            Path tmpDir = createTempDir();
            AutoDelete autoDelete(tmpDir, true);
            // FIXME: this requires GNU tar for decompression.
            runProgram("tar", true, {"xf", storePath, "-C", tmpDir, "--strip-components", "1"}, "");
            unpackedStorePath = store->addToStore(name, tmpDir, true, htSHA256, defaultPathFilter, false);
        }
        replaceSymlink(unpackedStorePath, unpackedLink);
        return unpackedStorePath;
    }

    return storePath;
}

bool isUri(const string & s)
{
    size_t pos = s.find("://");
    if (pos == string::npos) return false;
    string scheme(s, 0, pos);
    return scheme == "http" || scheme == "https" || scheme == "file";
}

}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <string>
#include "xcint.hpp"

#ifndef FORTRAN_INT
typedef int fortran_int_t;
#else
typedef FORTRAN_INT fortran_int_t;
#endif

functional_data xcint_funs[XC_NR_FUNCTIONALS];
parameter_data xcint_params[XC_NR_PARAMETERS_AND_FUNCTIONALS];

int xcint_lookup_functional(const char *name)
{
  for (int i=0;i<XC_NR_FUNCTIONALS;i++)
    if (strcasecmp(name,xcint_funs[i].name) == 0)
      return i;
  return -1;
}

int xcint_lookup_parameter(const char *name)
{
  for (int i=XC_NR_FUNCTIONALS;i<XC_NR_PARAMETERS_AND_FUNCTIONALS;i++)
    if (strcasecmp(name,xcint_params[i].name) == 0)
      return i;
  return -1;
}

int xcint_lookup_alias(const char *name)
{
  for (int i=0;i<XC_MAX_ALIASES and xcint_aliases[i].name;i++)
    if (strcasecmp(name,xcint_aliases[i].name) == 0)
      return i;
  return -1;
}

template<int FUN>
void xcint_functional_setup_helper()
{
  if (!(fundat_db<FUN>::symbol[0] == 'X' and fundat_db<FUN>::symbol[1] == 'C' and fundat_db<FUN>::symbol[2] == '_'))
    xcint_die("Functional symbol does not start with XC_",FUN);
  fundat_db<FUN>::d.name = fundat_db<FUN>::symbol + 3;
  fundat_db<FUN>::d.id = (enum xc_functional_id)FUN;
  xcint_funs[FUN] = fundat_db<FUN>::d;
  xcint_functional_setup_helper<FUN+1>();
}

template<> void xcint_functional_setup_helper<XC_NR_FUNCTIONALS>() {  }

template<int P>
void xcint_parameter_setup_helper()
{
  if (!(pardat_db<P>::symbol[0] == 'X' and pardat_db<P>::symbol[1] == 'C' and pardat_db<P>::symbol[2] == '_'))
    xcint_die("Symbol does not start with XC_",P);
  pardat_db<P>::d.name = pardat_db<P>::symbol + 3;
  xcint_params[P] = pardat_db<P>::d;
  xcint_parameter_setup_helper<P+1>();
}

template<>
void xcint_parameter_setup_helper<XC_NR_PARAMETERS_AND_FUNCTIONALS>() {}

vars_data xcint_vars[XC_NR_VARS] =
  {
    {"XC_A", 1, XC_DENSITY},
    {"XC_N", 1, XC_DENSITY},
    {"XC_A_B", 2, XC_DENSITY},
    {"XC_N_S", 2, XC_DENSITY},
    {"XC_A_GAA", 2, XC_DENSITY | XC_GRADIENT},
    {"XC_N_GNN", 2, XC_DENSITY | XC_GRADIENT},
    {"XC_A_B_GAA_GAB_GBB", 5, XC_DENSITY | XC_GRADIENT},
    {"XC_N_S_GNN_GNS_GSS", 5, XC_DENSITY | XC_GRADIENT},
    {"XC_A_GAA_LAPA", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_GAA_TAUA", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_GNN_LAPN", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_GNN_TAUN", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_GAA_GAB_GBB_LAPA_LAPB",7, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_GAA_GAB_GBB_TAUA_TAUB",7, XC_DENSITY | XC_GRADIENT | XC_KINETIC},
    {"XC_N_S_GNN_GNS_GSS_LAPN_LAPS",7, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_S_GNN_GNS_GSS_TAUN_TAUS",7, XC_DENSITY | XC_GRADIENT | XC_KINETIC},
    {"XC_A_AX_AY_AZ",4, XC_DENSITY | XC_GRADIENT},
    {"XC_A_B_AX_AY_AZ_BZ_BY_BZ", 8, XC_DENSITY | XC_GRADIENT},
    {"XC_N_NX_NY_NZ",4, XC_DENSITY | XC_GRADIENT},
    {"XC_N_S_NX_NY_NZ_SZ_SY_SZ",8, XC_DENSITY | XC_GRADIENT},
    {"XC_A_2ND_TAYLOR", 10, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_2ND_TAYLOR", 20, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_2ND_TAYLOR", 10, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_S_2ND_TAYLOR", 20, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
  };

void xcint_assure_setup()
{
  static bool is_setup = false;
  if (!is_setup)
    {
      xcint_functional_setup_helper<0>();
      xcint_parameter_setup_helper<XC_NR_FUNCTIONALS>();
      is_setup = true;
    }
}

void xcint_die(const char *message, int code)
{
  fprintf(stderr,"XCFun fatal error %i: ",code);
  fprintf(stderr,"%s",message);
  fprintf(stderr,"\n");
  exit(-1);
}

int xcint_write_fortran_module()
{
  xcint_assure_setup();
  FILE *dst = fopen("fortran/xcfun_autogen.F90","w");
  int i;
  if (!dst)
    {
      perror("Open fortran/xcfun_autogen.F90 for writing failed");
      return -1;
    }
  fprintf(dst,"! Autogenerated file, do not edit\n"
	  "module xcfun_autogen\n");
  fprintf(dst,"  integer, parameter :: XCFUN_CHECKSUM = %i\n",
	  XCFUN_CHECKSUM);
  fprintf(dst,"  integer, parameter :: XCFUN_FORTRAN_INT_SIZE = %lu\n",
	  sizeof(fortran_int_t));
  fprintf(dst,"  integer, parameter :: XC_MAX_ORDER = %i\n",
	  XC_MAX_ORDER);
  fprintf(dst,"  integer, parameter :: XC_NR_FUNCTIONALS = %i\n",
	  XC_NR_FUNCTIONALS);
  fprintf(dst,"  integer, parameter :: XC_NR_PARAMETERS_AND_FUNCTIONALS = %i\n",
	  XC_NR_PARAMETERS_AND_FUNCTIONALS);
  fprintf(dst,"  integer, parameter :: XC_NR_VARS = %i\n",
	  XC_NR_VARS);
  fprintf(dst,"\n");
  fprintf(dst,"!Functionals\n");
  for (i=0;i<XC_NR_FUNCTIONALS;i++)
    fprintf(dst,"  integer, parameter :: XC_%s = %i\n",
	    xcint_funs[i].name,i);
  fprintf(dst,"\n");
  fprintf(dst,"!Parameters\n");
  for (i=XC_NR_FUNCTIONALS;i<XC_NR_PARAMETERS_AND_FUNCTIONALS;i++)
    fprintf(dst,"  integer, parameter :: XC_%s = %i\n",
	    xcint_params[i].name,i);
  fprintf(dst,"\n");
  for (i=0;i<XC_NR_VARS;i++)
    fprintf(dst,"  integer, parameter :: %s = %i\n",
	    xcint_vars[i].symbol,i);
  fprintf(dst,"end module\n");
  fclose(dst);
  return 0;
}

<commit_msg>string -> string.h<commit_after>#include <cstdio>
#include <cstdlib>
#include <string.h>
#include "xcint.hpp"

#ifndef FORTRAN_INT
typedef int fortran_int_t;
#else
typedef FORTRAN_INT fortran_int_t;
#endif

functional_data xcint_funs[XC_NR_FUNCTIONALS];
parameter_data xcint_params[XC_NR_PARAMETERS_AND_FUNCTIONALS];

int xcint_lookup_functional(const char *name)
{
  for (int i=0;i<XC_NR_FUNCTIONALS;i++)
    if (strcasecmp(name,xcint_funs[i].name) == 0)
      return i;
  return -1;
}

int xcint_lookup_parameter(const char *name)
{
  for (int i=XC_NR_FUNCTIONALS;i<XC_NR_PARAMETERS_AND_FUNCTIONALS;i++)
    if (strcasecmp(name,xcint_params[i].name) == 0)
      return i;
  return -1;
}

int xcint_lookup_alias(const char *name)
{
  for (int i=0;i<XC_MAX_ALIASES and xcint_aliases[i].name;i++)
    if (strcasecmp(name,xcint_aliases[i].name) == 0)
      return i;
  return -1;
}

template<int FUN>
void xcint_functional_setup_helper()
{
  if (!(fundat_db<FUN>::symbol[0] == 'X' and fundat_db<FUN>::symbol[1] == 'C' and fundat_db<FUN>::symbol[2] == '_'))
    xcint_die("Functional symbol does not start with XC_",FUN);
  fundat_db<FUN>::d.name = fundat_db<FUN>::symbol + 3;
  fundat_db<FUN>::d.id = (enum xc_functional_id)FUN;
  xcint_funs[FUN] = fundat_db<FUN>::d;
  xcint_functional_setup_helper<FUN+1>();
}

template<> void xcint_functional_setup_helper<XC_NR_FUNCTIONALS>() {  }

template<int P>
void xcint_parameter_setup_helper()
{
  if (!(pardat_db<P>::symbol[0] == 'X' and pardat_db<P>::symbol[1] == 'C' and pardat_db<P>::symbol[2] == '_'))
    xcint_die("Symbol does not start with XC_",P);
  pardat_db<P>::d.name = pardat_db<P>::symbol + 3;
  xcint_params[P] = pardat_db<P>::d;
  xcint_parameter_setup_helper<P+1>();
}

template<>
void xcint_parameter_setup_helper<XC_NR_PARAMETERS_AND_FUNCTIONALS>() {}

vars_data xcint_vars[XC_NR_VARS] =
  {
    {"XC_A", 1, XC_DENSITY},
    {"XC_N", 1, XC_DENSITY},
    {"XC_A_B", 2, XC_DENSITY},
    {"XC_N_S", 2, XC_DENSITY},
    {"XC_A_GAA", 2, XC_DENSITY | XC_GRADIENT},
    {"XC_N_GNN", 2, XC_DENSITY | XC_GRADIENT},
    {"XC_A_B_GAA_GAB_GBB", 5, XC_DENSITY | XC_GRADIENT},
    {"XC_N_S_GNN_GNS_GSS", 5, XC_DENSITY | XC_GRADIENT},
    {"XC_A_GAA_LAPA", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_GAA_TAUA", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_GNN_LAPN", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_GNN_TAUN", 3, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_GAA_GAB_GBB_LAPA_LAPB",7, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_GAA_GAB_GBB_TAUA_TAUB",7, XC_DENSITY | XC_GRADIENT | XC_KINETIC},
    {"XC_N_S_GNN_GNS_GSS_LAPN_LAPS",7, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_S_GNN_GNS_GSS_TAUN_TAUS",7, XC_DENSITY | XC_GRADIENT | XC_KINETIC},
    {"XC_A_AX_AY_AZ",4, XC_DENSITY | XC_GRADIENT},
    {"XC_A_B_AX_AY_AZ_BZ_BY_BZ", 8, XC_DENSITY | XC_GRADIENT},
    {"XC_N_NX_NY_NZ",4, XC_DENSITY | XC_GRADIENT},
    {"XC_N_S_NX_NY_NZ_SZ_SY_SZ",8, XC_DENSITY | XC_GRADIENT},
    {"XC_A_2ND_TAYLOR", 10, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_A_B_2ND_TAYLOR", 20, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_2ND_TAYLOR", 10, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
    {"XC_N_S_2ND_TAYLOR", 20, XC_DENSITY | XC_GRADIENT | XC_LAPLACIAN},
  };

void xcint_assure_setup()
{
  static bool is_setup = false;
  if (!is_setup)
    {
      xcint_functional_setup_helper<0>();
      xcint_parameter_setup_helper<XC_NR_FUNCTIONALS>();
      is_setup = true;
    }
}

void xcint_die(const char *message, int code)
{
  fprintf(stderr,"XCFun fatal error %i: ",code);
  fprintf(stderr,"%s",message);
  fprintf(stderr,"\n");
  exit(-1);
}

int xcint_write_fortran_module()
{
  xcint_assure_setup();
  FILE *dst = fopen("fortran/xcfun_autogen.F90","w");
  int i;
  if (!dst)
    {
      perror("Open fortran/xcfun_autogen.F90 for writing failed");
      return -1;
    }
  fprintf(dst,"! Autogenerated file, do not edit\n"
	  "module xcfun_autogen\n");
  fprintf(dst,"  integer, parameter :: XCFUN_CHECKSUM = %i\n",
	  XCFUN_CHECKSUM);
  fprintf(dst,"  integer, parameter :: XCFUN_FORTRAN_INT_SIZE = %lu\n",
	  sizeof(fortran_int_t));
  fprintf(dst,"  integer, parameter :: XC_MAX_ORDER = %i\n",
	  XC_MAX_ORDER);
  fprintf(dst,"  integer, parameter :: XC_NR_FUNCTIONALS = %i\n",
	  XC_NR_FUNCTIONALS);
  fprintf(dst,"  integer, parameter :: XC_NR_PARAMETERS_AND_FUNCTIONALS = %i\n",
	  XC_NR_PARAMETERS_AND_FUNCTIONALS);
  fprintf(dst,"  integer, parameter :: XC_NR_VARS = %i\n",
	  XC_NR_VARS);
  fprintf(dst,"\n");
  fprintf(dst,"!Functionals\n");
  for (i=0;i<XC_NR_FUNCTIONALS;i++)
    fprintf(dst,"  integer, parameter :: XC_%s = %i\n",
	    xcint_funs[i].name,i);
  fprintf(dst,"\n");
  fprintf(dst,"!Parameters\n");
  for (i=XC_NR_FUNCTIONALS;i<XC_NR_PARAMETERS_AND_FUNCTIONALS;i++)
    fprintf(dst,"  integer, parameter :: XC_%s = %i\n",
	    xcint_params[i].name,i);
  fprintf(dst,"\n");
  for (i=0;i<XC_NR_VARS;i++)
    fprintf(dst,"  integer, parameter :: %s = %i\n",
	    xcint_vars[i].symbol,i);
  fprintf(dst,"end module\n");
  fclose(dst);
  return 0;
}

<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <atomic>

#include "ltac/Instruction.hpp"

using namespace eddic;

static std::atomic<std::size_t> uid_counter(0);

//Default constructor
ltac::Instruction::Instruction() : _uid(++uid_counter) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op) : _uid(++uid_counter), op(op) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1) : _uid(++uid_counter), op(op), arg1(arg1) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1, ltac::Argument arg2) : _uid(++uid_counter), op(op), arg1(arg1), arg2(arg2) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1, ltac::Argument arg2, ltac::Argument arg3) : _uid(++uid_counter), op(op), arg1(arg1), arg2(arg2), arg3(arg3) {
    //Nothing to init
}

ltac::Instruction::Instruction(std::string label, ltac::Operator op) : _uid(++uid_counter), op(op), label(std::move(label)) {
    //Nothing to init
}

ltac::Instruction::Instruction(const ltac::Instruction& rhs) :
    _uid(++uid_counter),
    op(rhs.op),
    arg1(rhs.arg1),
    arg2(rhs.arg2),
    arg3(rhs.arg3),
    size(rhs.size),
    label(rhs.label),
    target_function(rhs.target_function),
    uses(rhs.uses),
    float_uses(rhs.float_uses),
    hard_uses(rhs.hard_uses),
    hard_float_uses(rhs.hard_float_uses),
    kills(rhs.kills),
    float_kills(rhs.float_kills),
    hard_kills(rhs.hard_kills),
    hard_float_kills(rhs.hard_float_kills)
{
    //Nothing to init
}

ltac::Instruction& ltac::Instruction::operator=(const ltac::Instruction& rhs){
    //No need to assign this into this
    if(this == &rhs){
        return *this;
    }

    _uid = ++uid_counter;
    op = rhs.op;
    arg1 = rhs.arg1;
    arg2 = rhs.arg2;
    arg3 = rhs.arg3;
    size = rhs.size;
    label = rhs.label;
    target_function = rhs.target_function;
    uses = rhs.uses;
    float_uses = rhs.float_uses;
    hard_uses = rhs.hard_uses;
    hard_float_uses = rhs.hard_float_uses;
    kills = rhs.kills;
    float_kills = rhs.float_kills;
    hard_kills = rhs.hard_kills;
    hard_float_kills = rhs.hard_float_kills;

    return *this;
}

ltac::Instruction::Instruction(ltac::Instruction&& rhs) noexcept :
    _uid(std::move(rhs._uid)),
    op(std::move(rhs.op)),
    arg1(std::move(rhs.arg1)),
    arg2(std::move(rhs.arg2)),
    arg3(std::move(rhs.arg3)),
    size(std::move(rhs.size)),
    label(std::move(rhs.label)),
    target_function(std::move(rhs.target_function)),
    uses(std::move(rhs.uses)),
    float_uses(std::move(rhs.float_uses)),
    hard_uses(std::move(rhs.hard_uses)),
    hard_float_uses(std::move(rhs.hard_float_uses)),
    kills(std::move(rhs.kills)),
    float_kills(std::move(rhs.float_kills)),
    hard_kills(std::move(rhs.hard_kills)),
    hard_float_kills(std::move(rhs.hard_float_kills))
{
    rhs._uid = 0;
}

ltac::Instruction& ltac::Instruction::operator=(ltac::Instruction&& rhs) noexcept {
    //No need to assign this into this
    if(this == &rhs){
        return *this;
    }

    _uid = std::move(rhs._uid);
    op = std::move(rhs.op);
    arg1 = std::move(rhs.arg1);
    arg2 = std::move(rhs.arg2);
    arg3 = std::move(rhs.arg3);
    size = std::move(rhs.size);
    label = std::move(rhs.label);
    target_function = std::move(rhs.target_function);
    uses = std::move(rhs.uses);
    float_uses = std::move(rhs.float_uses);
    hard_uses = std::move(rhs.hard_uses);
    hard_float_uses = std::move(rhs.hard_float_uses);
    kills = std::move(rhs.kills);
    float_kills = std::move(rhs.float_kills);
    hard_kills = std::move(rhs.hard_kills);
    hard_float_kills = std::move(rhs.hard_float_kills);

    rhs._uid = 0;

    return *this;
}

bool ltac::Instruction::is_jump() const {
    return op >= ltac::Operator::ALWAYS && op <= ltac::Operator::NZ;
}

bool ltac::Instruction::is_label() const {
    return op == ltac::Operator::LABEL;
}
<commit_msg>Add log for copies<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <atomic>

#include "ltac/Instruction.hpp"

using namespace eddic;

static std::atomic<std::size_t> uid_counter(0);

//Default constructor
ltac::Instruction::Instruction() : _uid(++uid_counter) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op) : _uid(++uid_counter), op(op) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1) : _uid(++uid_counter), op(op), arg1(arg1) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1, ltac::Argument arg2) : _uid(++uid_counter), op(op), arg1(arg1), arg2(arg2) {
    //Nothing to init
}

ltac::Instruction::Instruction(ltac::Operator op, ltac::Argument arg1, ltac::Argument arg2, ltac::Argument arg3) : _uid(++uid_counter), op(op), arg1(arg1), arg2(arg2), arg3(arg3) {
    //Nothing to init
}

ltac::Instruction::Instruction(std::string label, ltac::Operator op) : _uid(++uid_counter), op(op), label(std::move(label)) {
    //Nothing to init
}

ltac::Instruction::Instruction(const ltac::Instruction& rhs) :
    _uid(++uid_counter),
    op(rhs.op),
    arg1(rhs.arg1),
    arg2(rhs.arg2),
    arg3(rhs.arg3),
    size(rhs.size),
    label(rhs.label),
    target_function(rhs.target_function),
    uses(rhs.uses),
    float_uses(rhs.float_uses),
    hard_uses(rhs.hard_uses),
    hard_float_uses(rhs.hard_float_uses),
    kills(rhs.kills),
    float_kills(rhs.float_kills),
    hard_kills(rhs.hard_kills),
    hard_float_kills(rhs.hard_float_kills)
{
    std::cout << "COPY" << std::endl;

    //Nothing to init
}

ltac::Instruction& ltac::Instruction::operator=(const ltac::Instruction& rhs){
    //No need to assign this into this
    if(this == &rhs){
        return *this;
    }

    std::cout << "COPY" << std::endl;

    _uid = ++uid_counter;
    op = rhs.op;
    arg1 = rhs.arg1;
    arg2 = rhs.arg2;
    arg3 = rhs.arg3;
    size = rhs.size;
    label = rhs.label;
    target_function = rhs.target_function;
    uses = rhs.uses;
    float_uses = rhs.float_uses;
    hard_uses = rhs.hard_uses;
    hard_float_uses = rhs.hard_float_uses;
    kills = rhs.kills;
    float_kills = rhs.float_kills;
    hard_kills = rhs.hard_kills;
    hard_float_kills = rhs.hard_float_kills;

    return *this;
}

ltac::Instruction::Instruction(ltac::Instruction&& rhs) noexcept :
    _uid(std::move(rhs._uid)),
    op(std::move(rhs.op)),
    arg1(std::move(rhs.arg1)),
    arg2(std::move(rhs.arg2)),
    arg3(std::move(rhs.arg3)),
    size(std::move(rhs.size)),
    label(std::move(rhs.label)),
    target_function(std::move(rhs.target_function)),
    uses(std::move(rhs.uses)),
    float_uses(std::move(rhs.float_uses)),
    hard_uses(std::move(rhs.hard_uses)),
    hard_float_uses(std::move(rhs.hard_float_uses)),
    kills(std::move(rhs.kills)),
    float_kills(std::move(rhs.float_kills)),
    hard_kills(std::move(rhs.hard_kills)),
    hard_float_kills(std::move(rhs.hard_float_kills))
{
    rhs._uid = 0;
}

ltac::Instruction& ltac::Instruction::operator=(ltac::Instruction&& rhs) noexcept {
    //No need to assign this into this
    if(this == &rhs){
        return *this;
    }

    _uid = std::move(rhs._uid);
    op = std::move(rhs.op);
    arg1 = std::move(rhs.arg1);
    arg2 = std::move(rhs.arg2);
    arg3 = std::move(rhs.arg3);
    size = std::move(rhs.size);
    label = std::move(rhs.label);
    target_function = std::move(rhs.target_function);
    uses = std::move(rhs.uses);
    float_uses = std::move(rhs.float_uses);
    hard_uses = std::move(rhs.hard_uses);
    hard_float_uses = std::move(rhs.hard_float_uses);
    kills = std::move(rhs.kills);
    float_kills = std::move(rhs.float_kills);
    hard_kills = std::move(rhs.hard_kills);
    hard_float_kills = std::move(rhs.hard_float_kills);

    rhs._uid = 0;

    return *this;
}

bool ltac::Instruction::is_jump() const {
    return op >= ltac::Operator::ALWAYS && op <= ltac::Operator::NZ;
}

bool ltac::Instruction::is_label() const {
    return op == ltac::Operator::LABEL;
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "KmlOverlayTagWriter.h"

#include "GeoDataTypes.h"
#include "GeoDataOverlay.h"
#include "GeoWriter.h"
#include "KmlElementDictionary.h"
#include "KmlColorStyleTagWriter.h"

namespace Marble
{

KmlOverlayTagWriter::KmlOverlayTagWriter(const QString &elementName)
    : m_elementName( elementName )
{
    // nothing to do
}

bool KmlOverlayTagWriter::write( const Marble::GeoNode *node, GeoWriter &writer ) const
{
    writer.writeStartElement( m_elementName );

    GeoDataOverlay const *overlay = static_cast<const GeoDataOverlay*>(node);
    QString const color = KmlColorStyleTagWriter::formatColor( overlay->color() );
    writer.writeOptionalElement( kml::kmlTag_color, color, "ffffffff" );
    QString const drawOrder = QString::number( overlay->drawOrder() );
    writer.writeOptionalElement( kml::kmlTag_drawOrder, drawOrder, "0" );

    if ( !overlay->iconFile().isEmpty() ) {
        writer.writeStartElement( kml::kmlTag_Icon );
        writer.writeStartElement( kml::kmlTag_href );
        writer.writeCharacters( overlay->iconFile() );
        writer.writeEndElement();
        writer.writeEndElement();
    }

    bool const result = writeMid( node, writer );
    writer.writeEndElement();
    return result;
}

}
<commit_msg>Write the overlay name, if set.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2012      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "KmlOverlayTagWriter.h"

#include "GeoDataTypes.h"
#include "GeoDataOverlay.h"
#include "GeoWriter.h"
#include "KmlElementDictionary.h"
#include "KmlColorStyleTagWriter.h"

namespace Marble
{

KmlOverlayTagWriter::KmlOverlayTagWriter(const QString &elementName)
    : m_elementName( elementName )
{
    // nothing to do
}

bool KmlOverlayTagWriter::write( const Marble::GeoNode *node, GeoWriter &writer ) const
{
    writer.writeStartElement( m_elementName );

    GeoDataOverlay const *overlay = static_cast<const GeoDataOverlay*>(node);
    writer.writeOptionalElement( kml::kmlTag_name, overlay->name() );
    QString const color = KmlColorStyleTagWriter::formatColor( overlay->color() );
    writer.writeOptionalElement( kml::kmlTag_color, color, "ffffffff" );
    QString const drawOrder = QString::number( overlay->drawOrder() );
    writer.writeOptionalElement( kml::kmlTag_drawOrder, drawOrder, "0" );

    if ( !overlay->iconFile().isEmpty() ) {
        writer.writeStartElement( kml::kmlTag_Icon );
        writer.writeStartElement( kml::kmlTag_href );
        writer.writeCharacters( overlay->iconFile() );
        writer.writeEndElement();
        writer.writeEndElement();
    }

    bool const result = writeMid( node, writer );
    writer.writeEndElement();
    return result;
}

}
<|endoftext|>


<commit_before>#include <vtkSphereSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>

#include "geometry/vtk_utils.h"
#include "system/parse_stl.h"

#include "mainwindow.h"
#include "ui_mainwindow.h"

using namespace gca;

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)//, ui(new Ui::MainWindow)
{
  //ui->setupUi(this);

  vtk_window = new QVTKWidget(this, Qt::Widget);
  setCentralWidget(vtk_window);

  auto m =
    parse_stl("/Users/dillon/CppWorkspace/gca/test/stl-files/onshape_parts/SmallReverseCameraMount - Part 1.stl", 0.0001);

  auto mesh_pd = polydata_for_trimesh(m);

  // vtkSmartPointer<vtkSphereSource> sphereSource =
  //   vtkSmartPointer<vtkSphereSource>::New();
  // sphereSource->SetCenter(0.0, 0.0, 0.0);
  // sphereSource->SetRadius(5.0);

  vtkSmartPointer<vtkPolyDataMapper> mapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputData(mesh_pd); //sphereSource->GetOutputPort());

  vtkSmartPointer<vtkActor> actor =
    vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();

  renderer->SetBackground(1, 1, 1);
  renderer->AddActor(actor);

  vtk_window->GetRenderWindow()->AddRenderer(renderer);

  vtk_window->show();

}

MainWindow::~MainWindow()
{
}
<commit_msg>Now creating proper layout with buttons<commit_after>#include <vtkSphereSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>

#include "geometry/vtk_utils.h"
#include "system/parse_stl.h"

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QHBoxLayout>
#include <QPushButton>

using namespace gca;

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)
{

  vtk_window = new QVTKWidget(this, Qt::Widget);

  QHBoxLayout *layout = new QHBoxLayout;
  QPushButton *button2 = new QPushButton("button2");

  layout->addWidget(vtk_window);
  layout->addWidget(button2);

  setCentralWidget(new QWidget);
  centralWidget()->setLayout(layout);

  auto m =
    parse_stl("/Users/dillon/CppWorkspace/gca/test/stl-files/onshape_parts/SmallReverseCameraMount - Part 1.stl", 0.0001);

  auto mesh_pd = polydata_for_trimesh(m);

  vtkSmartPointer<vtkPolyDataMapper> mapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputData(mesh_pd);

  vtkSmartPointer<vtkActor> actor =
    vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);

  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();

  renderer->SetBackground(1, 1, 1);
  renderer->AddActor(actor);

  vtk_window->GetRenderWindow()->AddRenderer(renderer);

  vtk_window->show();

}

MainWindow::~MainWindow()
{
}
<|endoftext|>


<commit_before>#ifndef TAKEWHILE__H__
#define TAKEWHILE__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of TakeWhile and takewhile
    template <typename FilterFunc, typename Container>
    class TakeWhile;

    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(FilterFunc, Container &&);

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc, std::initializer_list<T> &&);

    template <typename FilterFunc, typename Container>
    class TakeWhile {
        private:
            Container & container;
            FilterFunc filter_func;

            friend TakeWhile takewhile<FilterFunc, Container>(
                    FilterFunc, Container &&);

            template <typename FF, typename T>
            friend TakeWhile<FF, std::initializer_list<T>> takewhile(
                    FF, std::initializer_list<T> &&);

            // Value constructor for use only in the takewhile function
            TakeWhile(FilterFunc filter_func, Container && container)
                : container{container},
                filter_func(filter_func)
            { }

            TakeWhile () = delete;
            TakeWhile & operator=(const TakeWhile &) = delete;

        public:
            TakeWhile(const TakeWhile &) = default;

            class Iterator {
                private:
                    using iter_type = iterator_type<Container>;
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // check if the current value is true under the predicate
                    // if it is not, set the sub_iter to the end using
                    // placement new to avoid the requirement of the iterator
                    // having an operator=
                    void check_current() {
                        if (!this->filter_func(*this->sub_iter)) {
                            this->sub_iter.~iter_type();
                            new(&this->sub_iter) iterator_type<Container>(
                                    this->sub_end);
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        if (this->sub_iter != this->sub_end) {
                            // only do the check if not already at the end
                            this->check_current();
                        }
                    }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        ++this->sub_iter;
                        this->check_current();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() const {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a TakeWhile
    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(
            FilterFunc filter_func, Container && container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc filter_func, std::initializer_list<T> && il)
    {
        return {filter_func, std::move(il)};
    }

}

#endif //ifndef TAKEWHILE__H__
<commit_msg>formats takewhile<commit_after>#ifndef TAKEWHILE__H__
#define TAKEWHILE__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    //Forward declarations of TakeWhile and takewhile
    template <typename FilterFunc, typename Container>
    class TakeWhile;

    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(FilterFunc, Container&&);

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc, std::initializer_list<T>&&);

    template <typename FilterFunc, typename Container>
    class TakeWhile {
        private:
            Container& container;
            FilterFunc filter_func;

            friend TakeWhile takewhile<FilterFunc, Container>(
                    FilterFunc, Container&&);

            template <typename FF, typename T>
            friend TakeWhile<FF, std::initializer_list<T>> takewhile(
                    FF, std::initializer_list<T>&&);

            // Value constructor for use only in the takewhile function
            TakeWhile(FilterFunc filter_func, Container&& container)
                : container{container},
                filter_func(filter_func)
            { }

            TakeWhile () = delete;
            TakeWhile& operator=(const TakeWhile&) = delete;

        public:
            TakeWhile(const TakeWhile&) = default;

            class Iterator {
                private:
                    using iter_type = iterator_type<Container>;
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    FilterFunc filter_func;

                    // check if the current value is true under the predicate
                    // if it is not, set the sub_iter to the end using
                    // placement new to avoid the requirement of the iterator
                    // having an operator=
                    void check_current() {
                        if (!this->filter_func(*this->sub_iter)) {
                            this->sub_iter.~iter_type();
                            new(&this->sub_iter) iterator_type<Container>(
                                    this->sub_end);
                        }
                    }

                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            FilterFunc filter_func)
                        : sub_iter{iter},
                        sub_end{end},
                        filter_func(filter_func)
                    {
                        if (this->sub_iter != this->sub_end) {
                            // only do the check if not already at the end
                            this->check_current();
                        }
                    }

                    iterator_deref<Container> operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        this->check_current();
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() const {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

            Iterator end() const {
                return {std::end(this->container),
                        std::end(this->container),
                        this->filter_func};
            }

    };

    // Helper function to instantiate a TakeWhile
    template <typename FilterFunc, typename Container>
    TakeWhile<FilterFunc, Container> takewhile(
            FilterFunc filter_func, Container&& container) {
        return {filter_func, std::forward<Container>(container)};
    }

    template <typename FilterFunc, typename T>
    TakeWhile<FilterFunc, std::initializer_list<T>> takewhile(
            FilterFunc filter_func, std::initializer_list<T>&& il)
    {
        return {filter_func, std::move(il)};
    }

}

#endif //ifndef TAKEWHILE__H__
<|endoftext|>


<commit_before>#line 2 "togo/window/input/input_buffer.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <togo/window/config.hpp>
#include <togo/core/error/assert.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/io/object_buffer.hpp>
#include <togo/window/window/impl/types.hpp>
#include <togo/window/window/impl/private.hpp>
#include <togo/window/input/input_buffer.hpp>

#undef TOGO_TEST_LOG_ENABLE
#if defined(TOGO_TEST_INPUT_BUFFER)
	#define TOGO_TEST_LOG_ENABLE
#endif
#include <togo/core/log/test.hpp>

namespace togo {

InputBuffer::~InputBuffer() {
	for (auto& window : _windows) {
		if (window != nullptr) {
			window::detach_from_input_buffer(window);
			window = nullptr;
			--_num_windows;
		}
	}
}

/// Add a window.
///
/// If the window is already owned by an input buffer, an assertion
/// will fail. If the input buffer has no space for more windows, an
/// assertion will fail.
void input_buffer::add_window(InputBuffer& ib, Window* window) {
	TOGO_DEBUG_ASSERTE(window);
	TOGO_ASSERT(
		ib._num_windows < INPUT_SYSTEM_NUM_WINDOWS,
		"input buffer has no space for window"
	);
	for (auto& it : ib._windows) {
		if (it == nullptr) {
			it = window;
			++ib._num_windows;
			window::attach_to_input_buffer(window, ib);
			return;
		}
	}
	TOGO_ASSERT(false, "something has gone terribly wrong");
}

/// Remove a window.
///
/// If the window is not owned by the input buffer, an assertion
/// will fail.
void input_buffer::remove_window(InputBuffer& ib, Window* window) {
	TOGO_DEBUG_ASSERTE(window);
	for (auto& it : ib._windows) {
		if (it == window) {
			window::detach_from_input_buffer(window);
			it = nullptr;
			--ib._num_windows;
			return;
		}
	}
	TOGO_ASSERT(false, "something has gone terribly wrong");
}

static void update_input_states(Window* window) {
	for (auto const code : window->_key_clear_queue) {
		window->_key_states[
			unsigned_cast(code)
		] &= ~(1 << unsigned_cast(KeyAction::release));
	}
	fixed_array::clear(window->_key_clear_queue);
	for (auto& state : window->_mouse_button_states) {
		state &= ~(1 << unsigned_cast(MouseButtonAction::release));
	}
}

/// Update input states.
///
/// This should be executed once per frame before polling the input
/// buffer.
void input_buffer::update(InputBuffer& ib) {
	for (auto window : ib._windows) {
		if (!window) {
			continue;
		}
		update_input_states(window);
	}
}

static void set_key_state(KeyEvent const& event) {
	Window* const window = event.window;
	if (event.action == KeyAction::press) {
		// If state already has KeyAction::release, retain it
		// (it will be cleared by update())
		window->_key_states[
			unsigned_cast(event.code)
		] |= 1 << unsigned_cast(event.action);
	} else if (event.action == KeyAction::release) {
		// Replace state and enqueue clear
		window->_key_states[
			unsigned_cast(event.code)
		] = 1 << unsigned_cast(event.action);
		for (auto const code : window->_key_clear_queue) {
			if (code == event.code) {
				return;
			}
		}
		if (fixed_array::space(window->_key_clear_queue)) {
			fixed_array::push_back(window->_key_clear_queue, event.code);
		} else {
			TOGO_LOGF(
				"input_buffer: warning: discarded key-clear for key %u on window %p\n",
				unsigned_cast(event.code),
				event.window
			);
		}
	}
}

/// Poll events.
///
/// Returns true if an event was fetched.
///
/// @warning This must be called on the thread that created the
/// windows.
bool input_buffer::poll(
	InputBuffer& ib,
	InputEventType& type,
	InputEvent const*& event
) {
	if (!ib._buffer._consume_mode) {
		window::process_events(ib);
		if (!object_buffer::empty(ib._buffer)) {
			object_buffer::begin_consume(ib._buffer);
		} else {
			return false;
		}
	} else {
		if (!object_buffer::has_more(ib._buffer)) {
			object_buffer::end_consume(ib._buffer);
			return false;
		}
	}
	void const* vptr = nullptr;
	object_buffer::read(ib._buffer, type, vptr);
	event = static_cast<InputEvent const*>(vptr);
	#if defined(TOGO_TEST_INPUT_BUFFER)
		TOGO_TEST_LOGF("input event: %p => ", event->window);
		switch (type) {
		case InputEventType::key:
			TOGO_TEST_LOGF(
				"key: action = %u  code = %u  mods = %u\n",
				unsigned_cast(event->key.action),
				unsigned_cast(event->key.code),
				unsigned_cast(event->key.mods)
			);
			break;
		case InputEventType::mouse_button:
			TOGO_TEST_LOGF(
				"mouse_button: action = %u   button = %u\n",
				unsigned_cast(event->mouse_button.action),
				unsigned_cast(event->mouse_button.button)
			);
			break;
		case InputEventType::mouse_motion:
			TOGO_TEST_LOGF(
				"mouse_motion: (%d, %d)\n",
				event->mouse_motion.x, event->mouse_motion.y
			);
			break;
		case InputEventType::window_focus:
			TOGO_TEST_LOGF(
				"window_focus: focused = %s\n",
				event->window_focus.focused ? "true" : "false"
			);
			break;
		case InputEventType::window_close_request:
			TOGO_TEST_LOG("window_close_request\n");
			break;
		case InputEventType::window_resize:
			TOGO_TEST_LOGF(
				"window_resize: (%-4u, %-4u) -> (%-4u, %-4u)\n",
				event->window_resize.old_width,
				event->window_resize.old_height,
				event->window_resize.new_width,
				event->window_resize.new_height
			);
			break;
		}
	#endif
	switch (type) {
	case InputEventType::key:
		set_key_state(event->key);
		break;

	case InputEventType::mouse_button:
		if (event->mouse_button.action == MouseButtonAction::press) {
			event->window->_mouse_button_states[
				unsigned_cast(event->mouse_button.button)
			] |= 1 << unsigned_cast(event->mouse_button.action);
		} else if (event->mouse_button.action == MouseButtonAction::release) {
			event->window->_mouse_button_states[
				unsigned_cast(event->mouse_button.button)
			]  = 1 << unsigned_cast(event->mouse_button.action);
		}
		break;

	case InputEventType::mouse_motion:
		event->window->_mouse_x = event->mouse_motion.x;
		event->window->_mouse_y = event->mouse_motion.y;
		break;

	default:
		break;
	};
	return true;
}

} // namespace togo
<commit_msg>lib/window/input/input_buffer: corrected test log for WindowResizeEvent.<commit_after>#line 2 "togo/window/input/input_buffer.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <togo/window/config.hpp>
#include <togo/core/error/assert.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/io/object_buffer.hpp>
#include <togo/window/window/impl/types.hpp>
#include <togo/window/window/impl/private.hpp>
#include <togo/window/input/input_buffer.hpp>

#undef TOGO_TEST_LOG_ENABLE
#if defined(TOGO_TEST_INPUT_BUFFER)
	#define TOGO_TEST_LOG_ENABLE
#endif
#include <togo/core/log/test.hpp>

namespace togo {

InputBuffer::~InputBuffer() {
	for (auto& window : _windows) {
		if (window != nullptr) {
			window::detach_from_input_buffer(window);
			window = nullptr;
			--_num_windows;
		}
	}
}

/// Add a window.
///
/// If the window is already owned by an input buffer, an assertion
/// will fail. If the input buffer has no space for more windows, an
/// assertion will fail.
void input_buffer::add_window(InputBuffer& ib, Window* window) {
	TOGO_DEBUG_ASSERTE(window);
	TOGO_ASSERT(
		ib._num_windows < INPUT_SYSTEM_NUM_WINDOWS,
		"input buffer has no space for window"
	);
	for (auto& it : ib._windows) {
		if (it == nullptr) {
			it = window;
			++ib._num_windows;
			window::attach_to_input_buffer(window, ib);
			return;
		}
	}
	TOGO_ASSERT(false, "something has gone terribly wrong");
}

/// Remove a window.
///
/// If the window is not owned by the input buffer, an assertion
/// will fail.
void input_buffer::remove_window(InputBuffer& ib, Window* window) {
	TOGO_DEBUG_ASSERTE(window);
	for (auto& it : ib._windows) {
		if (it == window) {
			window::detach_from_input_buffer(window);
			it = nullptr;
			--ib._num_windows;
			return;
		}
	}
	TOGO_ASSERT(false, "something has gone terribly wrong");
}

static void update_input_states(Window* window) {
	for (auto const code : window->_key_clear_queue) {
		window->_key_states[
			unsigned_cast(code)
		] &= ~(1 << unsigned_cast(KeyAction::release));
	}
	fixed_array::clear(window->_key_clear_queue);
	for (auto& state : window->_mouse_button_states) {
		state &= ~(1 << unsigned_cast(MouseButtonAction::release));
	}
}

/// Update input states.
///
/// This should be executed once per frame before polling the input
/// buffer.
void input_buffer::update(InputBuffer& ib) {
	for (auto window : ib._windows) {
		if (!window) {
			continue;
		}
		update_input_states(window);
	}
}

static void set_key_state(KeyEvent const& event) {
	Window* const window = event.window;
	if (event.action == KeyAction::press) {
		// If state already has KeyAction::release, retain it
		// (it will be cleared by update())
		window->_key_states[
			unsigned_cast(event.code)
		] |= 1 << unsigned_cast(event.action);
	} else if (event.action == KeyAction::release) {
		// Replace state and enqueue clear
		window->_key_states[
			unsigned_cast(event.code)
		] = 1 << unsigned_cast(event.action);
		for (auto const code : window->_key_clear_queue) {
			if (code == event.code) {
				return;
			}
		}
		if (fixed_array::space(window->_key_clear_queue)) {
			fixed_array::push_back(window->_key_clear_queue, event.code);
		} else {
			TOGO_LOGF(
				"input_buffer: warning: discarded key-clear for key %u on window %p\n",
				unsigned_cast(event.code),
				event.window
			);
		}
	}
}

/// Poll events.
///
/// Returns true if an event was fetched.
///
/// @warning This must be called on the thread that created the
/// windows.
bool input_buffer::poll(
	InputBuffer& ib,
	InputEventType& type,
	InputEvent const*& event
) {
	if (!ib._buffer._consume_mode) {
		window::process_events(ib);
		if (!object_buffer::empty(ib._buffer)) {
			object_buffer::begin_consume(ib._buffer);
		} else {
			return false;
		}
	} else {
		if (!object_buffer::has_more(ib._buffer)) {
			object_buffer::end_consume(ib._buffer);
			return false;
		}
	}
	void const* vptr = nullptr;
	object_buffer::read(ib._buffer, type, vptr);
	event = static_cast<InputEvent const*>(vptr);
	#if defined(TOGO_TEST_INPUT_BUFFER)
		TOGO_TEST_LOGF("input event: %p => ", event->window);
		switch (type) {
		case InputEventType::key:
			TOGO_TEST_LOGF(
				"key: action = %u  code = %u  mods = %u\n",
				unsigned_cast(event->key.action),
				unsigned_cast(event->key.code),
				unsigned_cast(event->key.mods)
			);
			break;
		case InputEventType::mouse_button:
			TOGO_TEST_LOGF(
				"mouse_button: action = %u   button = %u\n",
				unsigned_cast(event->mouse_button.action),
				unsigned_cast(event->mouse_button.button)
			);
			break;
		case InputEventType::mouse_motion:
			TOGO_TEST_LOGF(
				"mouse_motion: (%d, %d)\n",
				event->mouse_motion.x, event->mouse_motion.y
			);
			break;
		case InputEventType::window_focus:
			TOGO_TEST_LOGF(
				"window_focus: focused = %s\n",
				event->window_focus.focused ? "true" : "false"
			);
			break;
		case InputEventType::window_close_request:
			TOGO_TEST_LOG("window_close_request\n");
			break;
		case InputEventType::window_resize:
			TOGO_TEST_LOGF(
				"window_resize: (%-4u, %-4u) -> (%-4u, %-4u)\n",
				event->window_resize.old_size.width,
				event->window_resize.old_size.height,
				event->window_resize.new_size.width,
				event->window_resize.new_size.height
			);
			break;
		}
	#endif
	switch (type) {
	case InputEventType::key:
		set_key_state(event->key);
		break;

	case InputEventType::mouse_button:
		if (event->mouse_button.action == MouseButtonAction::press) {
			event->window->_mouse_button_states[
				unsigned_cast(event->mouse_button.button)
			] |= 1 << unsigned_cast(event->mouse_button.action);
		} else if (event->mouse_button.action == MouseButtonAction::release) {
			event->window->_mouse_button_states[
				unsigned_cast(event->mouse_button.button)
			]  = 1 << unsigned_cast(event->mouse_button.action);
		}
		break;

	case InputEventType::mouse_motion:
		event->window->_mouse_x = event->mouse_motion.x;
		event->window->_mouse_y = event->mouse_motion.y;
		break;

	default:
		break;
	};
	return true;
}

} // namespace togo
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "include/wrapper/cef_stream_resource_handler.h"

#include <algorithm>

#include "include/base/cef_logging.h"
#include "include/base/cef_macros.h"
#include "include/cef_callback.h"
#include "include/cef_request.h"
#include "include/cef_runnable.h"
#include "include/cef_stream.h"
#include "include/wrapper/cef_helpers.h"

// Class that represents a readable/writable character buffer.
class CefStreamResourceHandler::Buffer {
 public:
  Buffer()
      : buffer_(NULL),
        size_(0),
        bytes_requested_(0),
        bytes_written_(0),
        bytes_read_(0) {
  }

  ~Buffer() {
    if (buffer_)
      delete [] buffer_;
  }

  void Reset(int new_size) {
    if (size_ < new_size) {
      if (buffer_)
        delete [] buffer_;
      size_ = new_size;
      buffer_ = new char[size_];
      DCHECK(buffer_);
    }
    bytes_requested_ = new_size;
    bytes_written_ = 0;
    bytes_read_ = 0;
  }

  bool IsEmpty() const {
    return (bytes_written_ == 0);
  }

  bool CanRead() const {
    return (bytes_read_ < bytes_written_);
  }

  int WriteTo(void* data_out, int bytes_to_read) {
    const int write_size =
        std::min(bytes_to_read, bytes_written_ - bytes_read_);
    if (write_size > 0) {
      memcpy(data_out, buffer_  + bytes_read_, write_size);
      bytes_read_ += write_size;
    }
    return write_size;
  }

  int ReadFrom(CefRefPtr<CefStreamReader> reader) {
    // Read until the buffer is full or until Read() returns 0 to indicate no
    // more data.
    int bytes_read;
    do {
      bytes_read = static_cast<int>(
          reader->Read(buffer_ + bytes_written_, 1,
                       bytes_requested_ - bytes_written_));
      bytes_written_ += bytes_read;
    } while (bytes_read != 0 && bytes_written_ < bytes_requested_);

    return bytes_written_;
  }

 private:
  char* buffer_;
  int size_;
  int bytes_requested_;
  int bytes_written_;
  int bytes_read_;

  DISALLOW_COPY_AND_ASSIGN(Buffer);
};

CefStreamResourceHandler::CefStreamResourceHandler(
    const CefString& mime_type,
    CefRefPtr<CefStreamReader> stream)
    : status_code_(200),
      status_text_("OK"),
      mime_type_(mime_type),
      stream_(stream),
      buffer_(NULL)
#ifndef NDEBUG
      , buffer_owned_by_file_thread_(false)
#endif
{
  DCHECK(!mime_type_.empty());
  DCHECK(stream_.get());
  read_on_file_thread_ = stream_->MayBlock();
}

CefStreamResourceHandler::CefStreamResourceHandler(
    int status_code,
    const CefString& status_text,
    const CefString& mime_type,
    CefResponse::HeaderMap header_map,
    CefRefPtr<CefStreamReader> stream)
    : status_code_(status_code),
      status_text_(status_text),
      mime_type_(mime_type),
      header_map_(header_map),
      stream_(stream),
      buffer_(NULL) {
  DCHECK(!mime_type_.empty());
  DCHECK(stream_.get());
  read_on_file_thread_ = stream_->MayBlock();
}

CefStreamResourceHandler::~CefStreamResourceHandler() {
  if (buffer_)
    delete buffer_;
}

bool CefStreamResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
                                              CefRefPtr<CefCallback> callback) {
  callback->Continue();
  return true;
}

void CefStreamResourceHandler::GetResponseHeaders(
    CefRefPtr<CefResponse> response,
    int64& response_length,
    CefString& redirectUrl) {
  response->SetStatus(status_code_);
  response->SetStatusText(status_text_);
  response->SetMimeType(mime_type_);

  if (!header_map_.empty())
    response->SetHeaderMap(header_map_);

  response_length = -1;
}

bool CefStreamResourceHandler::ReadResponse(void* data_out,
                                            int bytes_to_read,
                                            int& bytes_read,
                                            CefRefPtr<CefCallback> callback) {
  DCHECK_GT(bytes_to_read, 0);

  if (read_on_file_thread_) {
    DCHECK(!buffer_owned_by_file_thread_);
    if (buffer_ && (buffer_->CanRead() || buffer_->IsEmpty())) {
      if (buffer_->CanRead()) {
        // Provide data from the buffer.
        bytes_read = buffer_->WriteTo(data_out, bytes_to_read);
        return (bytes_read > 0);
      } else {
        // End of the steam.
        bytes_read = 0;
        return false;
      }
    } else {
      // Perform another read on the file thread.
      bytes_read = 0;
#ifndef NDEBUG
      buffer_owned_by_file_thread_ = true;
#endif
      CefPostTask(TID_FILE,
          NewCefRunnableMethod(this, &CefStreamResourceHandler::ReadOnFileThread,
                               bytes_to_read, callback));
      return true;
    }
  } else {
    // Read until the buffer is full or until Read() returns 0 to indicate no
    // more data.
    bytes_read = 0;
    int read = 0;
    do {
      read = static_cast<int>(
          stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
                        bytes_to_read - bytes_read));
      bytes_read += read;
    } while (read != 0 && bytes_read < bytes_to_read);

    return (bytes_read > 0);
  }
}

void CefStreamResourceHandler::Cancel() {
}

void CefStreamResourceHandler::ReadOnFileThread(
    int bytes_to_read,
    CefRefPtr<CefCallback> callback) {
  CEF_REQUIRE_FILE_THREAD();
  DCHECK(buffer_owned_by_file_thread_);

  if (!buffer_)
    buffer_ = new Buffer();
  buffer_->Reset(bytes_to_read);
  buffer_->ReadFrom(stream_);

#ifndef NDEBUG
  buffer_owned_by_file_thread_ = false;
#endif
  callback->Continue();
}
<commit_msg>Fix Release build compile error.<commit_after>// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "include/wrapper/cef_stream_resource_handler.h"

#include <algorithm>

#include "include/base/cef_logging.h"
#include "include/base/cef_macros.h"
#include "include/cef_callback.h"
#include "include/cef_request.h"
#include "include/cef_runnable.h"
#include "include/cef_stream.h"
#include "include/wrapper/cef_helpers.h"

// Class that represents a readable/writable character buffer.
class CefStreamResourceHandler::Buffer {
 public:
  Buffer()
      : buffer_(NULL),
        size_(0),
        bytes_requested_(0),
        bytes_written_(0),
        bytes_read_(0) {
  }

  ~Buffer() {
    if (buffer_)
      delete [] buffer_;
  }

  void Reset(int new_size) {
    if (size_ < new_size) {
      if (buffer_)
        delete [] buffer_;
      size_ = new_size;
      buffer_ = new char[size_];
      DCHECK(buffer_);
    }
    bytes_requested_ = new_size;
    bytes_written_ = 0;
    bytes_read_ = 0;
  }

  bool IsEmpty() const {
    return (bytes_written_ == 0);
  }

  bool CanRead() const {
    return (bytes_read_ < bytes_written_);
  }

  int WriteTo(void* data_out, int bytes_to_read) {
    const int write_size =
        std::min(bytes_to_read, bytes_written_ - bytes_read_);
    if (write_size > 0) {
      memcpy(data_out, buffer_  + bytes_read_, write_size);
      bytes_read_ += write_size;
    }
    return write_size;
  }

  int ReadFrom(CefRefPtr<CefStreamReader> reader) {
    // Read until the buffer is full or until Read() returns 0 to indicate no
    // more data.
    int bytes_read;
    do {
      bytes_read = static_cast<int>(
          reader->Read(buffer_ + bytes_written_, 1,
                       bytes_requested_ - bytes_written_));
      bytes_written_ += bytes_read;
    } while (bytes_read != 0 && bytes_written_ < bytes_requested_);

    return bytes_written_;
  }

 private:
  char* buffer_;
  int size_;
  int bytes_requested_;
  int bytes_written_;
  int bytes_read_;

  DISALLOW_COPY_AND_ASSIGN(Buffer);
};

CefStreamResourceHandler::CefStreamResourceHandler(
    const CefString& mime_type,
    CefRefPtr<CefStreamReader> stream)
    : status_code_(200),
      status_text_("OK"),
      mime_type_(mime_type),
      stream_(stream),
      buffer_(NULL)
#ifndef NDEBUG
      , buffer_owned_by_file_thread_(false)
#endif
{
  DCHECK(!mime_type_.empty());
  DCHECK(stream_.get());
  read_on_file_thread_ = stream_->MayBlock();
}

CefStreamResourceHandler::CefStreamResourceHandler(
    int status_code,
    const CefString& status_text,
    const CefString& mime_type,
    CefResponse::HeaderMap header_map,
    CefRefPtr<CefStreamReader> stream)
    : status_code_(status_code),
      status_text_(status_text),
      mime_type_(mime_type),
      header_map_(header_map),
      stream_(stream),
      buffer_(NULL) {
  DCHECK(!mime_type_.empty());
  DCHECK(stream_.get());
  read_on_file_thread_ = stream_->MayBlock();
}

CefStreamResourceHandler::~CefStreamResourceHandler() {
  if (buffer_)
    delete buffer_;
}

bool CefStreamResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
                                              CefRefPtr<CefCallback> callback) {
  callback->Continue();
  return true;
}

void CefStreamResourceHandler::GetResponseHeaders(
    CefRefPtr<CefResponse> response,
    int64& response_length,
    CefString& redirectUrl) {
  response->SetStatus(status_code_);
  response->SetStatusText(status_text_);
  response->SetMimeType(mime_type_);

  if (!header_map_.empty())
    response->SetHeaderMap(header_map_);

  response_length = -1;
}

bool CefStreamResourceHandler::ReadResponse(void* data_out,
                                            int bytes_to_read,
                                            int& bytes_read,
                                            CefRefPtr<CefCallback> callback) {
  DCHECK_GT(bytes_to_read, 0);

  if (read_on_file_thread_) {
#ifndef NDEBUG
    DCHECK(!buffer_owned_by_file_thread_);
#endif
    if (buffer_ && (buffer_->CanRead() || buffer_->IsEmpty())) {
      if (buffer_->CanRead()) {
        // Provide data from the buffer.
        bytes_read = buffer_->WriteTo(data_out, bytes_to_read);
        return (bytes_read > 0);
      } else {
        // End of the steam.
        bytes_read = 0;
        return false;
      }
    } else {
      // Perform another read on the file thread.
      bytes_read = 0;
#ifndef NDEBUG
      buffer_owned_by_file_thread_ = true;
#endif
      CefPostTask(TID_FILE,
          NewCefRunnableMethod(this, &CefStreamResourceHandler::ReadOnFileThread,
                               bytes_to_read, callback));
      return true;
    }
  } else {
    // Read until the buffer is full or until Read() returns 0 to indicate no
    // more data.
    bytes_read = 0;
    int read = 0;
    do {
      read = static_cast<int>(
          stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
                        bytes_to_read - bytes_read));
      bytes_read += read;
    } while (read != 0 && bytes_read < bytes_to_read);

    return (bytes_read > 0);
  }
}

void CefStreamResourceHandler::Cancel() {
}

void CefStreamResourceHandler::ReadOnFileThread(
    int bytes_to_read,
    CefRefPtr<CefCallback> callback) {
  CEF_REQUIRE_FILE_THREAD();
#ifndef NDEBUG
  DCHECK(buffer_owned_by_file_thread_);
#endif

  if (!buffer_)
    buffer_ = new Buffer();
  buffer_->Reset(bytes_to_read);
  buffer_->ReadFrom(stream_);

#ifndef NDEBUG
  buffer_owned_by_file_thread_ = false;
#endif
  callback->Continue();
}
<|endoftext|>


<commit_before>// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/datatype/documenttype.h>
#include <vespa/document/repo/configbuilder.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/repo/document_type_repo_factory.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/testkit/testapp.h>

using vespalib::string;
using namespace document::config_builder;
using namespace document;

namespace {

const string type_name = "test";
const int32_t doc_type_id = 787121340;
const string header_name = type_name + ".header";
const string body_name = type_name + ".body";

std::shared_ptr<const DocumenttypesConfig>
makeDocumentTypesConfig(const string &field_name)
{
    document::config_builder::DocumenttypesConfigBuilderHelper builder;
    builder.document(doc_type_id, type_name,
                     Struct(header_name),
                     Struct(body_name).addField(field_name,
                                                DataType::T_STRING));
    return std::make_shared<const DocumenttypesConfig>(builder.config());
}

TEST("requireThatEqualConfigsGivesSameRepo")
{
    auto config1 = makeDocumentTypesConfig("a");
    auto config2 = makeDocumentTypesConfig("b");
    auto config3 = std::make_shared<const DocumenttypesConfig>(*config1);
    auto config4 = std::make_shared<const DocumenttypesConfig>(*config2);
    auto repo1 = DocumentTypeRepoFactory::make(*config1);
    auto repo2 = DocumentTypeRepoFactory::make(*config2);
    auto repo3 = DocumentTypeRepoFactory::make(*config3);
    auto repo4 = DocumentTypeRepoFactory::make(*config4);
    EXPECT_NOT_EQUAL(repo1, repo2);
    EXPECT_EQUAL(repo1, repo3);
    EXPECT_NOT_EQUAL(repo1, repo4);
    EXPECT_NOT_EQUAL(repo2, repo3);
    EXPECT_EQUAL(repo2, repo4);
    EXPECT_NOT_EQUAL(repo3, repo4);
}

}

TEST_MAIN() { TEST_RUN_ALL(); }
<commit_msg>Adjust test name.<commit_after>// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/document/datatype/documenttype.h>
#include <vespa/document/repo/configbuilder.h>
#include <vespa/document/repo/documenttyperepo.h>
#include <vespa/document/repo/document_type_repo_factory.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/testkit/testapp.h>

using vespalib::string;
using namespace document::config_builder;
using namespace document;

namespace {

const string type_name = "test";
const int32_t doc_type_id = 787121340;
const string header_name = type_name + ".header";
const string body_name = type_name + ".body";

std::shared_ptr<const DocumenttypesConfig>
makeDocumentTypesConfig(const string &field_name)
{
    document::config_builder::DocumenttypesConfigBuilderHelper builder;
    builder.document(doc_type_id, type_name,
                     Struct(header_name),
                     Struct(body_name).addField(field_name,
                                                DataType::T_STRING));
    return std::make_shared<const DocumenttypesConfig>(builder.config());
}

TEST("require that equal configs gives same repo")
{
    auto config1 = makeDocumentTypesConfig("a");
    auto config2 = makeDocumentTypesConfig("b");
    auto config3 = std::make_shared<const DocumenttypesConfig>(*config1);
    auto config4 = std::make_shared<const DocumenttypesConfig>(*config2);
    auto repo1 = DocumentTypeRepoFactory::make(*config1);
    auto repo2 = DocumentTypeRepoFactory::make(*config2);
    auto repo3 = DocumentTypeRepoFactory::make(*config3);
    auto repo4 = DocumentTypeRepoFactory::make(*config4);
    EXPECT_NOT_EQUAL(repo1, repo2);
    EXPECT_EQUAL(repo1, repo3);
    EXPECT_NOT_EQUAL(repo1, repo4);
    EXPECT_NOT_EQUAL(repo2, repo3);
    EXPECT_EQUAL(repo2, repo4);
    EXPECT_NOT_EQUAL(repo3, repo4);
}

}

TEST_MAIN() { TEST_RUN_ALL(); }
<|endoftext|>