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

#include <google/dense_hash_set>

#include <locale>
#include <list>
#include <iostream>
#include <string>
#include <atomic>

#include <re2/re2.h>

#include "smart_git.h"
#include "timer.h"
#include "thread_queue.h"
#include "thread_pool.h"

using google::dense_hash_set;
using re2::RE2;
using re2::StringPiece;
using namespace std;

#define CHUNK_SIZE (1 << 20)
#define MAX_GAP    (1 << 12)

struct search_file {
    string path;
    const char *ref;
    git_oid oid;
};

struct chunk_file {
    search_file *file;
    int left;
    int right;
    void expand(int l, int r) {
        left  = min(left, l);
        right = max(right, r);
    }

    bool operator<(const chunk_file& rhs) const {
        return left < rhs.left;
    }
};

struct match_result {
    search_file *file;
    int lno;
    StringPiece line;
};

#define CHUNK_MAGIC 0xC407FADE

struct chunk {
    int size;
    unsigned magic;
    vector<chunk_file> files;
    vector<chunk_file> cur_file;
    char data[0];

    chunk()
        : size(0), magic(CHUNK_MAGIC), files() {
    }

    void add_chunk_file(search_file *sf, const StringPiece &line) {
        int l = line.data() - data;
        int r = l + line.size();
        chunk_file *f = NULL;
        int min_dist = numeric_limits<int>::max(), dist;
        for (vector<chunk_file>::iterator it = cur_file.begin();
             it != cur_file.end(); it ++) {
            if (l <= it->left)
                dist = max(0, it->left - r);
            else if (r >= it->right)
                dist = max(0, l - it->right);
            else
                dist = 0;
            assert(dist == 0 || r < it->left || l > it->right);
            if (dist < min_dist) {
                min_dist = dist;
                f = &(*it);
            }
        }
        if (f && min_dist < MAX_GAP) {
            f->expand(l, r);
            return;
        }
        cur_file.push_back(chunk_file());
        chunk_file &cf = cur_file.back();
        cf.file = sf;
        cf.left = l;
        cf.right = r;
    }

    void finish_file() {
        int right = -1;
        sort(cur_file.begin(), cur_file.end());
        for (vector<chunk_file>::iterator it = cur_file.begin();
             it != cur_file.end(); it ++) {
            assert(right < it->left);
            right = max(right, it->right);
        }
        files.insert(files.end(), cur_file.begin(), cur_file.end());
        cur_file.clear();
    }

    static chunk* from_str(const char *p) {
        chunk *out = reinterpret_cast<chunk*>
            (reinterpret_cast<uintptr_t>(p) & ~(CHUNK_SIZE - 1));
        assert(out->magic == CHUNK_MAGIC);
        return out;
    }
};

#define CHUNK_SPACE  (CHUNK_SIZE - (sizeof(chunk)))

chunk *alloc_chunk() {
    void *p;
    if (posix_memalign(&p, CHUNK_SIZE, CHUNK_SIZE) != 0)
        return NULL;
    return new(p) chunk;
};

class chunk_allocator {
public:
    chunk_allocator() : current_() {
        new_chunk();
    }

    char *alloc(size_t len) {
        assert(len < CHUNK_SPACE);
        if ((current_->size + len) > CHUNK_SPACE)
            new_chunk();
        char *out = current_->data + current_->size;
        current_->size += len;
        return out;
    }

    list<chunk*>::iterator begin () {
        return chunks_.begin();
    }

    typename list<chunk*>::iterator end () {
        return chunks_.end();
    }

    chunk *current_chunk() {
        return current_;
    }

protected:
    void new_chunk() {
        current_ = alloc_chunk();
        chunks_.push_back(current_);
    }

    list<chunk*> chunks_;
    chunk *current_;
};

/*
 * We special-case data() == NULL to provide an "empty" element for
 * dense_hash_set.
 *
 * StringPiece::operator== will consider a zero-length string equal to a
 * zero-length string with a NULL data().
 */
struct eqstr {
    bool operator()(const StringPiece& lhs, const StringPiece& rhs) const {
        if (lhs.data() == NULL && rhs.data() == NULL)
            return true;
        if (lhs.data() == NULL || rhs.data() == NULL)
            return false;
        return lhs == rhs;
    }
};

struct hashstr {
    locale loc;
    size_t operator()(const StringPiece &str) const {
        const collate<char> &coll = use_facet<collate<char> >(loc);
        return coll.hash(str.data(), str.data() + str.size());
    }
};

const StringPiece empty_string(NULL, 0);

typedef dense_hash_set<StringPiece, hashstr, eqstr> string_hash;

class code_counter;

class searcher {
public:
    searcher(code_counter *cc, thread_queue<match_result*> &queue, RE2& pat) :
        cc_(cc), pat_(pat), queue_(queue), matches_(0) {
    }

    bool operator()(const chunk *chunk) {
        if (chunk == NULL) {
            queue_.push(NULL);
            return true;
        }
        StringPiece str(chunk->data, chunk->size);
        StringPiece match;
        int pos = 0;
        while (pos < str.size()) {
            if (!pat_.Match(str, pos, str.size(), RE2::UNANCHORED, &match, 1))
                break;
            assert(memchr(match.data(), '\n', match.size()) == NULL);
            StringPiece line = find_line(str, match);
            find_match(line);
            pos = line.size() + line.data() - str.data();
            if (matches_ >= 10) {
                queue_.push(NULL);
                return true;
            }
        }
        return false;
    }

protected:
    void find_match (const StringPiece& line) {
        chunk *c = chunk::from_str(line.data());
        int off = line.data() - c->data;
        int lno;
        for(vector<chunk_file>::iterator it = c->files.begin();
            it != c->files.end(); it++) {
            if (off >= it->left && off < it->right) {
                lno = try_match(line, it->file);
                if (lno > 0) {
                    match_result *m = new match_result({it->file, lno, line});
                    queue_.push(m);
                    if (++matches_ >= 10)
                        return;
                }
            }
        }
    }

    int try_match(const StringPiece &line, search_file *sf);

    static StringPiece find_line(const StringPiece& chunk, const StringPiece& match) {
        const char *start, *end;
        assert(match.data() >= chunk.data());
        assert(match.data() < chunk.data() + chunk.size());
        assert(match.size() < (chunk.size() - (match.data() - chunk.data())));
        start = static_cast<const char*>
            (memrchr(chunk.data(), '\n', match.data() - chunk.data()));
        if (start == NULL)
            start = chunk.data();
        else
            start++;
        end = static_cast<const char*>
            (memchr(match.data() + match.size(), '\n',
                    chunk.size() - (match.data() - chunk.data()) - match.size()));
        if (end == NULL)
            end = chunk.data() + chunk.size();
        return StringPiece(start, end - start);
    }

    code_counter *cc_;
    RE2& pat_;
    thread_queue<match_result*> &queue_;
    atomic_int matches_;
};

class code_counter {
public:
    code_counter(git_repository *repo)
        : repo_(repo), stats_()
    {
        lines_.set_empty_key(empty_string);
    }

    void walk_ref(const char *ref) {
        smart_object<git_commit> commit;
        smart_object<git_tree> tree;
        resolve_ref(commit, ref);
        git_commit_tree(tree, commit);

        walk_tree(ref, "", tree);
    }

    void dump_stats() {
        printf("Bytes: %ld (dedup: %ld)\n", stats_.bytes, stats_.dedup_bytes);
        printf("Lines: %ld (dedup: %ld)\n", stats_.lines, stats_.dedup_lines);
    }

    bool match(RE2& pat) {
        list<chunk*>::iterator it;
        match_result *m;
        int matches = 0;
        int threads = 4;

        thread_queue<match_result*> results;
        searcher search(this, results, pat);
        thread_pool<chunk*, searcher&> pool(threads, search);

        for (it = alloc_.begin(); it != alloc_.end(); it++) {
            pool.queue(*it);
        }
        for (int i = 0; i < threads; i++)
            pool.queue(NULL);

        while (threads) {
            m = results.pop();
            if (!m) {
                threads--;
                continue;
            }
            matches++;
            print_match(m);
            delete m;
        }
        return matches > 0;
    }
protected:
    void print_match(const match_result *m) {
        printf("%s:%s:%d: %.*s\n",
               m->file->ref,
               m->file->path.c_str(),
               m->lno,
               m->line.size(), m->line.data());
    }

    void walk_tree(const char *ref, const string& pfx, git_tree *tree) {
        string path;
        int entries = git_tree_entrycount(tree);
        int i;
        for (i = 0; i < entries; i++) {
            const git_tree_entry *ent = git_tree_entry_byindex(tree, i);
            path = pfx + git_tree_entry_name(ent);
            smart_object<git_object> obj;
            git_tree_entry_2object(obj, repo_, ent);
            if (git_tree_entry_type(ent) == GIT_OBJ_TREE) {
                walk_tree(ref, path + "/", obj);
            } else if (git_tree_entry_type(ent) == GIT_OBJ_BLOB) {
                update_stats(ref, path, obj);
            }
        }
    }

    void update_stats(const char *ref, const string& path, git_blob *blob) {
        size_t len = git_blob_rawsize(blob);
        const char *p = static_cast<const char*>(git_blob_rawcontent(blob));
        const char *end = p + len;
        const char *f;
        search_file *sf = new search_file;
        sf->path = path;
        sf->ref = ref;
        git_oid_cpy(&sf->oid, git_object_id(reinterpret_cast<git_object*>(blob)));
        chunk *c;
        StringPiece line;

        while ((f = static_cast<const char*>(memchr(p, '\n', end - p))) != 0) {
            string_hash::iterator it = lines_.find(StringPiece(p, f - p));
            if (it == lines_.end()) {
                stats_.dedup_bytes += (f - p) + 1;
                stats_.dedup_lines ++;

                // Include the trailing '\n' in the chunk buffer
                char *alloc = alloc_.alloc(f - p + 1);
                memcpy(alloc, p, f - p + 1);
                line = StringPiece(alloc, f - p);
                lines_.insert(line);
                c = alloc_.current_chunk();
            } else {
                line = *it;
                c = chunk::from_str(line.data());
            }
            c->add_chunk_file(sf, line);
            p = f + 1;
            stats_.lines++;
        }

        for (list<chunk*>::iterator it = alloc_.begin();
             it != alloc_.end(); it++)
            (*it)->finish_file();

        stats_.bytes += len;
    }

    void resolve_ref(smart_object<git_commit> &out, const char *refname) {
        git_reference *ref;
        const git_oid *oid;
        git_oid tmp;
        smart_object<git_object> obj;
        if (git_oid_fromstr(&tmp, refname) == GIT_SUCCESS) {
            git_object_lookup(obj, repo_, &tmp, GIT_OBJ_ANY);
        } else {
            git_reference_lookup(&ref, repo_, refname);
            git_reference_resolve(&ref, ref);
            oid = git_reference_oid(ref);
            git_object_lookup(obj, repo_, oid, GIT_OBJ_ANY);
        }
        if (git_object_type(obj) == GIT_OBJ_TAG) {
            git_tag_target(out, obj);
        } else {
            out = obj.release();
        }
    }

    mutex repo_lock_;
    git_repository *repo_;
    string_hash lines_;
    struct {
        unsigned long bytes, dedup_bytes;
        unsigned long lines, dedup_lines;
    } stats_;
    chunk_allocator alloc_;

    friend class searcher;
};

int searcher::try_match(const StringPiece &line, search_file *sf) {
    smart_object<git_blob> blob;
    mutex_locker locked(cc_->repo_lock_);
    git_blob_lookup(blob, cc_->repo_, &sf->oid);
    int pos;
    StringPiece search(static_cast<const char*>(git_blob_rawcontent(blob)),
                       git_blob_rawsize(blob));
    pos = search.find(line);
    if (pos == StringPiece::npos) {
        return 0;
    }
    return 1 + count(search.data(), search.data() + pos, '\n');
}

int main(int argc, char **argv) {
    git_repository *repo;
    git_repository_open(&repo, ".git");

    code_counter counter(repo);

    for (int i = 1; i < argc; i++) {
        timer tm;
        struct timeval elapsed;
        printf("Walking %s...", argv[i]);
        fflush(stdout);
        counter.walk_ref(argv[i]);
        elapsed = tm.elapsed();
        printf(" done in %d.%06ds\n",
               (int)elapsed.tv_sec, (int)elapsed.tv_usec);
    }
    counter.dump_stats();
    RE2::Options opts;
    opts.set_never_nl(true);
    opts.set_one_line(false);
    opts.set_perl_classes(true);
    opts.set_posix_syntax(true);
    while (true) {
        printf("regex> ");
        string line;
        getline(cin, line);
        if (cin.eof())
            break;
        RE2 re(line, opts);
        if (re.ok()) {
            timer tm;
            struct timeval elapsed;
            if (!counter.match(re)) {
                printf("no match\n");
            }
            elapsed = tm.elapsed();
            printf("Match completed in %d.%06ds.\n",
                   (int)elapsed.tv_sec, (int)elapsed.tv_usec);
        }
    }

    return 0;
}
<commit_msg>Estimate the total number of matches.<commit_after>#include <stdio.h>
#include <assert.h>
#include <string.h>

#include <google/dense_hash_set>

#include <locale>
#include <list>
#include <iostream>
#include <string>
#include <atomic>

#include <re2/re2.h>

#include "smart_git.h"
#include "timer.h"
#include "thread_queue.h"
#include "thread_pool.h"

using google::dense_hash_set;
using re2::RE2;
using re2::StringPiece;
using namespace std;

#define CHUNK_SIZE (1 << 20)
#define MAX_GAP    (1 << 12)
#define MAX_MATCHES 10

struct search_file {
    string path;
    const char *ref;
    git_oid oid;
};

struct chunk_file {
    search_file *file;
    int left;
    int right;
    void expand(int l, int r) {
        left  = min(left, l);
        right = max(right, r);
    }

    bool operator<(const chunk_file& rhs) const {
        return left < rhs.left;
    }
};

struct match_result {
    search_file *file;
    int lno;
    StringPiece line;
};

#define CHUNK_MAGIC 0xC407FADE

struct chunk {
    int size;
    unsigned magic;
    vector<chunk_file> files;
    vector<chunk_file> cur_file;
    char data[0];

    chunk()
        : size(0), magic(CHUNK_MAGIC), files() {
    }

    void add_chunk_file(search_file *sf, const StringPiece &line) {
        int l = line.data() - data;
        int r = l + line.size();
        chunk_file *f = NULL;
        int min_dist = numeric_limits<int>::max(), dist;
        for (vector<chunk_file>::iterator it = cur_file.begin();
             it != cur_file.end(); it ++) {
            if (l <= it->left)
                dist = max(0, it->left - r);
            else if (r >= it->right)
                dist = max(0, l - it->right);
            else
                dist = 0;
            assert(dist == 0 || r < it->left || l > it->right);
            if (dist < min_dist) {
                min_dist = dist;
                f = &(*it);
            }
        }
        if (f && min_dist < MAX_GAP) {
            f->expand(l, r);
            return;
        }
        cur_file.push_back(chunk_file());
        chunk_file &cf = cur_file.back();
        cf.file = sf;
        cf.left = l;
        cf.right = r;
    }

    void finish_file() {
        int right = -1;
        sort(cur_file.begin(), cur_file.end());
        for (vector<chunk_file>::iterator it = cur_file.begin();
             it != cur_file.end(); it ++) {
            assert(right < it->left);
            right = max(right, it->right);
        }
        files.insert(files.end(), cur_file.begin(), cur_file.end());
        cur_file.clear();
    }

    static chunk* from_str(const char *p) {
        chunk *out = reinterpret_cast<chunk*>
            (reinterpret_cast<uintptr_t>(p) & ~(CHUNK_SIZE - 1));
        assert(out->magic == CHUNK_MAGIC);
        return out;
    }
};

#define CHUNK_SPACE  (CHUNK_SIZE - (sizeof(chunk)))

chunk *alloc_chunk() {
    void *p;
    if (posix_memalign(&p, CHUNK_SIZE, CHUNK_SIZE) != 0)
        return NULL;
    return new(p) chunk;
};

class chunk_allocator {
public:
    chunk_allocator() : current_() {
        new_chunk();
    }

    char *alloc(size_t len) {
        assert(len < CHUNK_SPACE);
        if ((current_->size + len) > CHUNK_SPACE)
            new_chunk();
        char *out = current_->data + current_->size;
        current_->size += len;
        return out;
    }

    list<chunk*>::iterator begin () {
        return chunks_.begin();
    }

    typename list<chunk*>::iterator end () {
        return chunks_.end();
    }

    chunk *current_chunk() {
        return current_;
    }

protected:
    void new_chunk() {
        current_ = alloc_chunk();
        chunks_.push_back(current_);
    }

    list<chunk*> chunks_;
    chunk *current_;
};

/*
 * We special-case data() == NULL to provide an "empty" element for
 * dense_hash_set.
 *
 * StringPiece::operator== will consider a zero-length string equal to a
 * zero-length string with a NULL data().
 */
struct eqstr {
    bool operator()(const StringPiece& lhs, const StringPiece& rhs) const {
        if (lhs.data() == NULL && rhs.data() == NULL)
            return true;
        if (lhs.data() == NULL || rhs.data() == NULL)
            return false;
        return lhs == rhs;
    }
};

struct hashstr {
    locale loc;
    size_t operator()(const StringPiece &str) const {
        const collate<char> &coll = use_facet<collate<char> >(loc);
        return coll.hash(str.data(), str.data() + str.size());
    }
};

const StringPiece empty_string(NULL, 0);

typedef dense_hash_set<StringPiece, hashstr, eqstr> string_hash;

class code_counter;

class searcher {
public:
    searcher(code_counter *cc, thread_queue<match_result*> &queue, RE2& pat) :
        cc_(cc), pat_(pat), queue_(queue),
        matches_(0), searched_(0), hit_rate_(0) {
    }

    bool operator()(const chunk *chunk) {
        if (chunk == NULL) {
            queue_.push(NULL);
            return true;
        }
        StringPiece str(chunk->data, chunk->size);
        StringPiece match;
        int pos = 0;
        while (pos < str.size()) {
            if (!pat_.Match(str, pos, str.size(), RE2::UNANCHORED, &match, 1))
                break;
            assert(memchr(match.data(), '\n', match.size()) == NULL);
            StringPiece line = find_line(str, match);
            find_match(line);
            pos = line.size() + line.data() - str.data();
        }
        return false;
    }

    int approx_matches() {
        if (hit_rate_ == 0)
            return matches_;
        return searched_ / hit_rate_;
    }

protected:
    void find_match (const StringPiece& line) {
        chunk *c = chunk::from_str(line.data());
        int off = line.data() - c->data;
        int lno;
        for(vector<chunk_file>::iterator it = c->files.begin();
            it != c->files.end(); it++) {
            if (off >= it->left && off < it->right) {
                searched_++;
                if (matches_.load() >= MAX_MATCHES)
                    continue;
                lno = try_match(line, it->file);
                if (lno > 0) {
                    match_result *m = new match_result({it->file, lno, line});
                    queue_.push(m);
                    if (++matches_ == 10)
                        hit_rate_ = float(searched_) / matches_;
                }
            }
        }
    }

    int try_match(const StringPiece &line, search_file *sf);

    static StringPiece find_line(const StringPiece& chunk, const StringPiece& match) {
        const char *start, *end;
        assert(match.data() >= chunk.data());
        assert(match.data() < chunk.data() + chunk.size());
        assert(match.size() < (chunk.size() - (match.data() - chunk.data())));
        start = static_cast<const char*>
            (memrchr(chunk.data(), '\n', match.data() - chunk.data()));
        if (start == NULL)
            start = chunk.data();
        else
            start++;
        end = static_cast<const char*>
            (memchr(match.data() + match.size(), '\n',
                    chunk.size() - (match.data() - chunk.data()) - match.size()));
        if (end == NULL)
            end = chunk.data() + chunk.size();
        return StringPiece(start, end - start);
    }

    code_counter *cc_;
    RE2& pat_;
    thread_queue<match_result*> &queue_;
    atomic_int matches_;
    atomic_int searched_;
    float hit_rate_;
};

class code_counter {
public:
    code_counter(git_repository *repo)
        : repo_(repo), stats_()
    {
        lines_.set_empty_key(empty_string);
    }

    void walk_ref(const char *ref) {
        smart_object<git_commit> commit;
        smart_object<git_tree> tree;
        resolve_ref(commit, ref);
        git_commit_tree(tree, commit);

        walk_tree(ref, "", tree);
    }

    void dump_stats() {
        printf("Bytes: %ld (dedup: %ld)\n", stats_.bytes, stats_.dedup_bytes);
        printf("Lines: %ld (dedup: %ld)\n", stats_.lines, stats_.dedup_lines);
    }

    bool match(RE2& pat) {
        list<chunk*>::iterator it;
        match_result *m;
        int matches = 0;
        int threads = 4;

        thread_queue<match_result*> results;
        searcher search(this, results, pat);
        thread_pool<chunk*, searcher&> pool(threads, search);

        for (it = alloc_.begin(); it != alloc_.end(); it++) {
            pool.queue(*it);
        }
        for (int i = 0; i < threads; i++)
            pool.queue(NULL);

        while (threads) {
            m = results.pop();
            if (!m) {
                threads--;
                continue;
            }
            matches++;
            print_match(m);
            delete m;
        }
        if (matches)
            printf("Results 1-%d of about %d.\n", matches, search.approx_matches());
        return matches > 0;
    }
protected:
    void print_match(const match_result *m) {
        printf("%s:%s:%d: %.*s\n",
               m->file->ref,
               m->file->path.c_str(),
               m->lno,
               m->line.size(), m->line.data());
    }

    void walk_tree(const char *ref, const string& pfx, git_tree *tree) {
        string path;
        int entries = git_tree_entrycount(tree);
        int i;
        for (i = 0; i < entries; i++) {
            const git_tree_entry *ent = git_tree_entry_byindex(tree, i);
            path = pfx + git_tree_entry_name(ent);
            smart_object<git_object> obj;
            git_tree_entry_2object(obj, repo_, ent);
            if (git_tree_entry_type(ent) == GIT_OBJ_TREE) {
                walk_tree(ref, path + "/", obj);
            } else if (git_tree_entry_type(ent) == GIT_OBJ_BLOB) {
                update_stats(ref, path, obj);
            }
        }
    }

    void update_stats(const char *ref, const string& path, git_blob *blob) {
        size_t len = git_blob_rawsize(blob);
        const char *p = static_cast<const char*>(git_blob_rawcontent(blob));
        const char *end = p + len;
        const char *f;
        search_file *sf = new search_file;
        sf->path = path;
        sf->ref = ref;
        git_oid_cpy(&sf->oid, git_object_id(reinterpret_cast<git_object*>(blob)));
        chunk *c;
        StringPiece line;

        while ((f = static_cast<const char*>(memchr(p, '\n', end - p))) != 0) {
            string_hash::iterator it = lines_.find(StringPiece(p, f - p));
            if (it == lines_.end()) {
                stats_.dedup_bytes += (f - p) + 1;
                stats_.dedup_lines ++;

                // Include the trailing '\n' in the chunk buffer
                char *alloc = alloc_.alloc(f - p + 1);
                memcpy(alloc, p, f - p + 1);
                line = StringPiece(alloc, f - p);
                lines_.insert(line);
                c = alloc_.current_chunk();
            } else {
                line = *it;
                c = chunk::from_str(line.data());
            }
            c->add_chunk_file(sf, line);
            p = f + 1;
            stats_.lines++;
        }

        for (list<chunk*>::iterator it = alloc_.begin();
             it != alloc_.end(); it++)
            (*it)->finish_file();

        stats_.bytes += len;
    }

    void resolve_ref(smart_object<git_commit> &out, const char *refname) {
        git_reference *ref;
        const git_oid *oid;
        git_oid tmp;
        smart_object<git_object> obj;
        if (git_oid_fromstr(&tmp, refname) == GIT_SUCCESS) {
            git_object_lookup(obj, repo_, &tmp, GIT_OBJ_ANY);
        } else {
            git_reference_lookup(&ref, repo_, refname);
            git_reference_resolve(&ref, ref);
            oid = git_reference_oid(ref);
            git_object_lookup(obj, repo_, oid, GIT_OBJ_ANY);
        }
        if (git_object_type(obj) == GIT_OBJ_TAG) {
            git_tag_target(out, obj);
        } else {
            out = obj.release();
        }
    }

    mutex repo_lock_;
    git_repository *repo_;
    string_hash lines_;
    struct {
        unsigned long bytes, dedup_bytes;
        unsigned long lines, dedup_lines;
    } stats_;
    chunk_allocator alloc_;

    friend class searcher;
};

int searcher::try_match(const StringPiece &line, search_file *sf) {
    smart_object<git_blob> blob;
    mutex_locker locked(cc_->repo_lock_);
    git_blob_lookup(blob, cc_->repo_, &sf->oid);
    int pos;
    StringPiece search(static_cast<const char*>(git_blob_rawcontent(blob)),
                       git_blob_rawsize(blob));
    pos = search.find(line);
    if (pos == StringPiece::npos) {
        return 0;
    }
    return 1 + count(search.data(), search.data() + pos, '\n');
}

int main(int argc, char **argv) {
    git_repository *repo;
    git_repository_open(&repo, ".git");

    code_counter counter(repo);

    for (int i = 1; i < argc; i++) {
        timer tm;
        struct timeval elapsed;
        printf("Walking %s...", argv[i]);
        fflush(stdout);
        counter.walk_ref(argv[i]);
        elapsed = tm.elapsed();
        printf(" done in %d.%06ds\n",
               (int)elapsed.tv_sec, (int)elapsed.tv_usec);
    }
    counter.dump_stats();
    RE2::Options opts;
    opts.set_never_nl(true);
    opts.set_one_line(false);
    opts.set_perl_classes(true);
    opts.set_posix_syntax(true);
    while (true) {
        printf("regex> ");
        string line;
        getline(cin, line);
        if (cin.eof())
            break;
        RE2 re(line, opts);
        if (re.ok()) {
            timer tm;
            struct timeval elapsed;
            if (!counter.match(re)) {
                printf("no match\n");
            }
            elapsed = tm.elapsed();
            printf("Match completed in %d.%06ds.\n",
                   (int)elapsed.tv_sec, (int)elapsed.tv_usec);
        }
    }

    return 0;
}
<|endoftext|>


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

#include <activemq/ActiveMQTextMessage.h>
#include <cms/TopicConnectionFactory.h>
#include <cms/TopicConnection.h>
#include <cms/TopicSession.h>
#include <cms/TopicSubscriber.h>
#include <cms/Topic.h>
#include <activemq/ActiveMQConnectionFactory.h>
#include <cms/MessageListener.h>
#include <cms/ExceptionListener.h>
#include <cms/TopicPublisher.h>

#include <stdlib.h>
#include <sys/time.h>
#include <iostream>

using namespace std;

class Tester
:
    public cms::ExceptionListener,
    public cms::MessageListener
{
public:

    Tester(){numReceived = 0;}
    virtual ~Tester(){}

    void test(){

        try{

        	int numMessages = 1000;
        	int sleepTime = 10;

        	printf("Starting activemqcms test (sending %d messages and sleeping %d seconds) ...\n", numMessages, sleepTime );

            // START SNIPPET: demo
            cms::TopicConnectionFactory* connectionFactory = new activemq::ActiveMQConnectionFactory( "127.0.0.1:61626" );
            cms::TopicConnection* connection = connectionFactory->createTopicConnection();
            connection->setExceptionListener( this );
            connection->start();
            cms::TopicSession* session = connection->createTopicSession( false );
            cms::Topic* topic = session->createTopic("mytopic");
            cms::TopicSubscriber* subscriber = session->createSubscriber( topic );
            subscriber->setMessageListener( this );
            cms::TopicPublisher* publisher = session->createPublisher( topic );

            const char* text = "this is a test!";
            cms::TextMessage* msg = session->createTextMessage( text );

            for( int ix=0; ix<numMessages; ++ix ){
                publisher->publish( msg );
                doSleep();
            }
            // END SNIPPET: demo

            sleep( sleepTime );

            printf("received: %d\n", numReceived );

            delete publisher;
            subscriber->close();
            delete subscriber;
            session->close();
            delete session;
            connection->close();
            delete connection;
            delete connectionFactory;

        }catch( cms::CMSException& ex ){
            printf("StompTester::test() - %s\n", ex.getMessage() );
        }
    }

    virtual void onMessage( const cms::Message* message ){
        const cms::TextMessage* txtMsg = dynamic_cast<const cms::TextMessage*>(message);
        if( txtMsg == NULL ){
            printf("received non-text message\n" );
            return;
        }

        numReceived++;
        //printf( "[%d]: %s\n", ++ix, txtMsg->getMessage() );
    }

    virtual void onException( const cms::CMSException* error ){
        printf( "StompTester::onException() - %s\n", error->getMessage() );
    }

    virtual void doSleep() {
        timespec sleepTime;
        sleepTime.tv_sec = 0;
        sleepTime.tv_nsec = 1000;
        nanosleep( &sleepTime, &sleepTime );
    }

private:

    int numReceived;
};

int main(int argc, char *argv[]){
	try{

        Tester tester;
        tester.test();

	}catch( ... ){
		printf("main - caught unknown exception\n" );
	}

	printf("done");

    cout.flush();

	return 0;
}

<commit_msg>Fixed handling of bytes message for Jira issue AMQ-685<commit_after>/*
 * Copyright 2006 The Apache Software Foundation or its licensors, as
 * applicable.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <activemq/ActiveMQTextMessage.h>
#include <activemq/ActiveMQBytesMessage.h>
#include <cms/TopicConnectionFactory.h>
#include <cms/TopicConnection.h>
#include <cms/TopicSession.h>
#include <cms/TopicSubscriber.h>
#include <cms/Topic.h>
#include <activemq/ActiveMQConnectionFactory.h>
#include <cms/MessageListener.h>
#include <cms/ExceptionListener.h>
#include <cms/TopicPublisher.h>

#include <stdlib.h>
#include <sys/time.h>
#include <iostream>

using namespace std;

class Tester
:
    public cms::ExceptionListener,
    public cms::MessageListener
{
public:

    Tester(){numReceived = 0;}
    virtual ~Tester(){}

    void test(){

        try{

        	int messagesPerType = 3000;
        	int sleepTime = 2;

        	printf("Starting activemqcms test (sending %d messages per type and sleeping %d seconds) ...\n", messagesPerType, sleepTime );

            // START SNIPPET: demo
            cms::TopicConnectionFactory* connectionFactory = new activemq::ActiveMQConnectionFactory( "127.0.0.1:61613" );
            cms::TopicConnection* connection = connectionFactory->createTopicConnection();
            connection->setExceptionListener( this );
            connection->start();
            cms::TopicSession* session = connection->createTopicSession( false );
            cms::Topic* topic = session->createTopic("mytopic");
            cms::TopicSubscriber* subscriber = session->createSubscriber( topic );
            subscriber->setMessageListener( this );
            cms::TopicPublisher* publisher = session->createPublisher( topic );

            // Send some text messages.
            const char* text = "this is a test!";
            cms::TextMessage* textMsg = session->createTextMessage( text );
            for( int ix=0; ix<messagesPerType; ++ix ){
                publisher->publish( textMsg );
                doSleep();
            }

            // Send some bytes messages.
            char buf[10];
            memset( buf, 0, 10 );
            buf[0] = 0;
            buf[1] = 1;
            buf[2] = 2;
            buf[3] = 3;
            buf[4] = 0;
            buf[5] = 4;
            buf[6] = 5;
            buf[7] = 6;
            cms::BytesMessage* bytesMsg = session->createBytesMessage();
            bytesMsg->setData( buf, 10 );
            for( int ix=0; ix<messagesPerType; ++ix ){
                publisher->publish( bytesMsg );
                doSleep();
            }
            // END SNIPPET: demo

            sleep( sleepTime );

            printf("received: %d\n", numReceived );

            sleep( 5 );

            printf("unsubscribing\n" );
            delete publisher;
            subscriber->close();
            delete subscriber;

            sleep( 5 );

            session->close();
            delete session;
            connection->close();
            delete connection;
            delete connectionFactory;

        }catch( cms::CMSException& ex ){
            printf("StompTester::test() - %s\n", ex.getMessage() );
        }
    }

    virtual void onMessage( const cms::Message* message ){

        // Got a text message.
        const cms::TextMessage* txtMsg = dynamic_cast<const cms::TextMessage*>(message);
        if( txtMsg != NULL ){
            //printf("received text msg: %s\n", txtMsg->getText() );
        }

        // Got a bytes msg.
        const cms::BytesMessage* bytesMsg = dynamic_cast<const cms::BytesMessage*>(message);
        if( bytesMsg != NULL ){
            /*printf("received bytes msg: " );
            const char* bytes = bytesMsg->getData();
            int numBytes = bytesMsg->getNumBytes();
            for( int ix=0; ix<numBytes; ++ix ){
            	printf("[%d]", bytes[ix] );
            }
            printf("\n");*/
        }

        numReceived++;
    }

    virtual void onException( const cms::CMSException* error ){
        printf( "StompTester::onException() - %s\n", error->getMessage() );
    }

    virtual void doSleep() {
        timespec sleepTime;
        sleepTime.tv_sec = 0;
        sleepTime.tv_nsec = 1000;
        nanosleep( &sleepTime, &sleepTime );
    }

private:

    int numReceived;
};

int main(int argc, char *argv[]){
	try{

        Tester tester;
        tester.test();

	}catch( ... ){
		printf("main - caught unknown exception\n" );
	}

	printf("done");

    cout.flush();

	return 0;
}

<|endoftext|>


<commit_before>// fdrawcmd.sys real device wrapper:
//  http://simonowen.com/fdrawcmd/

#include "SAMdisk.h"
#include "DemandDisk.h"
#include "IBMPC.h"
#include "FdrawcmdSys.h"

#ifdef HAVE_FDRAWCMD_H
#include "fdrawcmd.h"

class FdrawSysDevDisk final : public DemandDisk
{
public:
	FdrawSysDevDisk(const std::string &path, std::unique_ptr<FdrawcmdSys> fdrawcmd)
		: m_fdrawcmd(std::move(fdrawcmd))
	{
		try
		{
			SetMetadata(path);

			m_fdrawcmd->SetMotorTimeout(0);
			m_fdrawcmd->Recalibrate();

			if (!opt.newdrive)
				m_fdrawcmd->SetDiskCheck(false);
		}
		catch (...)
		{
			throw util::exception("failed to initialise fdrawcmd.sys device");
		}
	}

protected:
	TrackData load(const CylHead &cylhead, bool /*first_read*/) override
	{
		m_fdrawcmd->Seek(cylhead.cyl);

		auto firstSectorSeen{0};
		auto track = BlindReadHeaders(cylhead, firstSectorSeen);

		int i;
		for (i = 0; !g_fAbort && i < track.size(); i += 2)
			ReadSector(cylhead, track, i, firstSectorSeen);
		for (i = 1 ; !g_fAbort && i < track.size(); i += 2)
			ReadSector(cylhead, track, i, firstSectorSeen);

		return TrackData(cylhead, std::move(track));
	}

	bool preload(const Range &/*range*/) override
	{
		return false;
	}

private:
	void SetMetadata(const std::string &path);
	bool DetectEncodingAndDataRate(int head);
	Track BlindReadHeaders(const CylHead &cylhead, int &firstSectorSeen);
	void ReadSector(const CylHead &cylhead, Track &track, int index, int firstSectorSeen=0);

	std::unique_ptr<FdrawcmdSys> m_fdrawcmd;
	Encoding m_lastEncoding{Encoding::Unknown};
	DataRate m_lastDataRate{DataRate::Unknown};
	bool m_warnedMFM128{false};
};

void FdrawSysDevDisk::SetMetadata(const std::string &path)
{
	auto device_path = R"(\\.\)" + path;
	Win32Handle hdev{
		CreateFile(device_path.c_str(), 0, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, NULL) };

	if (hdev.get() != INVALID_HANDLE_VALUE)
	{
		DWORD dwRet = 0;
		DISK_GEOMETRY dg[8]{};
		if (DeviceIoControl(hdev.get(), IOCTL_STORAGE_GET_MEDIA_TYPES,
			nullptr, 0, &dg, sizeof(dg), &dwRet, NULL) && dwRet > sizeof(DISK_GEOMETRY))
		{
			auto count = dwRet / sizeof(dg[0]);
			metadata["bios_type"] = to_string(dg[count - 1].MediaType);
		}
	}

	FD_FDC_INFO info{};
	if (m_fdrawcmd->GetFdcInfo(info))
	{
		static const std::vector<std::string> fdc_types{
			"Unknown", "Unknown1", "Normal", "Enhanced", "82077", "82077AA", "82078_44", "82078_64", "National" };
		static const std::vector<std::string> data_rates{
			"250K", "300K", "500K", "1M", "2M" };

		std::stringstream ss;
		for (size_t i = 0, n = 0; i < data_rates.size(); ++i)
		{
			if (!(info.SpeedsAvailable & (1U << i)))
				continue;

			if (n++) ss << " / ";
			ss << data_rates[i];
		}

		metadata["fdc_type"] = (info.ControllerType < fdc_types.size()) ? fdc_types[info.ControllerType] : "???";
		metadata["data_rates"] = ss.str();
	}
}

// Detect encoding and data rate of the track under the given drive head.
bool FdrawSysDevDisk::DetectEncodingAndDataRate(int head)
{
	FD_CMD_RESULT result{};

	if (m_lastEncoding != Encoding::Unknown && m_lastDataRate != DataRate::Unknown)
	{
		// Try the last successful encoding and data rate.
		m_fdrawcmd->SetEncRate(m_lastEncoding, m_lastDataRate);

		// Return if we found a sector.
		if (m_fdrawcmd->CmdReadId(head, result))
			return true;
	}

	for (auto encoding : {Encoding::MFM, Encoding::FM})
	{
		for (auto datarate : {DataRate::_1M, DataRate::_500K, DataRate::_300K, DataRate::_250K})
		{
			// Skip FM if disabled or the data rate is 1Mbps (not worth checking).
			if (encoding == Encoding::FM && (opt.fm == 0 || datarate == DataRate::_1M))
				continue;

			// Skip rates not matching user selection (note: legacy values!)
			static const std::array<DataRate, 4> rates{DataRate::_500K, DataRate::_300K, DataRate::_250K, DataRate::_1M};
			if (opt.rate >= 0 && opt.rate < static_cast<int>(rates.size()) && datarate != rates[opt.rate])
				continue;

			// Skip 1Mbps if the FDC doesn't report it's supported.
			if (datarate == DataRate::_1M)
			{
				FD_FDC_INFO fi{};
				if (!m_fdrawcmd->GetFdcInfo(fi) || !(fi.SpeedsAvailable & FDC_SPEED_1M))
				{
					// Fail if user selected the rate.
					if (opt.rate != -1)
						throw util::exception("FDC doesn't support 1Mbps data rate");

					continue;
				}
			}

			m_fdrawcmd->SetEncRate(encoding, datarate);

			// Retry in case of spurious header CRC errors.
			for (auto i = 0; i <= opt.retries; ++i)
			{
				if (m_fdrawcmd->CmdReadId(head, result))
				{
					// Remember the settings for the first try next time.
					m_lastEncoding = encoding;
					m_lastDataRate = datarate;
					return true;
				}

				// Give up on the current settings if nothing was found.
				if (GetLastError() == ERROR_FLOPPY_ID_MARK_NOT_FOUND ||
					GetLastError() == ERROR_SECTOR_NOT_FOUND)
					break;

				// Fail for any reason except a CRC error
				if (GetLastError() != ERROR_CRC)
					throw win32_error(GetLastError(), "READ_ID");
			}
		}
	}

	// Nothing detected.
	return false;
}

Track FdrawSysDevDisk::BlindReadHeaders(const CylHead &cylhead, int &firstSectorSeen)
{
	Track track;

	auto scan_size = sizeof(FD_TIMED_SCAN_RESULT) + sizeof(FD_TIMED_ID_HEADER) * MAX_SECTORS;
	MEMORY mem(scan_size);
	auto scan_result = reinterpret_cast<FD_TIMED_SCAN_RESULT *>(mem.pb);

	if (m_lastEncoding == Encoding::Unknown || m_lastDataRate == DataRate::Unknown)
		DetectEncodingAndDataRate(cylhead.head);

	if (!m_fdrawcmd->CmdTimedScan(cylhead.head, scan_result, scan_size))
		throw win32_error(GetLastError(), "scan");

	// If nothing was found and we have valid settings, they might have changed.
	if (!scan_result->count && m_lastEncoding != Encoding::Unknown)
	{
		DetectEncodingAndDataRate(cylhead.head);

		if (!m_fdrawcmd->CmdTimedScan(cylhead.head, scan_result, scan_size))
			throw win32_error(GetLastError(), "scan");
	}

	// If the track time is slower than 200rpm, an index-halving cable must be present
	if (scan_result->tracktime > RPM_TIME_200)
		throw util::exception("index-halving cables are no longer supported");

	firstSectorSeen = scan_result->firstseen;

	auto bit_us{GetDataTime(m_lastDataRate, m_lastEncoding) / 16};
	track.tracktime = scan_result->tracktime;
	track.tracklen = track.tracktime / bit_us;

	for (int i = 0; i < scan_result->count; ++i)
	{
		const auto &scan_header{scan_result->Header[i]};
		Header header(scan_header.cyl, scan_header.head, scan_header.sector, scan_header.size);
		Sector sector(m_lastDataRate, m_lastEncoding, header);

		sector.offset = scan_header.reltime / bit_us;
		track.add(std::move(sector));
	}

	return track;
}

void FdrawSysDevDisk::ReadSector(const CylHead &cylhead, Track &track, int index, int firstSectorSeen)
{
	auto &sector = track[index];

	if (sector.has_badidcrc() || sector.has_good_data())
		return;

	auto size = sector.SizeCodeToLength(sector.SizeCodeToRealSizeCode(sector.header.size));
	MEMORY mem(size);

	for (int i = 0; !g_fAbort && i <= opt.retries; ++i)
	{
		// If the sector id occurs more than once on the track, synchronise to the correct one
		if (track.is_repeated(sector))
		{
			auto offset{(index + track.size() - firstSectorSeen) % track.size()};
			m_fdrawcmd->FdSetSectorOffset(offset);
		}

		// Invalidate the content so misbehaving FDCs can be identififed.
		memset(mem.pb, 0xee, mem.size);

		const Header &header = sector.header;
		if (!m_fdrawcmd->CmdRead(cylhead.head, header.cyl, header.head, header.sector, header.size, 1, mem))
		{
			// Reject errors other than CRC, sector not found and missing address marks
			auto error{GetLastError()};
			if (error != ERROR_CRC &&
				error != ERROR_SECTOR_NOT_FOUND &&
				error != ERROR_FLOPPY_ID_MARK_NOT_FOUND)
			{
				throw win32_error(error, "read");
			}
		}

		// Get the controller result for the read to find out more
		FD_CMD_RESULT result{};
		if (!m_fdrawcmd->GetResult(result))
			throw win32_error(GetLastError(), "result");

		// Try again if header or data field are missing.
		if ((result.st1 & STREG1_MISSING_ADDRESS_MARK) || (result.st1 & STREG1_NO_DATA))
			continue;

		// Header match not found for a sector we scanned earlier?
		if (result.st1 & STREG1_END_OF_CYLINDER)
		{
			// Warn the user if we suspect the FDC can't handle 128-byte MFM sectors.
			if (!m_warnedMFM128 && sector.encoding == Encoding::MFM && sector.size() == 128)
			{
				Message(msgWarning, "FDC seems unable to read 128-byte sectors correctly");
				m_warnedMFM128 = true;
			}
			continue;
		}

		bool data_crc_error{ (result.st2 & STREG2_DATA_ERROR_IN_DATA_FIELD) != 0 };
		uint8_t dam = (result.st2 & STREG2_CONTROL_MARK) ? 0xf8 : 0xfb;

		Data data(mem.pb, mem.pb + mem.size);
		sector.add(std::move(data), data_crc_error, dam);

		// If the read command was successful we're all done.
		if ((result.st0 & STREG0_INTERRUPT_CODE) == 0)
			break;

		// Accept sectors that overlap the next field, as they're unlikely to succeed.
		if (track.data_overlap(sector))
			break;

		// Accept 8K sectors with a recognised checksum method.
		if (track.is_8k_sector())
		{
			// If the 8K checksum is recognised we're done.
			auto chk8k_method = Get8KChecksumMethod(mem.pb, size);
			if (chk8k_method == CHK8K_VALID || chk8k_method >= CHK8K_FOUND)
				break;
		}
	}
}

bool ReadFdrawSysDev(const std::string &path, std::shared_ptr<Disk> &disk)
{
	auto devidx = (util::lowercase(path) == "b:") ? 1 : 0;
	auto fdrawcmd = FdrawcmdSys::Open(devidx);
	if (!fdrawcmd)
		throw util::exception("failed to open fdrawcmd.sys device");

	auto fdrawcmd_dev_disk = std::make_shared<FdrawSysDevDisk>(path, std::move(fdrawcmd));
	fdrawcmd_dev_disk->extend(CylHead(83 - 1, 2 - 1));

	fdrawcmd_dev_disk->strType = "fdrawcmd.sys";
	disk = fdrawcmd_dev_disk;

	return true;
}

#endif // HAVE_FDRAWCMD_H
<commit_msg>Add fdrawcmd.sys support for gap data reading<commit_after>// fdrawcmd.sys real device wrapper:
//  http://simonowen.com/fdrawcmd/

#include "SAMdisk.h"
#include "DemandDisk.h"
#include "IBMPC.h"
#include "FdrawcmdSys.h"

#ifdef HAVE_FDRAWCMD_H
#include "fdrawcmd.h"

class FdrawSysDevDisk final : public DemandDisk
{
public:
	FdrawSysDevDisk(const std::string &path, std::unique_ptr<FdrawcmdSys> fdrawcmd)
		: m_fdrawcmd(std::move(fdrawcmd))
	{
		try
		{
			SetMetadata(path);

			m_fdrawcmd->SetMotorTimeout(0);
			m_fdrawcmd->Recalibrate();

			if (!opt.newdrive)
				m_fdrawcmd->SetDiskCheck(false);
		}
		catch (...)
		{
			throw util::exception("failed to initialise fdrawcmd.sys device");
		}
	}

protected:
	TrackData load(const CylHead &cylhead, bool /*first_read*/) override
	{
		m_fdrawcmd->Seek(cylhead.cyl);

		auto firstSectorSeen{0};
		auto track = BlindReadHeaders(cylhead, firstSectorSeen);

		int i;
		for (i = 0; !g_fAbort && i < track.size(); i += 2)
			ReadSector(cylhead, track, i, firstSectorSeen);
		for (i = 1 ; !g_fAbort && i < track.size(); i += 2)
			ReadSector(cylhead, track, i, firstSectorSeen);

		if (opt.gaps >= GAPS_CLEAN)
			ReadFirstGap(cylhead, track);

		return TrackData(cylhead, std::move(track));
	}

	bool preload(const Range &/*range*/) override
	{
		return false;
	}

private:
	void SetMetadata(const std::string &path);
	bool DetectEncodingAndDataRate(int head);
	Track BlindReadHeaders(const CylHead &cylhead, int &firstSectorSeen);
	void ReadSector(const CylHead &cylhead, Track &track, int index, int firstSectorSeen=0);
	void ReadFirstGap(const CylHead &cylhead, Track &track);

	std::unique_ptr<FdrawcmdSys> m_fdrawcmd;
	Encoding m_lastEncoding{Encoding::Unknown};
	DataRate m_lastDataRate{DataRate::Unknown};
	bool m_warnedMFM128{false};
};

void FdrawSysDevDisk::SetMetadata(const std::string &path)
{
	auto device_path = R"(\\.\)" + path;
	Win32Handle hdev{
		CreateFile(device_path.c_str(), 0, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, NULL) };

	if (hdev.get() != INVALID_HANDLE_VALUE)
	{
		DWORD dwRet = 0;
		DISK_GEOMETRY dg[8]{};
		if (DeviceIoControl(hdev.get(), IOCTL_STORAGE_GET_MEDIA_TYPES,
			nullptr, 0, &dg, sizeof(dg), &dwRet, NULL) && dwRet > sizeof(DISK_GEOMETRY))
		{
			auto count = dwRet / sizeof(dg[0]);
			metadata["bios_type"] = to_string(dg[count - 1].MediaType);
		}
	}

	FD_FDC_INFO info{};
	if (m_fdrawcmd->GetFdcInfo(info))
	{
		static const std::vector<std::string> fdc_types{
			"Unknown", "Unknown1", "Normal", "Enhanced", "82077", "82077AA", "82078_44", "82078_64", "National" };
		static const std::vector<std::string> data_rates{
			"250K", "300K", "500K", "1M", "2M" };

		std::stringstream ss;
		for (size_t i = 0, n = 0; i < data_rates.size(); ++i)
		{
			if (!(info.SpeedsAvailable & (1U << i)))
				continue;

			if (n++) ss << " / ";
			ss << data_rates[i];
		}

		metadata["fdc_type"] = (info.ControllerType < fdc_types.size()) ? fdc_types[info.ControllerType] : "???";
		metadata["data_rates"] = ss.str();
	}
}

// Detect encoding and data rate of the track under the given drive head.
bool FdrawSysDevDisk::DetectEncodingAndDataRate(int head)
{
	FD_CMD_RESULT result{};

	if (m_lastEncoding != Encoding::Unknown && m_lastDataRate != DataRate::Unknown)
	{
		// Try the last successful encoding and data rate.
		m_fdrawcmd->SetEncRate(m_lastEncoding, m_lastDataRate);

		// Return if we found a sector.
		if (m_fdrawcmd->CmdReadId(head, result))
			return true;
	}

	for (auto encoding : {Encoding::MFM, Encoding::FM})
	{
		for (auto datarate : {DataRate::_1M, DataRate::_500K, DataRate::_300K, DataRate::_250K})
		{
			// Skip FM if disabled or the data rate is 1Mbps (not worth checking).
			if (encoding == Encoding::FM && (opt.fm == 0 || datarate == DataRate::_1M))
				continue;

			// Skip rates not matching user selection (note: legacy values!)
			static const std::array<DataRate, 4> rates{DataRate::_500K, DataRate::_300K, DataRate::_250K, DataRate::_1M};
			if (opt.rate >= 0 && opt.rate < static_cast<int>(rates.size()) && datarate != rates[opt.rate])
				continue;

			// Skip 1Mbps if the FDC doesn't report it's supported.
			if (datarate == DataRate::_1M)
			{
				FD_FDC_INFO fi{};
				if (!m_fdrawcmd->GetFdcInfo(fi) || !(fi.SpeedsAvailable & FDC_SPEED_1M))
				{
					// Fail if user selected the rate.
					if (opt.rate != -1)
						throw util::exception("FDC doesn't support 1Mbps data rate");

					continue;
				}
			}

			m_fdrawcmd->SetEncRate(encoding, datarate);

			// Retry in case of spurious header CRC errors.
			for (auto i = 0; i <= opt.retries; ++i)
			{
				if (m_fdrawcmd->CmdReadId(head, result))
				{
					// Remember the settings for the first try next time.
					m_lastEncoding = encoding;
					m_lastDataRate = datarate;
					return true;
				}

				// Give up on the current settings if nothing was found.
				if (GetLastError() == ERROR_FLOPPY_ID_MARK_NOT_FOUND ||
					GetLastError() == ERROR_SECTOR_NOT_FOUND)
					break;

				// Fail for any reason except a CRC error
				if (GetLastError() != ERROR_CRC)
					throw win32_error(GetLastError(), "READ_ID");
			}
		}
	}

	// Nothing detected.
	return false;
}

Track FdrawSysDevDisk::BlindReadHeaders(const CylHead &cylhead, int &firstSectorSeen)
{
	Track track;

	auto scan_size = sizeof(FD_TIMED_SCAN_RESULT) + sizeof(FD_TIMED_ID_HEADER) * MAX_SECTORS;
	MEMORY mem(scan_size);
	auto scan_result = reinterpret_cast<FD_TIMED_SCAN_RESULT *>(mem.pb);

	if (m_lastEncoding == Encoding::Unknown || m_lastDataRate == DataRate::Unknown)
		DetectEncodingAndDataRate(cylhead.head);

	if (!m_fdrawcmd->CmdTimedScan(cylhead.head, scan_result, scan_size))
		throw win32_error(GetLastError(), "scan");

	// If nothing was found and we have valid settings, they might have changed.
	if (!scan_result->count && m_lastEncoding != Encoding::Unknown)
	{
		DetectEncodingAndDataRate(cylhead.head);

		if (!m_fdrawcmd->CmdTimedScan(cylhead.head, scan_result, scan_size))
			throw win32_error(GetLastError(), "scan");
	}

	// If the track time is slower than 200rpm, an index-halving cable must be present
	if (scan_result->tracktime > RPM_TIME_200)
		throw util::exception("index-halving cables are no longer supported");

	firstSectorSeen = scan_result->firstseen;

	auto bit_us{GetDataTime(m_lastDataRate, m_lastEncoding) / 16};
	track.tracktime = scan_result->tracktime;
	track.tracklen = track.tracktime / bit_us;

	for (int i = 0; i < scan_result->count; ++i)
	{
		const auto &scan_header{scan_result->Header[i]};
		Header header(scan_header.cyl, scan_header.head, scan_header.sector, scan_header.size);
		Sector sector(m_lastDataRate, m_lastEncoding, header);

		sector.offset = scan_header.reltime / bit_us;
		track.add(std::move(sector));
	}

	return track;
}

void FdrawSysDevDisk::ReadSector(const CylHead &cylhead, Track &track, int index, int firstSectorSeen)
{
	auto &sector = track[index];

	if (sector.has_badidcrc() || sector.has_good_data())
		return;

	auto size = sector.SizeCodeToLength(sector.SizeCodeToRealSizeCode(sector.header.size));
	MEMORY mem(size);

	for (int i = 0; !g_fAbort && i <= opt.retries; ++i)
	{
		// If the sector id occurs more than once on the track, synchronise to the correct one
		if (track.is_repeated(sector))
		{
			auto offset{(index + track.size() - firstSectorSeen) % track.size()};
			m_fdrawcmd->FdSetSectorOffset(offset);
		}

		// Invalidate the content so misbehaving FDCs can be identififed.
		memset(mem.pb, 0xee, mem.size);

		const Header &header = sector.header;
		if (!m_fdrawcmd->CmdRead(cylhead.head, header.cyl, header.head, header.sector, header.size, 1, mem))
		{
			// Reject errors other than CRC, sector not found and missing address marks
			auto error{GetLastError()};
			if (error != ERROR_CRC &&
				error != ERROR_SECTOR_NOT_FOUND &&
				error != ERROR_FLOPPY_ID_MARK_NOT_FOUND)
			{
				throw win32_error(error, "read");
			}
		}

		// Get the controller result for the read to find out more
		FD_CMD_RESULT result{};
		if (!m_fdrawcmd->GetResult(result))
			throw win32_error(GetLastError(), "result");

		// Try again if header or data field are missing.
		if (result.st1 & (STREG1_MISSING_ADDRESS_MARK | STREG1_NO_DATA))
			continue;

		// Header match not found for a sector we scanned earlier?
		if (result.st1 & STREG1_END_OF_CYLINDER)
		{
			// Warn the user if we suspect the FDC can't handle 128-byte MFM sectors.
			if (!m_warnedMFM128 && sector.encoding == Encoding::MFM && sector.size() == 128)
			{
				Message(msgWarning, "FDC seems unable to read 128-byte sectors correctly");
				m_warnedMFM128 = true;
			}
			continue;
		}

		bool data_crc_error{ (result.st2 & STREG2_DATA_ERROR_IN_DATA_FIELD) != 0 };
		uint8_t dam = (result.st2 & STREG2_CONTROL_MARK) ? 0xf8 : 0xfb;

		Data data(mem.pb, mem.pb + mem.size);
		sector.add(std::move(data), data_crc_error, dam);

		// If the read command was successful we're all done.
		if ((result.st0 & STREG0_INTERRUPT_CODE) == 0)
			break;

		// Accept sectors that overlap the next field, as they're unlikely to succeed.
		if (track.data_overlap(sector))
			break;

		// Accept 8K sectors with a recognised checksum method.
		if (track.is_8k_sector())
		{
			// If the 8K checksum is recognised we're done.
			auto chk8k_method = Get8KChecksumMethod(mem.pb, size);
			if (chk8k_method == CHK8K_VALID || chk8k_method >= CHK8K_FOUND)
				break;
		}
	}
}

void FdrawSysDevDisk::ReadFirstGap(const CylHead &cylhead, Track &track)
{
	if (track.empty())
		return;

	auto &sector = track[0];

	if (sector.has_badidcrc() || track.data_overlap(sector))
		return;

	// Read a size
	auto size_code = sector.header.size + 1;
	auto size = sector.SizeCodeToLength(sector.SizeCodeToRealSizeCode(size_code));
	MEMORY mem(size);

	for (int i = 0; !g_fAbort && i <= opt.retries; ++i)
	{
		// Invalidate the content so misbehaving FDCs can be identififed.
		memset(mem.pb, 0xee, mem.size);

		if (!m_fdrawcmd->CmdReadTrack(cylhead.head, 0, 0, 0, size_code, 1, mem))
		{
			// Reject errors other than CRC, sector not found and missing address marks
			auto error{ GetLastError() };
			if (error != ERROR_CRC &&
				error != ERROR_SECTOR_NOT_FOUND &&
				error != ERROR_FLOPPY_ID_MARK_NOT_FOUND)
			{
				throw win32_error(error, "read_track");
			}
		}

		FD_CMD_RESULT result{};
		if (!m_fdrawcmd->GetResult(result))
			throw win32_error(GetLastError(), "result");

		if (result.st1 & (STREG1_MISSING_ADDRESS_MARK | STREG1_END_OF_CYLINDER))
			continue;
		else if (result.st2 & STREG2_MISSING_ADDRESS_MARK_IN_DATA_FIELD)
			continue;

		// Sanity check the start of the track against a good copy.
		if (sector.has_good_data())
		{
			const auto data = sector.data_copy();
			if (std::memcmp(data.data(), mem.pb, data.size()))
			{
				Message(msgWarning, "track read of %s doesn't match first sector content", CH(cylhead.cyl, cylhead.head));
				break;
			}
		}

		auto extent = track.data_extent_bytes(sector);
		sector.add(Data(mem.pb, mem.pb + extent), sector.has_baddatacrc(), sector.dam);
		break;
	}
}

bool ReadFdrawSysDev(const std::string &path, std::shared_ptr<Disk> &disk)
{
	auto devidx = (util::lowercase(path) == "b:") ? 1 : 0;
	auto fdrawcmd = FdrawcmdSys::Open(devidx);
	if (!fdrawcmd)
		throw util::exception("failed to open fdrawcmd.sys device");

	auto fdrawcmd_dev_disk = std::make_shared<FdrawSysDevDisk>(path, std::move(fdrawcmd));
	fdrawcmd_dev_disk->extend(CylHead(83 - 1, 2 - 1));

	fdrawcmd_dev_disk->strType = "fdrawcmd.sys";
	disk = fdrawcmd_dev_disk;

	return true;
}

#endif // HAVE_FDRAWCMD_H
<|endoftext|>


<commit_before>#include "intent_contextualization_system.h"
#include "game/messages/intent_message.h"

#include "game/components/car_component.h"
#include "game/components/driver_component.h"
#include "game/components/gun_component.h"
#include "game/components/container_component.h"
#include "game/components/trigger_query_detector_component.h"
#include "game/components/melee_component.h"
#include "game/components/trigger_collision_detector_component.h"

#include "game/transcendental/cosmos.h"
#include "game/transcendental/entity_id.h"

#include "game/detail/inventory_slot_id.h"
#include "game/detail/inventory_slot_handle.h"

#include "game/transcendental/entity_handle.h"
#include "game/transcendental/step.h"

using namespace augs;

void intent_contextualization_system::contextualize_use_button_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& intents = step.messages.get_queue<messages::intent_message>();

	for (auto& e : intents) {
		const auto subject = cosmos[e.subject];

		const auto* const query_detector = subject.find<components::trigger_query_detector>();
		const auto* const collision_detector = subject.find<components::trigger_collision_detector>();

		if (e.intent == intent_type::USE_BUTTON) {
			const auto* const maybe_driver = subject.find<components::driver>();

			if (maybe_driver) {
				const auto car_id = maybe_driver->owned_vehicle;
				const auto car = cosmos[car_id];

				if (car.alive() && car.get<components::car>().current_driver == e.subject) {
					e.intent = intent_type::RELEASE_CAR;
					continue;
				}
			}

			if (query_detector) {
				e.intent = intent_type::QUERY_TOUCHING_TRIGGERS;
				continue;
			}
		}
		else if (e.intent == intent_type::START_PICKING_UP_ITEMS) {
			if (collision_detector) {
				e.intent = intent_type::DETECT_TRIGGER_COLLISIONS;
				continue;
			}
		}
	}
}

void intent_contextualization_system::contextualize_crosshair_action_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& events = step.messages.get_queue<messages::intent_message>();

	for (auto& it : events) {
		entity_id callee;

		const auto subject = cosmos[it.subject];

		const auto maybe_crosshair = subject[sub_entity_name::CHARACTER_CROSSHAIR];

		if (it.intent == intent_type::MOVE_CROSSHAIR && maybe_crosshair.alive()) {
			it.subject = maybe_crosshair;
			continue;
		}

		if (subject.has<components::container>()) {
			if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION) {
				const auto hand = subject[slot_function::PRIMARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
			}

			if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION) {
				const auto hand = subject[slot_function::SECONDARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
				else {
					const auto prim_hand = subject[slot_function::PRIMARY_HAND];

					if (prim_hand.alive() && prim_hand->items_inside.size() > 0)
						callee = prim_hand.get_items_inside()[0];
				}
			}
		}

		const auto callee_handle = cosmos[callee];

		if (callee_handle.alive()) {
			if (callee_handle.find<components::gun>()) {
				it.intent = intent_type::PRESS_GUN_TRIGGER;
				it.subject = callee;
				continue;
			}
			if (callee_handle.find<components::melee>()) {
				if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION)
					it.intent = intent_type::MELEE_PRIMARY_MOVE;
				else if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION)
					it.intent = intent_type::MELEE_SECONDARY_MOVE;

				it.subject = callee;
				continue;
			}
		}
	}
}

void intent_contextualization_system::contextualize_movement_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& intents = step.messages.get_queue<messages::intent_message>();

	for (auto& e : intents) {
		entity_id callee;

		const auto subject = cosmos[e.subject];

		const auto* const maybe_driver = subject.find<components::driver>();
		const auto* const maybe_container = subject.find<components::container>();

		if (maybe_driver && cosmos[maybe_driver->owned_vehicle].alive()) {
			if (e.intent == intent_type::MOVE_FORWARD
				|| e.intent == intent_type::MOVE_BACKWARD
				|| e.intent == intent_type::MOVE_LEFT
				|| e.intent == intent_type::MOVE_RIGHT) {
				callee = maybe_driver->owned_vehicle;
			}
			else if (e.intent == intent_type::SPACE_BUTTON) {
				callee = maybe_driver->owned_vehicle;
				e.intent = intent_type::HAND_BRAKE;
			}
		}

		const auto callee_handle = cosmos[callee];

		if (callee_handle.dead()) {
			if (maybe_container) {
				if (e.intent == intent_type::SPACE_BUTTON) {
					const auto hand = subject[slot_function::PRIMARY_HAND];

					if (hand.alive() && hand->items_inside.size() > 0) {
						e.intent = intent_type::MELEE_TERTIARY_MOVE;
						callee = hand.get_items_inside()[0];
					}
				}
			}
		}

		if(callee_handle.alive())
			e.subject = callee;
	}
}
<commit_msg>aesthetics in intent_contextualization_system.cpp<commit_after>#include "intent_contextualization_system.h"
#include "game/messages/intent_message.h"

#include "game/components/car_component.h"
#include "game/components/driver_component.h"
#include "game/components/gun_component.h"
#include "game/components/container_component.h"
#include "game/components/trigger_query_detector_component.h"
#include "game/components/melee_component.h"
#include "game/components/trigger_collision_detector_component.h"

#include "game/transcendental/cosmos.h"
#include "game/transcendental/entity_id.h"

#include "game/detail/inventory_slot_id.h"
#include "game/detail/inventory_slot_handle.h"

#include "game/transcendental/entity_handle.h"
#include "game/transcendental/step.h"

using namespace augs;

void intent_contextualization_system::contextualize_use_button_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& intents = step.messages.get_queue<messages::intent_message>();

	for (auto& e : intents) {
		const auto subject = cosmos[e.subject];

		const auto* const query_detector = subject.find<components::trigger_query_detector>();
		const auto* const collision_detector = subject.find<components::trigger_collision_detector>();

		if (e.intent == intent_type::USE_BUTTON) {
			const auto* const maybe_driver = subject.find<components::driver>();

			if (maybe_driver) {
				const auto car_id = maybe_driver->owned_vehicle;
				const auto car = cosmos[car_id];

				if (car.alive() && car.get<components::car>().current_driver == e.subject) {
					e.intent = intent_type::RELEASE_CAR;
					continue;
				}
			}

			if (query_detector) {
				e.intent = intent_type::QUERY_TOUCHING_TRIGGERS;
				continue;
			}
		}
		else if (e.intent == intent_type::START_PICKING_UP_ITEMS) {
			if (collision_detector) {
				e.intent = intent_type::DETECT_TRIGGER_COLLISIONS;
				continue;
			}
		}
	}
}

void intent_contextualization_system::contextualize_crosshair_action_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& events = step.messages.get_queue<messages::intent_message>();

	for (auto& it : events) {
		entity_id callee;

		const auto subject = cosmos[it.subject];

		const auto maybe_crosshair = subject[sub_entity_name::CHARACTER_CROSSHAIR];

		if (it.intent == intent_type::MOVE_CROSSHAIR && maybe_crosshair.alive()) {
			it.subject = maybe_crosshair;
			continue;
		}

		if (subject.has<components::container>()) {
			if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION) {
				const auto hand = subject[slot_function::PRIMARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
			}

			if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION) {
				const auto hand = subject[slot_function::SECONDARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
				else {
					const auto prim_hand = subject[slot_function::PRIMARY_HAND];

					if (prim_hand.alive() && prim_hand->items_inside.size() > 0)
						callee = prim_hand.get_items_inside()[0];
				}
			}
		}

		const auto callee_handle = cosmos[callee];

		if (callee_handle.alive()) {
			if (callee_handle.find<components::gun>()) {
				it.intent = intent_type::PRESS_GUN_TRIGGER;
				it.subject = callee;
				continue;
			}
			if (callee_handle.find<components::melee>()) {
				if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION)
					it.intent = intent_type::MELEE_PRIMARY_MOVE;
				else if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION)
					it.intent = intent_type::MELEE_SECONDARY_MOVE;

				it.subject = callee;
				continue;
			}
		}
	}
}

void intent_contextualization_system::contextualize_movement_intents(fixed_step& step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& intents = step.messages.get_queue<messages::intent_message>();

	for (auto& e : intents) {
		entity_id callee;
		bool callee_resolved = false;

		const auto subject = cosmos[e.subject];

		const auto* const maybe_driver = subject.find<components::driver>();
		const auto* const maybe_container = subject.find<components::container>();

		if (maybe_driver && cosmos[maybe_driver->owned_vehicle].alive()) {
			if (e.intent == intent_type::MOVE_FORWARD
				|| e.intent == intent_type::MOVE_BACKWARD
				|| e.intent == intent_type::MOVE_LEFT
				|| e.intent == intent_type::MOVE_RIGHT) {
				callee = maybe_driver->owned_vehicle;
				callee_resolved = true;
			}
			else if (e.intent == intent_type::SPACE_BUTTON) {
				callee = maybe_driver->owned_vehicle;
				callee_resolved = true;
				e.intent = intent_type::HAND_BRAKE;
			}
		}

		if (!callee_resolved) {
			if (maybe_container) {
				if (e.intent == intent_type::SPACE_BUTTON) {
					const auto hand = subject[slot_function::PRIMARY_HAND];

					if (hand.alive() && hand->items_inside.size() > 0) {
						e.intent = intent_type::MELEE_TERTIARY_MOVE;
						callee = hand.get_items_inside()[0];
						callee_resolved = true;
					}
				}
			}
		}

		if(callee_resolved)
			e.subject = callee;
	}
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>
#include <typeinfo>

#include "fmt.hh"

// _sfmt fills the passed buffer with the expected format
// _sfmt (base specialization) for a single argument
template <typename T>
int _sfmt(char* buffer, int start, bool ln, T x) {
	auto fmt = _fmt(x);
	std::strcpy(buffer + start, fmt);
	start += strlen(fmt);

	if (ln) {
		std::strcpy(buffer + start, "\n");
		start++;
	}

	return start;
}

// _sfmt fills the passed buffer with the expected format
// _sfmt (variadic specialization) for multiple arguments
// it returns the number of characters written to the passed buffer
template <typename First, typename... Args>
int _sfmt(char* buffer, int start, bool ln, First x, Args... rest) {
	auto fmt = _fmt(x);
	std::strcpy(buffer + start, fmt);
	start += strlen(fmt);

	std::strcpy(buffer + start, " ");
	start++;

	return _sfmt(buffer, start, ln, rest...);
}

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

// _print creates a new buffer for the passed arguments and calls printf
// the first parameter checks whether newline has to be printed at the end or
// not
template <typename... T>
int _print(FILE* stream, bool ln, T... args) {
	int nargs = sizeof...(args);
	int size = nargs * 5 - 1;
	if (ln) size++;
	char buf[size];
	memset(buf, 0, size);

	_sfmt(buf, 0, ln, args...);
	return fprintf(stream, buf, args...);
}

// fprint (empty argument specialization), simply returns 0
int fprint(FILE* stream) { return 0; }

// fprint (variadic arguments specialization) prints without newline at the end
// to the passed stream
template <typename... T>
int fprint(FILE* stream, T... args) {
	return _print(stream, false, args...);
}

// fprintln (empty argument specialization), simply prints a newline
// to the passed stream
int fprintln(FILE* stream) { return fprintf(stream, "\n"); }

// fprintln (variadic arguments specialization) prints with newline at the end
// to the passed stream
template <typename... T>
int fprintln(FILE* stream, T... args) {
	return _print(stream, true, args...);
}

// print (empty argument specialization), simply returns 0
int print() { return 0; }

// print (variadic arguments specialization) prints without newline at the end
template <typename... T>
int print(T... args) {
	return _print(stdout, false, args...);
}

// println (empty argument specialization), simply prints a newline
int println() { return printf("\n"); }

// println (variadic arguments specialization) prints with newline at the end
template <typename... T>
int println(T... args) {
	return _print(stdout, true, args...);
}

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

// scan (empty argument specialization), simply returns 0
int fscan(FILE* stream) { return 0; }

// scan (variadic arguments specialization) creates a format string and then
// scans
// arguments, returning the result of the scanf call
template <typename... T>
int fscan(FILE* stream, T... args) {
	int nargs = sizeof...(args);
	int size = 5 * nargs - 1;

	char buf[size];
	memset(buf, 0, size);

	_sfmt(buf, 0, false, args...);
	return fscanf(stream, buf, args...);
}

void fscanskipln(FILE* stream) {
	while (true) {
		char ch = getc(stream);
		if (ch == EOF || ch == '\n') break;
		// TODO: check if we need
		// https://sourcegraph.com/github.com/golang/go@838eaa738f2bc07c3706b96f9e702cb80877dfe1/-/blob/src/fmt/scan.go#L1058:8
	}
}

// fscanln (empty argument specialization), scans until a newline and returns 0
int fscanln(FILE* stream) {
	fscanskipln(stream);
	return 0;
}

// scanln is scan but will read until a newline or EOF
template <typename... T>
int fscanln(FILE* stream, T... args) {
	int v = fscan(stream, args...);
	fscanskipln(stream);
	return v;
}

int scan() { return 0; }

template <typename... T>
int scan(T... args) {
	return fscan(stdin, args...);
}

int scanln() { return fscanln(stdin); }

template <typename... T>
int scanln(T... args) {
	return fscanln(stdin, args...);
}
<commit_msg>sprint: add include guard<commit_after>#pragma once

#include <cstdio>
#include <cstring>
#include <typeinfo>

#include "fmt.hh"

// _sfmt fills the passed buffer with the expected format
// _sfmt (base specialization) for a single argument
template <typename T>
int _sfmt(char* buffer, int start, bool ln, T x) {
	auto fmt = _fmt(x);
	std::strcpy(buffer + start, fmt);
	start += strlen(fmt);

	if (ln) {
		std::strcpy(buffer + start, "\n");
		start++;
	}

	return start;
}

// _sfmt fills the passed buffer with the expected format
// _sfmt (variadic specialization) for multiple arguments
// it returns the number of characters written to the passed buffer
template <typename First, typename... Args>
int _sfmt(char* buffer, int start, bool ln, First x, Args... rest) {
	auto fmt = _fmt(x);
	std::strcpy(buffer + start, fmt);
	start += strlen(fmt);

	std::strcpy(buffer + start, " ");
	start++;

	return _sfmt(buffer, start, ln, rest...);
}

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

// _print creates a new buffer for the passed arguments and calls printf
// the first parameter checks whether newline has to be printed at the end or
// not
template <typename... T>
int _print(FILE* stream, bool ln, T... args) {
	int nargs = sizeof...(args);
	int size = nargs * 5 - 1;
	if (ln) size++;
	char buf[size];
	memset(buf, 0, size);

	_sfmt(buf, 0, ln, args...);
	return fprintf(stream, buf, args...);
}

// fprint (empty argument specialization), simply returns 0
int fprint(FILE* stream) { return 0; }

// fprint (variadic arguments specialization) prints without newline at the end
// to the passed stream
template <typename... T>
int fprint(FILE* stream, T... args) {
	return _print(stream, false, args...);
}

// fprintln (empty argument specialization), simply prints a newline
// to the passed stream
int fprintln(FILE* stream) { return fprintf(stream, "\n"); }

// fprintln (variadic arguments specialization) prints with newline at the end
// to the passed stream
template <typename... T>
int fprintln(FILE* stream, T... args) {
	return _print(stream, true, args...);
}

// print (empty argument specialization), simply returns 0
int print() { return 0; }

// print (variadic arguments specialization) prints without newline at the end
template <typename... T>
int print(T... args) {
	return _print(stdout, false, args...);
}

// println (empty argument specialization), simply prints a newline
int println() { return printf("\n"); }

// println (variadic arguments specialization) prints with newline at the end
template <typename... T>
int println(T... args) {
	return _print(stdout, true, args...);
}

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

// scan (empty argument specialization), simply returns 0
int fscan(FILE* stream) { return 0; }

// scan (variadic arguments specialization) creates a format string and then
// scans
// arguments, returning the result of the scanf call
template <typename... T>
int fscan(FILE* stream, T... args) {
	int nargs = sizeof...(args);
	int size = 5 * nargs - 1;

	char buf[size];
	memset(buf, 0, size);

	_sfmt(buf, 0, false, args...);
	return fscanf(stream, buf, args...);
}

void fscanskipln(FILE* stream) {
	while (true) {
		char ch = getc(stream);
		if (ch == EOF || ch == '\n') break;
		// TODO: check if we need
		// https://sourcegraph.com/github.com/golang/go@838eaa738f2bc07c3706b96f9e702cb80877dfe1/-/blob/src/fmt/scan.go#L1058:8
	}
}

// fscanln (empty argument specialization), scans until a newline and returns 0
int fscanln(FILE* stream) {
	fscanskipln(stream);
	return 0;
}

// scanln is scan but will read until a newline or EOF
template <typename... T>
int fscanln(FILE* stream, T... args) {
	int v = fscan(stream, args...);
	fscanskipln(stream);
	return v;
}

int scan() { return 0; }

template <typename... T>
int scan(T... args) {
	return fscan(stdin, args...);
}

int scanln() { return fscanln(stdin); }

template <typename... T>
int scanln(T... args) {
	return fscanln(stdin, args...);
}
<|endoftext|>


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

#include "dictionary_manager.hpp"

#include <memory>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <algorithm>

#include "log_stream.hpp"
#include "po_parser.hpp"
#include "unix_file_system.hpp"

namespace tinygettext {

static bool has_suffix(const std::string& lhs, const std::string rhs)
{
  if (lhs.length() < rhs.length())
    return false;
  else
    return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0;
}

DictionaryManager::DictionaryManager(const std::string& charset_) :
  dictionaries(),
  search_path(),
  charset(charset_),
  use_fuzzy(true),
  current_language(),
  current_dict(0),
  empty_dict(),
  filesystem(new UnixFileSystem)
{
}

DictionaryManager::~DictionaryManager()
{
  for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
  {
    delete i->second;
  }
}

void
DictionaryManager::clear_cache()
{
  for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
  {
    delete i->second;
  }
  dictionaries.clear();

  current_dict = 0;
}

Dictionary&
DictionaryManager::get_dictionary()
{
  if (current_dict)
  {
    return *current_dict;
  }
  else
  {
    if (current_language)
    {
      current_dict = &get_dictionary(current_language);
      return *current_dict;
    }
    else
    {
      return empty_dict;
    }
  }
}

Dictionary&
DictionaryManager::get_dictionary(const Language& language)
{
  //log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl;
  //log_debug << "...normalized as \"" << lang << "\"" << std::endl;
  assert(language);

  Dictionaries::iterator i = dictionaries.find(language);
  if (i != dictionaries.end())
  {
    return *i->second;
  }
  else // Dictionary for languages lang isn't loaded, so we load it
  {
    //log_debug << "get_dictionary: " << lang << std::endl;
    Dictionary* dict = new Dictionary(charset);

    dictionaries[language] = dict;

    for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p)
    {
      std::vector<std::string> files = filesystem->open_directory(*p);

      std::string best_filename;
      int best_score = 0;

      for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++)
      {
        // check if filename matches requested language
        if (has_suffix(*filename, ".po"))
        { // ignore anything that isn't a .po file
          Language po_language = Language::from_env(filename->substr(0, filename->size()-3));

          if (!po_language)
          {
            log_warning << *filename << ": warning: ignoring, unknown language" << std::endl;
          }
          else
          {
            int score = Language::match(language, po_language);

            if (score > best_score)
            {
              best_score = score;
              best_filename = *filename;
            }
          }
        }
      }

      if (!best_filename.empty())
      {
        std::string pofile = *p + "/" + best_filename;
        try
        {
          std::auto_ptr<std::istream> in = filesystem->open_file(pofile);
          if (!in.get())
          {
            log_error << "error: failure opening: " << pofile << std::endl;
          }
          else
          {
            POParser::parse(pofile, *in, *dict);
          }
        }
        catch(std::exception& e)
        {
          log_error << "error: failure parsing: " << pofile << std::endl;
          log_error << e.what() << "" << std::endl;
        }
      }
    }

    return *dict;
  }
}

std::set<Language>
DictionaryManager::get_languages()
{
  std::set<Language> languages;

  for (SearchPath::iterator p = search_path.begin(); p != search_path.end(); ++p)
  {
    std::vector<std::string> files = filesystem->open_directory(*p);

    for(std::vector<std::string>::iterator file = files.begin(); file != files.end(); ++file)
    {
      if (has_suffix(*file, ".po"))
      {
        languages.insert(Language::from_env(file->substr(0, file->size()-3)));
      }
    }
  }
  return languages;
}

void
DictionaryManager::set_language(const Language& language)
{
  if (current_language != language)
  {
    current_language = language;
    current_dict     = 0;
  }
}

Language
DictionaryManager::get_language() const
{
  return current_language;
}

void
DictionaryManager::set_charset(const std::string& charset_)
{
  clear_cache(); // changing charset invalidates cache
  charset = charset_;
}

void
DictionaryManager::set_use_fuzzy(bool t)
{
  clear_cache();
  use_fuzzy = t;
}

bool
DictionaryManager::get_use_fuzzy() const
{
  return use_fuzzy;
}

void
DictionaryManager::add_directory(const std::string& pathname)
{
  clear_cache(); // adding directories invalidates cache
  search_path.push_back(pathname);
}

void
DictionaryManager::add_po(const std::string& name, std::istream& in, const Language& lang)
{
  Dictionary *dict = new Dictionary(charset);
  POParser::parse( name, in, *dict );
  dictionaries[lang] = dict;
}

void
DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_)
{
  filesystem = filesystem_;
}

} // namespace tinygettext

/* EOF */
<commit_msg>Fix get_lanuguages() for our implementation of tinygettext<commit_after>//  tinygettext - A gettext replacement that works directly on .po files
//  Copyright (C) 2006 Ingo Ruhnke <grumbel@gmx.de>
//
//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU General Public License
//  as published by the Free Software Foundation; either version 2
//  of the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#include "dictionary_manager.hpp"

#include <memory>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <algorithm>

#include "log_stream.hpp"
#include "po_parser.hpp"
#include "unix_file_system.hpp"

namespace tinygettext {

static bool has_suffix(const std::string& lhs, const std::string rhs)
{
  if (lhs.length() < rhs.length())
    return false;
  else
    return lhs.compare(lhs.length() - rhs.length(), rhs.length(), rhs) == 0;
}

DictionaryManager::DictionaryManager(const std::string& charset_) :
  dictionaries(),
  search_path(),
  charset(charset_),
  use_fuzzy(true),
  current_language(),
  current_dict(0),
  empty_dict(),
  filesystem(new UnixFileSystem)
{
}

DictionaryManager::~DictionaryManager()
{
  for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
  {
    delete i->second;
  }
}

void
DictionaryManager::clear_cache()
{
  for(Dictionaries::iterator i = dictionaries.begin(); i != dictionaries.end(); ++i)
  {
    delete i->second;
  }
  dictionaries.clear();

  current_dict = 0;
}

Dictionary&
DictionaryManager::get_dictionary()
{
  if (current_dict)
  {
    return *current_dict;
  }
  else
  {
    if (current_language)
    {
      current_dict = &get_dictionary(current_language);
      return *current_dict;
    }
    else
    {
      return empty_dict;
    }
  }
}

Dictionary&
DictionaryManager::get_dictionary(const Language& language)
{
  //log_debug << "Dictionary for language \"" << spec << "\" requested" << std::endl;
  //log_debug << "...normalized as \"" << lang << "\"" << std::endl;
  assert(language);

  Dictionaries::iterator i = dictionaries.find(language);
  if (i != dictionaries.end())
  {
    return *i->second;
  }
  else // Dictionary for languages lang isn't loaded, so we load it
  {
    //log_debug << "get_dictionary: " << lang << std::endl;
    Dictionary* dict = new Dictionary(charset);

    dictionaries[language] = dict;

    for (SearchPath::reverse_iterator p = search_path.rbegin(); p != search_path.rend(); ++p)
    {
      std::vector<std::string> files = filesystem->open_directory(*p);

      std::string best_filename;
      int best_score = 0;

      for(std::vector<std::string>::iterator filename = files.begin(); filename != files.end(); filename++)
      {
        // check if filename matches requested language
        if (has_suffix(*filename, ".po"))
        { // ignore anything that isn't a .po file
          Language po_language = Language::from_env(filename->substr(0, filename->size()-3));

          if (!po_language)
          {
            log_warning << *filename << ": warning: ignoring, unknown language" << std::endl;
          }
          else
          {
            int score = Language::match(language, po_language);

            if (score > best_score)
            {
              best_score = score;
              best_filename = *filename;
            }
          }
        }
      }

      if (!best_filename.empty())
      {
        std::string pofile = *p + "/" + best_filename;
        try
        {
          std::auto_ptr<std::istream> in = filesystem->open_file(pofile);
          if (!in.get())
          {
            log_error << "error: failure opening: " << pofile << std::endl;
          }
          else
          {
            POParser::parse(pofile, *in, *dict);
          }
        }
        catch(std::exception& e)
        {
          log_error << "error: failure parsing: " << pofile << std::endl;
          log_error << e.what() << "" << std::endl;
        }
      }
    }

    return *dict;
  }
}

std::set<Language>
DictionaryManager::get_languages()
{
  std::set<Language> languages;

  for (std::map<Language,Dictionary*>::iterator p = dictionaries.begin(); p != dictionaries.end(); ++p)
  {
    languages.insert(p->first);
  }
  return languages;
}

void
DictionaryManager::set_language(const Language& language)
{
  if (current_language != language)
  {
    current_language = language;
    current_dict     = 0;
  }
}

Language
DictionaryManager::get_language() const
{
  return current_language;
}

void
DictionaryManager::set_charset(const std::string& charset_)
{
  clear_cache(); // changing charset invalidates cache
  charset = charset_;
}

void
DictionaryManager::set_use_fuzzy(bool t)
{
  clear_cache();
  use_fuzzy = t;
}

bool
DictionaryManager::get_use_fuzzy() const
{
  return use_fuzzy;
}

void
DictionaryManager::add_directory(const std::string& pathname)
{
  clear_cache(); // adding directories invalidates cache
  search_path.push_back(pathname);
}

void
DictionaryManager::add_po(const std::string& name, std::istream& in, const Language& lang)
{
  Dictionary *dict = new Dictionary(charset);
  POParser::parse( name, in, *dict );
  dictionaries[lang] = dict;
}

void
DictionaryManager::set_filesystem(std::auto_ptr<FileSystem> filesystem_)
{
  filesystem = filesystem_;
}

} // namespace tinygettext

/* EOF */
<|endoftext|>


<commit_before>

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#include "Effekseer.Color.h"

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#if (_M_IX86_FP >= 2) || defined(__SSE__)
#define EFK_SSE2
#include <emmintrin.h>
#elif defined(__ARM_NEON__)
#define EFK_NEON
#include <arm_neon.h>
#endif

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
namespace Effekseer
{

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color::Color( uint8_t r, uint8_t g, uint8_t b, uint8_t a )
	: R	( r )
	, G	( g )
	, B	( b )
	, A	( a )
{
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Mul( Color in1, Color in2 )
{
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_cvtsi32_si128(*(int32_t*)&in2);
	__m128i zero = _mm_setzero_si128();
	__m128i mask = _mm_set1_epi16(1);

	s1 = _mm_unpacklo_epi8(s1, zero);
	s2 = _mm_unpacklo_epi8(s2, zero);

	__m128i r0 = _mm_mullo_epi16(s1, s2);
	__m128i r1 = _mm_srli_epi16(r0, 8);
	__m128i r2 = _mm_and_si128(r0, mask);
	__m128i r3 = _mm_or_si128(r2, r1);
	__m128i res = _mm_packus_epi16(r3, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	uint16x8_t mask = vmovq_n_u16(1);
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	uint16x8_t r0 = vmulq_u16(s3, s4);
	uint16x8_t r1 = vshrq_n_u16(r0, 8);
	uint16x8_t r2 = vandq_u16(r0, mask);
	uint16x8_t r3 = vorrq_u16(r2, r1);
	uint8x8_t res = vqmovn_u16(r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	Color o;
	o.R = (uint8_t)((float)in1.R * (float)in2.R / 255.0f);
	o.G = (uint8_t)((float)in1.G * (float)in2.G / 255.0f);
	o.B = (uint8_t)((float)in1.B * (float)in2.B / 255.0f);
	o.A = (uint8_t)((float)in1.A * (float)in2.A / 255.0f);
	return o;
#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Mul( Color in1, float in2 )
{
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_set1_epi16((int16_t)(in2 * 256));
	__m128i zero = _mm_setzero_si128();

	s1 = _mm_unpacklo_epi8(s1, zero);

	__m128i res = _mm_mullo_epi16(s1, s2);
	res = _mm_srli_epi16(res, 8);
	res = _mm_packus_epi16(res, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint16x8_t s2 = vmovq_n_u16((uint16_t)(in2 * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t r0 = vmulq_u16(s3, s2);
	uint16x8_t r1 = vshrq_n_u16(r0, 8);
	uint8x8_t res = vqmovn_u16(r1);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	Color o;
	o.R = (uint8_t)Clamp((int)((float)in1.R * in2), 255, 0);
	o.G = (uint8_t)Clamp((int)((float)in1.G * in2), 255, 0);
	o.B = (uint8_t)Clamp((int)((float)in1.B * in2), 255, 0);
	o.A = (uint8_t)Clamp((int)((float)in1.A * in2), 255, 0);
	return o;
#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Lerp( const Color in1, const Color in2, float t )
{
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_cvtsi32_si128(*(int32_t*)&in2);
	__m128i tm = _mm_set1_epi16((int16_t)(t * 256));
	__m128i zero = _mm_setzero_si128();

	s1 = _mm_unpacklo_epi8(s1, zero);
	s2 = _mm_unpacklo_epi8(s2, zero);

	__m128i r0 = _mm_subs_epi16(s2, s1);
	__m128i r1 = _mm_mullo_epi16(r0, tm);
	__m128i r2 = _mm_srai_epi16(r1, 8);
	__m128i r3 = _mm_adds_epi16(s1, r2);
	__m128i res = _mm_packus_epi16(r3, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)

#ifdef __ANDROID__
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	int16x8_t tm = vmovq_n_s16((int16_t)(t * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	int16x8_t r0 = (int16x8_t)vqsubq_s16((int16x8_t)s4, (int16x8_t)s3);
	int16x8_t r1 = vmulq_s16(r0, tm);
	int16x8_t r2 = vrshrq_n_s16(r1, 8);
	int16x8_t r3 = (int16x8_t)vqaddq_s16((int16x8_t)s3, r2);
	uint8x8_t res = (uint8x8_t)vqmovn_u16((uint16x8_t)r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	int16x8_t tm = vmovq_n_s16((int16_t)(t * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	int16x8_t r0 = vqsubq_s16(s4, s3);
	int16x8_t r1 = vmulq_s16(r0, tm);
	int16x8_t r2 = vrshrq_n_s16(r1, 8);
	int16x8_t r3 = vqaddq_s16(s3, r2);
	uint8x8_t res = vqmovn_u16(r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#endif

#else
	Color o;
	o.R = (uint8_t)Clamp( in1.R + (in2.R - in1.R) * t, 255, 0 );
	o.G = (uint8_t)Clamp( in1.G + (in2.G - in1.G) * t, 255, 0 );
	o.B = (uint8_t)Clamp( in1.B + (in2.B - in1.B) * t, 255, 0 );
	o.A = (uint8_t)Clamp( in1.A + (in2.A - in1.A) * t, 255, 0 );
	return o;
#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------<commit_msg>Commented out bug<commit_after>

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#include "Effekseer.Color.h"

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
#if (_M_IX86_FP >= 2) || defined(__SSE__)
#define EFK_SSE2
#include <emmintrin.h>
#elif defined(__ARM_NEON__)
#define EFK_NEON
#include <arm_neon.h>
#endif

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
namespace Effekseer
{

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color::Color( uint8_t r, uint8_t g, uint8_t b, uint8_t a )
	: R	( r )
	, G	( g )
	, B	( b )
	, A	( a )
{
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Mul( Color in1, Color in2 )
{
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_cvtsi32_si128(*(int32_t*)&in2);
	__m128i zero = _mm_setzero_si128();
	__m128i mask = _mm_set1_epi16(1);

	s1 = _mm_unpacklo_epi8(s1, zero);
	s2 = _mm_unpacklo_epi8(s2, zero);

	__m128i r0 = _mm_mullo_epi16(s1, s2);
	__m128i r1 = _mm_srli_epi16(r0, 8);
	__m128i r2 = _mm_and_si128(r0, mask);
	__m128i r3 = _mm_or_si128(r2, r1);
	__m128i res = _mm_packus_epi16(r3, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	uint16x8_t mask = vmovq_n_u16(1);
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	uint16x8_t r0 = vmulq_u16(s3, s4);
	uint16x8_t r1 = vshrq_n_u16(r0, 8);
	uint16x8_t r2 = vandq_u16(r0, mask);
	uint16x8_t r3 = vorrq_u16(r2, r1);
	uint8x8_t res = vqmovn_u16(r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	Color o;
	o.R = (uint8_t)((float)in1.R * (float)in2.R / 255.0f);
	o.G = (uint8_t)((float)in1.G * (float)in2.G / 255.0f);
	o.B = (uint8_t)((float)in1.B * (float)in2.B / 255.0f);
	o.A = (uint8_t)((float)in1.A * (float)in2.A / 255.0f);
	return o;
#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Mul( Color in1, float in2 )
{
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_set1_epi16((int16_t)(in2 * 256));
	__m128i zero = _mm_setzero_si128();

	s1 = _mm_unpacklo_epi8(s1, zero);

	__m128i res = _mm_mullo_epi16(s1, s2);
	res = _mm_srli_epi16(res, 8);
	res = _mm_packus_epi16(res, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint16x8_t s2 = vmovq_n_u16((uint16_t)(in2 * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t r0 = vmulq_u16(s3, s2);
	uint16x8_t r1 = vshrq_n_u16(r0, 8);
	uint8x8_t res = vqmovn_u16(r1);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	Color o;
	o.R = (uint8_t)Clamp((int)((float)in1.R * in2), 255, 0);
	o.G = (uint8_t)Clamp((int)((float)in1.G * in2), 255, 0);
	o.B = (uint8_t)Clamp((int)((float)in1.B * in2), 255, 0);
	o.A = (uint8_t)Clamp((int)((float)in1.A * in2), 255, 0);
	return o;
#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
Color Color::Lerp( const Color in1, const Color in2, float t )
{
	/*
#if defined(EFK_SSE2)
	__m128i s1 = _mm_cvtsi32_si128(*(int32_t*)&in1);
	__m128i s2 = _mm_cvtsi32_si128(*(int32_t*)&in2);
	__m128i tm = _mm_set1_epi16((int16_t)(t * 256));
	__m128i zero = _mm_setzero_si128();

	s1 = _mm_unpacklo_epi8(s1, zero);
	s2 = _mm_unpacklo_epi8(s2, zero);

	__m128i r0 = _mm_subs_epi16(s2, s1);
	__m128i r1 = _mm_mullo_epi16(r0, tm);
	__m128i r2 = _mm_srai_epi16(r1, 8);
	__m128i r3 = _mm_adds_epi16(s1, r2);
	__m128i res = _mm_packus_epi16(r3, zero);

	Color o;
	*(int*)&o = _mm_cvtsi128_si32(res);
	return o;
#elif defined(EFK_NEON)

#ifdef __ANDROID__
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	int16x8_t tm = vmovq_n_s16((int16_t)(t * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	int16x8_t r0 = (int16x8_t)vqsubq_s16((int16x8_t)s4, (int16x8_t)s3);
	int16x8_t r1 = vmulq_s16(r0, tm);
	int16x8_t r2 = vrshrq_n_s16(r1, 8);
	int16x8_t r3 = (int16x8_t)vqaddq_s16((int16x8_t)s3, r2);
	uint8x8_t res = (uint8x8_t)vqmovn_u16((uint16x8_t)r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#else
	uint8x8_t s1 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in1));
	uint8x8_t s2 = vreinterpret_u8_u32(vmov_n_u32(*(uint32_t*)&in2));
	int16x8_t tm = vmovq_n_s16((int16_t)(t * 256));
	uint16x8_t s3 = vmovl_u8(s1);
	uint16x8_t s4 = vmovl_u8(s2);
	int16x8_t r0 = vqsubq_s16(s4, s3);
	int16x8_t r1 = vmulq_s16(r0, tm);
	int16x8_t r2 = vrshrq_n_s16(r1, 8);
	int16x8_t r3 = vqaddq_s16(s3, r2);
	uint8x8_t res = vqmovn_u16(r3);

	Color o;
	*(uint32_t*)&o = vget_lane_u32(vreinterpret_u32_u8(res), 0);
	return o;
#endif

#else
	*/
	Color o;
	o.R = (uint8_t)Clamp( in1.R + (in2.R - in1.R) * t, 255, 0 );
	o.G = (uint8_t)Clamp( in1.G + (in2.G - in1.G) * t, 255, 0 );
	o.B = (uint8_t)Clamp( in1.B + (in2.B - in1.B) * t, 255, 0 );
	o.A = (uint8_t)Clamp( in1.A + (in2.A - in1.A) * t, 255, 0 );
	return o;
//#endif
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------
}

//----------------------------------------------------------------------------------
//
//----------------------------------------------------------------------------------<|endoftext|>