<commit_before>/*******************************************************************************
  Copyright (c) 2011-2014 Dmitry Matveev <me@dmitrymatveev.co.uk>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*******************************************************************************/

#include <cassert>
#include <cstring>
#include <poll.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "inotify_client.hh"
#include "log.hh"

#include <iostream>

inotify_client::inotify_client ()
: fd (inotify_init())
{
    assert (fd != -1);
}

inotify_client::~inotify_client ()
{
    close (fd);
}

int inotify_client::watch (const std::string &filename, uint32_t flags)
{
    assert (fd != -1);
    LOG ("INO: Adding " << VAR (filename) << VAR (flags));

    int retval = inotify_add_watch (fd, filename.c_str(), flags);
    LOG ("INO: " << VAR (retval));
    return retval;
}

void inotify_client::cancel (int watch_id)
{
    assert (fd != -1);
    if (inotify_rm_watch (fd, watch_id) != 0) {
        LOG ("INO: rm watch failed " << VAR (fd) << VAR (watch_id));
    }
}

#ifdef IN_DEF_SOCKBUFSIZE
#define IE_BUFSIZE IN_DEF_SOCKBUFSIZE
#else
#define IE_BUFSIZE (((sizeof (struct inotify_event) + FILENAME_MAX)) * 20)
#endif

events inotify_client::receive_during (int timeout) const
{
    events received;
    struct pollfd pfd;

    time_t start = timems ();
    time_t elapsed = 0;

    LOG ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

    while ((elapsed = timems () - start) < timeout) {
        memset (&pfd, 0, sizeof (struct pollfd));
        pfd.fd = fd;
        pfd.events = POLLIN;

        LOG ("INO: Polling with " << VAR (timeout) << " ms");
        int pollretval = poll (&pfd, 1, timeout);
        LOG ("INO: Poll returned " << VAR (pollretval) << ", " << VAR(pfd.revents));
        if (pollretval == -1) {
            return events();
        }

        if (pfd.revents & POLLIN) {
            char buffer[IE_BUFSIZE];
            char *ptr = buffer;
            int avail = read (fd, buffer, IE_BUFSIZE);

            /* The construction is probably harmful */
            while (avail >= sizeof (struct inotify_event *)) {
                struct inotify_event *ie = (struct inotify_event *) ptr;
                event ev;

                if (ie->len) {
                        ev.filename = ie->name;
                }
                ev.flags = ie->mask;
                ev.watch = ie->wd;
                ev.cookie = ie->cookie;

                LOG ("INO: Got next event! " << VAR (ev.filename) << VAR (ev.watch) << VAR (ev.flags));
                received.insert (ev);

                int offset = sizeof (struct inotify_event) + ie->len;
                avail -= offset;
                ptr += offset;
            }
        }
    }

    LOG ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");

    return received;
}

long inotify_client::bytes_available (int fd)
{
    long int avail = 0;
    size_t bytes;

    if (ioctl (fd, FIONREAD, (char *) &bytes) >= 0)
        avail = (long int) *((int *) &bytes);

    return avail;
}

int inotify_client::get_fd ()
{
    return fd;
}

time_t inotify_client::timems ()
{
    struct timespec ts;

    if (clock_gettime (CLOCK_MONOTONIC, &ts) < 0) {
        return time(NULL) * 1000;
    }

    return ts.tv_sec * 1000 + (time_t)(ts.tv_nsec / 1000000L);
}
<commit_msg>Test suite: Use CLOCK_MONOTONIC only if it is available in time.h<commit_after>/*******************************************************************************
  Copyright (c) 2011-2014 Dmitry Matveev <me@dmitrymatveev.co.uk>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*******************************************************************************/

#include <cassert>
#include <cstring>
#include <poll.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "inotify_client.hh"
#include "log.hh"

#include <iostream>

inotify_client::inotify_client ()
: fd (inotify_init())
{
    assert (fd != -1);
}

inotify_client::~inotify_client ()
{
    close (fd);
}

int inotify_client::watch (const std::string &filename, uint32_t flags)
{
    assert (fd != -1);
    LOG ("INO: Adding " << VAR (filename) << VAR (flags));

    int retval = inotify_add_watch (fd, filename.c_str(), flags);
    LOG ("INO: " << VAR (retval));
    return retval;
}

void inotify_client::cancel (int watch_id)
{
    assert (fd != -1);
    if (inotify_rm_watch (fd, watch_id) != 0) {
        LOG ("INO: rm watch failed " << VAR (fd) << VAR (watch_id));
    }
}

#ifdef IN_DEF_SOCKBUFSIZE
#define IE_BUFSIZE IN_DEF_SOCKBUFSIZE
#else
#define IE_BUFSIZE (((sizeof (struct inotify_event) + FILENAME_MAX)) * 20)
#endif

events inotify_client::receive_during (int timeout) const
{
    events received;
    struct pollfd pfd;

    time_t start = timems ();
    time_t elapsed = 0;

    LOG ("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

    while ((elapsed = timems () - start) < timeout) {
        memset (&pfd, 0, sizeof (struct pollfd));
        pfd.fd = fd;
        pfd.events = POLLIN;

        LOG ("INO: Polling with " << VAR (timeout) << " ms");
        int pollretval = poll (&pfd, 1, timeout);
        LOG ("INO: Poll returned " << VAR (pollretval) << ", " << VAR(pfd.revents));
        if (pollretval == -1) {
            return events();
        }

        if (pfd.revents & POLLIN) {
            char buffer[IE_BUFSIZE];
            char *ptr = buffer;
            int avail = read (fd, buffer, IE_BUFSIZE);

            /* The construction is probably harmful */
            while (avail >= sizeof (struct inotify_event *)) {
                struct inotify_event *ie = (struct inotify_event *) ptr;
                event ev;

                if (ie->len) {
                        ev.filename = ie->name;
                }
                ev.flags = ie->mask;
                ev.watch = ie->wd;
                ev.cookie = ie->cookie;

                LOG ("INO: Got next event! " << VAR (ev.filename) << VAR (ev.watch) << VAR (ev.flags));
                received.insert (ev);

                int offset = sizeof (struct inotify_event) + ie->len;
                avail -= offset;
                ptr += offset;
            }
        }
    }

    LOG ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");

    return received;
}

long inotify_client::bytes_available (int fd)
{
    long int avail = 0;
    size_t bytes;

    if (ioctl (fd, FIONREAD, (char *) &bytes) >= 0)
        avail = (long int) *((int *) &bytes);

    return avail;
}

int inotify_client::get_fd ()
{
    return fd;
}

time_t inotify_client::timems ()
{
    struct timespec ts;

#ifdef CLOCK_MONOTONIC
    if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) {
        return ts.tv_sec * 1000 + (time_t)(ts.tv_nsec / 1000000L);
    }
#endif

    return time(NULL) * 1000;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "mutation.hh"

class mutation_partition_assertion {
    schema_ptr _schema;
    const mutation_partition& _m;
public:
    mutation_partition_assertion(schema_ptr s, const mutation_partition& m)
        : _schema(s)
        , _m(m)
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_partition_assertion& is_equal_to(const mutation_partition& other,
            const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        return is_equal_to(*_schema, other, ck_ranges);
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_partition_assertion& is_equal_to(const schema& s, const mutation_partition& other,
            const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_partition_assertion(_schema, _m.sliced(*_schema, *ck_ranges))
                .is_equal_to(s, other.sliced(s, *ck_ranges));
            return *this;
        }
        if (!_m.equal(*_schema, other, s)) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (!other.equal(s, _m, *_schema)) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& is_not_equal_to(const mutation_partition& other) {
        return is_not_equal_to(*_schema, other);
    }

    mutation_partition_assertion& is_not_equal_to(const schema& s, const mutation_partition& other) {
        if (_m.equal(*_schema, other, s)) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& has_same_continuity(const mutation_partition& other) {
        if (!_m.equal_continuity(*_schema, other)) {
            BOOST_FAIL(sprint("Continuity doesn't match: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& is_continuous(const position_range& r, is_continuous cont = is_continuous::yes) {
        if (!_m.check_continuity(*_schema, r, cont)) {
            BOOST_FAIL(sprint("Expected range %s to be %s in %s", r, cont ? "continuous" : "discontinuous", _m));
        }
        return *this;
    }
};

static inline
mutation_partition_assertion assert_that(schema_ptr s, const mutation_partition& mp) {
    return {std::move(s), mp};
}

class mutation_assertion {
    mutation _m;
public:
    mutation_assertion(mutation m)
        : _m(std::move(m))
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_assertion& is_equal_to(const mutation& other, const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_assertion(_m.sliced(*ck_ranges)).is_equal_to(other.sliced(*ck_ranges));
            return *this;
        }
        if (_m != other) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (other != _m) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& is_not_equal_to(const mutation& other) {
        if (_m == other) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& has_schema(schema_ptr s) {
        if (_m.schema() != s) {
            BOOST_FAIL(sprint("Expected mutation of schema %s, but got %s", *s, *_m.schema()));
        }
        return *this;
    }

    mutation_assertion& has_same_continuity(const mutation& other) {
        assert_that(_m.schema(), _m.partition()).has_same_continuity(other.partition());
        return *this;
    }

    mutation_assertion& is_continuous(const position_range& r, is_continuous cont = is_continuous::yes) {
        assert_that(_m.schema(), _m.partition()).is_continuous(r, cont);
        return *this;
    }

    // Verifies that mutation data remains unchanged when upgraded to the new schema
    void is_upgrade_equivalent(schema_ptr new_schema) {
        mutation m2 = _m;
        m2.upgrade(new_schema);
        BOOST_REQUIRE(m2.schema() == new_schema);
        mutation_assertion(m2).is_equal_to(_m);

        mutation m3 = m2;
        m3.upgrade(_m.schema());
        BOOST_REQUIRE(m3.schema() == _m.schema());
        mutation_assertion(m3).is_equal_to(_m);
        mutation_assertion(m3).is_equal_to(m2);
    }
};

static inline
mutation_assertion assert_that(mutation m) {
    return { std::move(m) };
}

static inline
mutation_assertion assert_that(streamed_mutation sm) {
    auto mo = mutation_from_streamed_mutation(std::move(sm)).get0();
    return { std::move(*mo) };
}

class mutation_opt_assertions {
    mutation_opt _mo;
public:
    mutation_opt_assertions(mutation_opt mo) : _mo(std::move(mo)) {}

    mutation_assertion has_mutation() {
        if (!_mo) {
            BOOST_FAIL("Expected engaged mutation_opt, but found not");
        }
        return { *_mo };
    }

    void has_no_mutation() {
        if (_mo) {
            BOOST_FAIL("Expected disengaged mutation_opt");
        }
    }
};

static inline
mutation_opt_assertions assert_that(mutation_opt mo) {
    return { std::move(mo) };
}

static inline
mutation_opt_assertions assert_that(streamed_mutation_opt smo) {
    auto mo = mutation_from_streamed_mutation(std::move(smo)).get0();
    return { std::move(mo) };
}

class streamed_mutation_assertions {
    streamed_mutation _sm;
    clustering_key::equality _ck_eq;
public:
    streamed_mutation_assertions(streamed_mutation sm)
        : _sm(std::move(sm)), _ck_eq(*_sm.schema()) { }

    streamed_mutation_assertions& produces_static_row() {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL("Expected static row, got end of stream");
        }
        if (mfopt->mutation_fragment_kind() != mutation_fragment::kind::static_row) {
            BOOST_FAIL(sprint("Expected static row, got: %s", mfopt->mutation_fragment_kind()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment::kind k, std::vector<int> ck_elements) {
        std::vector<bytes> ck_bytes;
        for (auto&& e : ck_elements) {
            ck_bytes.emplace_back(int32_type->decompose(e));
        }
        auto ck = clustering_key_prefix::from_exploded(*_sm.schema(), std::move(ck_bytes));

        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", ck));
        }
        if (mfopt->mutation_fragment_kind() != k) {
            BOOST_FAIL(sprint("Expected mutation fragment kind %s, got: %s", k, mfopt->mutation_fragment_kind()));
        }
        if (!_ck_eq(mfopt->key(), ck)) {
            BOOST_FAIL(sprint("Expected key %s, got: %s", ck, mfopt->key()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment mf) {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", mf));
        }
        if (!mfopt->equal(*_sm.schema(), mf)) {
            BOOST_FAIL(sprint("Expected %s, but got %s", mf, *mfopt));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(const mutation& m) {
        assert_that(mutation_from_streamed_mutation(_sm).get0()).is_equal_to(m);
        return *this;
    }

    streamed_mutation_assertions& produces_only(const std::deque<mutation_fragment>& fragments) {
        for (auto&& f : fragments) {
            produces(f);
        }
        produces_end_of_stream();
        return *this;
    }

    streamed_mutation_assertions& produces_row_with_key(const clustering_key& ck) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", ck));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected row with key %s, but got end of stream", ck));
        }
        if (!mfo->is_clustering_row()) {
            BOOST_FAIL(sprint("Expected row with key %s, but got %s", ck, *mfo));
        }
        auto& actual = mfo->as_clustering_row().key();
        if (!actual.equal(*_sm.schema(), ck)) {
            BOOST_FAIL(sprint("Expected row with key %s, but key is %s", ck, actual));
        }
        return *this;
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    streamed_mutation_assertions& produces_range_tombstone(const range_tombstone& rt, const query::clustering_row_ranges& ck_ranges = {}) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", rt));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got end of stream", rt));
        }
        if (!mfo->is_range_tombstone()) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, *mfo));
        }
        const schema& s = *_sm.schema();
        range_tombstone_list actual_list(s);
        position_in_partition::equal_compare eq(s);
        while (mutation_fragment* next = _sm.peek().get0()) {
            if (!next->is_range_tombstone() || !eq(next->position(), mfo->position())) {
                break;
            }
            actual_list.apply(s, _sm().get0()->as_range_tombstone());
        }
        actual_list.apply(s, mfo->as_range_tombstone());
        {
            range_tombstone_list expected_list(s);
            expected_list.apply(s, rt);
            actual_list.trim(s, ck_ranges);
            expected_list.trim(s, ck_ranges);
            if (!actual_list.equal(s, expected_list)) {
                BOOST_FAIL(sprint("Expected %s, but got %s", expected_list, actual_list));
            }
        }
        return *this;
    }

    streamed_mutation_assertions& fwd_to(const clustering_key& ck1, const clustering_key& ck2) {
        return fwd_to(position_range{
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck1),
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck2)
        });
    }

    streamed_mutation_assertions& fwd_to(position_range range) {
        BOOST_TEST_MESSAGE(sprint("Forwarding to %s", range));
        _sm.fast_forward_to(std::move(range)).get();
        return *this;
    }

    streamed_mutation_assertions& produces_end_of_stream() {
        auto mfopt = _sm().get0();
        if (mfopt) {
            BOOST_FAIL(sprint("Expected end of stream, got: %s", *mfopt));
        }
        return *this;
    }

    void has_monotonic_positions() {
        position_in_partition::less_compare less(*_sm.schema());
        mutation_fragment_opt prev;
        for (;;) {
            mutation_fragment_opt mfo = _sm().get0();
            if (!mfo) {
                break;
            }
            if (prev) {
                if (less(mfo->position(), prev->position())) {
                    BOOST_FAIL(sprint("previous fragment has greater position: prev=%s, current=%s", *prev, *mfo));
                }
            }
            prev = std::move(mfo);
        }
    }
};

static inline streamed_mutation_assertions assert_that_stream(streamed_mutation sm)
{
    return streamed_mutation_assertions(std::move(sm));
}
<commit_msg>Delete unused assert_that(streamed_mutation)<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "mutation.hh"

class mutation_partition_assertion {
    schema_ptr _schema;
    const mutation_partition& _m;
public:
    mutation_partition_assertion(schema_ptr s, const mutation_partition& m)
        : _schema(s)
        , _m(m)
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_partition_assertion& is_equal_to(const mutation_partition& other,
            const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        return is_equal_to(*_schema, other, ck_ranges);
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_partition_assertion& is_equal_to(const schema& s, const mutation_partition& other,
            const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_partition_assertion(_schema, _m.sliced(*_schema, *ck_ranges))
                .is_equal_to(s, other.sliced(s, *ck_ranges));
            return *this;
        }
        if (!_m.equal(*_schema, other, s)) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (!other.equal(s, _m, *_schema)) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& is_not_equal_to(const mutation_partition& other) {
        return is_not_equal_to(*_schema, other);
    }

    mutation_partition_assertion& is_not_equal_to(const schema& s, const mutation_partition& other) {
        if (_m.equal(*_schema, other, s)) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& has_same_continuity(const mutation_partition& other) {
        if (!_m.equal_continuity(*_schema, other)) {
            BOOST_FAIL(sprint("Continuity doesn't match: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_partition_assertion& is_continuous(const position_range& r, is_continuous cont = is_continuous::yes) {
        if (!_m.check_continuity(*_schema, r, cont)) {
            BOOST_FAIL(sprint("Expected range %s to be %s in %s", r, cont ? "continuous" : "discontinuous", _m));
        }
        return *this;
    }
};

static inline
mutation_partition_assertion assert_that(schema_ptr s, const mutation_partition& mp) {
    return {std::move(s), mp};
}

class mutation_assertion {
    mutation _m;
public:
    mutation_assertion(mutation m)
        : _m(std::move(m))
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_assertion& is_equal_to(const mutation& other, const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_assertion(_m.sliced(*ck_ranges)).is_equal_to(other.sliced(*ck_ranges));
            return *this;
        }
        if (_m != other) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (other != _m) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& is_not_equal_to(const mutation& other) {
        if (_m == other) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& has_schema(schema_ptr s) {
        if (_m.schema() != s) {
            BOOST_FAIL(sprint("Expected mutation of schema %s, but got %s", *s, *_m.schema()));
        }
        return *this;
    }

    mutation_assertion& has_same_continuity(const mutation& other) {
        assert_that(_m.schema(), _m.partition()).has_same_continuity(other.partition());
        return *this;
    }

    mutation_assertion& is_continuous(const position_range& r, is_continuous cont = is_continuous::yes) {
        assert_that(_m.schema(), _m.partition()).is_continuous(r, cont);
        return *this;
    }

    // Verifies that mutation data remains unchanged when upgraded to the new schema
    void is_upgrade_equivalent(schema_ptr new_schema) {
        mutation m2 = _m;
        m2.upgrade(new_schema);
        BOOST_REQUIRE(m2.schema() == new_schema);
        mutation_assertion(m2).is_equal_to(_m);

        mutation m3 = m2;
        m3.upgrade(_m.schema());
        BOOST_REQUIRE(m3.schema() == _m.schema());
        mutation_assertion(m3).is_equal_to(_m);
        mutation_assertion(m3).is_equal_to(m2);
    }
};

static inline
mutation_assertion assert_that(mutation m) {
    return { std::move(m) };
}

class mutation_opt_assertions {
    mutation_opt _mo;
public:
    mutation_opt_assertions(mutation_opt mo) : _mo(std::move(mo)) {}

    mutation_assertion has_mutation() {
        if (!_mo) {
            BOOST_FAIL("Expected engaged mutation_opt, but found not");
        }
        return { *_mo };
    }

    void has_no_mutation() {
        if (_mo) {
            BOOST_FAIL("Expected disengaged mutation_opt");
        }
    }
};

static inline
mutation_opt_assertions assert_that(mutation_opt mo) {
    return { std::move(mo) };
}

static inline
mutation_opt_assertions assert_that(streamed_mutation_opt smo) {
    auto mo = mutation_from_streamed_mutation(std::move(smo)).get0();
    return { std::move(mo) };
}

class streamed_mutation_assertions {
    streamed_mutation _sm;
    clustering_key::equality _ck_eq;
public:
    streamed_mutation_assertions(streamed_mutation sm)
        : _sm(std::move(sm)), _ck_eq(*_sm.schema()) { }

    streamed_mutation_assertions& produces_static_row() {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL("Expected static row, got end of stream");
        }
        if (mfopt->mutation_fragment_kind() != mutation_fragment::kind::static_row) {
            BOOST_FAIL(sprint("Expected static row, got: %s", mfopt->mutation_fragment_kind()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment::kind k, std::vector<int> ck_elements) {
        std::vector<bytes> ck_bytes;
        for (auto&& e : ck_elements) {
            ck_bytes.emplace_back(int32_type->decompose(e));
        }
        auto ck = clustering_key_prefix::from_exploded(*_sm.schema(), std::move(ck_bytes));

        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", ck));
        }
        if (mfopt->mutation_fragment_kind() != k) {
            BOOST_FAIL(sprint("Expected mutation fragment kind %s, got: %s", k, mfopt->mutation_fragment_kind()));
        }
        if (!_ck_eq(mfopt->key(), ck)) {
            BOOST_FAIL(sprint("Expected key %s, got: %s", ck, mfopt->key()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment mf) {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", mf));
        }
        if (!mfopt->equal(*_sm.schema(), mf)) {
            BOOST_FAIL(sprint("Expected %s, but got %s", mf, *mfopt));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(const mutation& m) {
        assert_that(mutation_from_streamed_mutation(_sm).get0()).is_equal_to(m);
        return *this;
    }

    streamed_mutation_assertions& produces_only(const std::deque<mutation_fragment>& fragments) {
        for (auto&& f : fragments) {
            produces(f);
        }
        produces_end_of_stream();
        return *this;
    }

    streamed_mutation_assertions& produces_row_with_key(const clustering_key& ck) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", ck));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected row with key %s, but got end of stream", ck));
        }
        if (!mfo->is_clustering_row()) {
            BOOST_FAIL(sprint("Expected row with key %s, but got %s", ck, *mfo));
        }
        auto& actual = mfo->as_clustering_row().key();
        if (!actual.equal(*_sm.schema(), ck)) {
            BOOST_FAIL(sprint("Expected row with key %s, but key is %s", ck, actual));
        }
        return *this;
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    streamed_mutation_assertions& produces_range_tombstone(const range_tombstone& rt, const query::clustering_row_ranges& ck_ranges = {}) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", rt));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got end of stream", rt));
        }
        if (!mfo->is_range_tombstone()) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, *mfo));
        }
        const schema& s = *_sm.schema();
        range_tombstone_list actual_list(s);
        position_in_partition::equal_compare eq(s);
        while (mutation_fragment* next = _sm.peek().get0()) {
            if (!next->is_range_tombstone() || !eq(next->position(), mfo->position())) {
                break;
            }
            actual_list.apply(s, _sm().get0()->as_range_tombstone());
        }
        actual_list.apply(s, mfo->as_range_tombstone());
        {
            range_tombstone_list expected_list(s);
            expected_list.apply(s, rt);
            actual_list.trim(s, ck_ranges);
            expected_list.trim(s, ck_ranges);
            if (!actual_list.equal(s, expected_list)) {
                BOOST_FAIL(sprint("Expected %s, but got %s", expected_list, actual_list));
            }
        }
        return *this;
    }

    streamed_mutation_assertions& fwd_to(const clustering_key& ck1, const clustering_key& ck2) {
        return fwd_to(position_range{
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck1),
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck2)
        });
    }

    streamed_mutation_assertions& fwd_to(position_range range) {
        BOOST_TEST_MESSAGE(sprint("Forwarding to %s", range));
        _sm.fast_forward_to(std::move(range)).get();
        return *this;
    }

    streamed_mutation_assertions& produces_end_of_stream() {
        auto mfopt = _sm().get0();
        if (mfopt) {
            BOOST_FAIL(sprint("Expected end of stream, got: %s", *mfopt));
        }
        return *this;
    }

    void has_monotonic_positions() {
        position_in_partition::less_compare less(*_sm.schema());
        mutation_fragment_opt prev;
        for (;;) {
            mutation_fragment_opt mfo = _sm().get0();
            if (!mfo) {
                break;
            }
            if (prev) {
                if (less(mfo->position(), prev->position())) {
                    BOOST_FAIL(sprint("previous fragment has greater position: prev=%s, current=%s", *prev, *mfo));
                }
            }
            prev = std::move(mfo);
        }
    }
};

static inline streamed_mutation_assertions assert_that_stream(streamed_mutation sm)
{
    return streamed_mutation_assertions(std::move(sm));
}
<|endoftext|>


<commit_before>#include <vector>

#include "test.h"

#include "uninorms.h"
using namespace ufal::unilib;

void split(const string& text, char sep, vector<string>& tokens) {
  tokens.clear();
  if (text.empty()) return;

  string::size_type index = 0;
  for (string::size_type next; (next = text.find(sep, index)) != string::npos; index = next + 1)
    tokens.emplace_back(text, index, next - index);
  tokens.emplace_back(text, index);
}

int main(void) {
  // Unicode normalization
  auto nfc = [](u32string str) { uninorms::nfc(str); return str; };
  auto nfd = [](u32string str) { uninorms::nfd(str); return str; };
  auto nfkc = [](u32string str) { uninorms::nfkc(str); return str; };
  auto nfkd = [](u32string str) { uninorms::nfkd(str); return str; };

  // Simple NFD + NFKD tests
  for (auto&& data : {
    make_tuple(U("příliš žluťoučký kůň úpěl ďábelské ódy"),
               U("pr\u030ci\u0301lis\u030c z\u030clut\u030couc\u030cky\u0301 ku\u030an\u030c u\u0301pe\u030cl d\u030ca\u0301belske\u0301 o\u0301dy")),
    make_tuple(U("PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ ÓDY"),
               U("PR\u030cI\u0301LIS\u030c Z\u030cLUT\u030cOUC\u030cKY\u0301 KU\u030aN\u030c U\u0301PE\u030cL D\u030cA\u0301BELSKE\u0301 O\u0301DY")),
    make_tuple(U("\u0345\u035D\u035C\u0315\u0300\u05AE\U0001D16D\u302E\u059A\u0316\u302A\u031B\u1DCE\u0321\u0F74\u0F72\u0F71\u0EC8"),
               U("\u0EC8\u0F71\u0F72\u0F74\u0321\u1DCE\u031B\u302A\u0316\u059A\u302E\U0001D16D\u05AE\u0300\u0315\u035C\u035D\u0345")),
    make_tuple(U("\u0EB8\u0E48\u0E38\u0C56\u0C55\u0711\u0670\u0652\u0651\u061A\u0619\u0618\u064D\u064C\u064B\uFB1E\u05C2\u05C1"),
               U("\u05C1\u05C2\uFB1E\u064B\u064C\u064D\u0618\u0619\u061A\u0651\u0652\u0670\u0711\u0C55\u0C56\u0E38\u0E48\u0EB8")),
    make_tuple(U("\u05BF\u05BD\u05BC\u05BB\u05B9\u05B8\u05B7\u05B6\u05B5\u05B4\u05B3\u05B2\u05B1\u05B0\u094D\u3099\u093C\u0334"),
               U("\u0334\u093C\u3099\u094D\u05B0\u05B1\u05B2\u05B3\u05B4\u05B5\u05B6\u05B7\u05B8\u05B9\u05BB\u05BC\u05BD\u05BF"))}) {
    test(nfd, get<0>(data).u32, get<1>(data).u32);
    test(nfd, get<1>(data).u32, get<1>(data).u32);
    test(nfkd, get<0>(data).u32, get<1>(data).u32);
    test(nfkd, get<1>(data).u32, get<1>(data).u32);
  }

  // Load UCD NormalizationTest from standard input and perform required
  // conformance tests.
  string line;
  vector<string> words;
  vector<string> characters;
  vector<u32string> forms(5);
  while (getline(cin, line)) {
    split(line, ';', words);
    if (words.size() != forms.size()) return cerr << "Cannot parse NormalizationTest line " << line << endl, 1;
    for (unsigned i = 0; i < words.size(); i++) {
      split(words[i], ' ', characters);
      forms[i].clear();
      for (auto&& character : characters)
        forms[i] += stoi(character, nullptr, 16);
    }

    test(nfc, forms[0], forms[1]);
    test(nfc, forms[1], forms[1]);
    test(nfc, forms[2], forms[1]);
    test(nfc, forms[3], forms[3]);
    test(nfc, forms[4], forms[3]);

    test(nfd, forms[0], forms[2]);
    test(nfd, forms[1], forms[2]);
    test(nfd, forms[2], forms[2]);
    test(nfd, forms[3], forms[4]);
    test(nfd, forms[4], forms[4]);

    test(nfkc, forms[0], forms[3]);
    test(nfkc, forms[1], forms[3]);
    test(nfkc, forms[2], forms[3]);
    test(nfkc, forms[3], forms[3]);
    test(nfkc, forms[4], forms[3]);

    test(nfkd, forms[0], forms[4]);
    test(nfkd, forms[1], forms[4]);
    test(nfkd, forms[2], forms[4]);
    test(nfkd, forms[3], forms[4]);
    test(nfkd, forms[4], forms[4]);
  }

  test_summary();

  return 0;
}
<commit_msg>Test that chars not listed in NormalizationTest are fixedpoints.<commit_after>#include <vector>

#include "test.h"

#include "uninorms.h"
using namespace ufal::unilib;

void split(const string& text, char sep, vector<string>& tokens) {
  tokens.clear();
  if (text.empty()) return;

  string::size_type index = 0;
  for (string::size_type next; (next = text.find(sep, index)) != string::npos; index = next + 1)
    tokens.emplace_back(text, index, next - index);
  tokens.emplace_back(text, index);
}

int main(void) {
  // Unicode normalization
  auto nfc = [](u32string str) { uninorms::nfc(str); return str; };
  auto nfd = [](u32string str) { uninorms::nfd(str); return str; };
  auto nfkc = [](u32string str) { uninorms::nfkc(str); return str; };
  auto nfkd = [](u32string str) { uninorms::nfkd(str); return str; };

  // Simple NFD + NFKD tests
  for (auto&& data : {
    make_tuple(U("příliš žluťoučký kůň úpěl ďábelské ódy"),
               U("pr\u030ci\u0301lis\u030c z\u030clut\u030couc\u030cky\u0301 ku\u030an\u030c u\u0301pe\u030cl d\u030ca\u0301belske\u0301 o\u0301dy")),
    make_tuple(U("PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ ÓDY"),
               U("PR\u030cI\u0301LIS\u030c Z\u030cLUT\u030cOUC\u030cKY\u0301 KU\u030aN\u030c U\u0301PE\u030cL D\u030cA\u0301BELSKE\u0301 O\u0301DY")),
    make_tuple(U("\u0345\u035D\u035C\u0315\u0300\u05AE\U0001D16D\u302E\u059A\u0316\u302A\u031B\u1DCE\u0321\u0F74\u0F72\u0F71\u0EC8"),
               U("\u0EC8\u0F71\u0F72\u0F74\u0321\u1DCE\u031B\u302A\u0316\u059A\u302E\U0001D16D\u05AE\u0300\u0315\u035C\u035D\u0345")),
    make_tuple(U("\u0EB8\u0E48\u0E38\u0C56\u0C55\u0711\u0670\u0652\u0651\u061A\u0619\u0618\u064D\u064C\u064B\uFB1E\u05C2\u05C1"),
               U("\u05C1\u05C2\uFB1E\u064B\u064C\u064D\u0618\u0619\u061A\u0651\u0652\u0670\u0711\u0C55\u0C56\u0E38\u0E48\u0EB8")),
    make_tuple(U("\u05BF\u05BD\u05BC\u05BB\u05B9\u05B8\u05B7\u05B6\u05B5\u05B4\u05B3\u05B2\u05B1\u05B0\u094D\u3099\u093C\u0334"),
               U("\u0334\u093C\u3099\u094D\u05B0\u05B1\u05B2\u05B3\u05B4\u05B5\u05B6\u05B7\u05B8\u05B9\u05BB\u05BC\u05BD\u05BF"))}) {
    test(nfd, get<0>(data).u32, get<1>(data).u32);
    test(nfd, get<1>(data).u32, get<1>(data).u32);
    test(nfkd, get<0>(data).u32, get<1>(data).u32);
    test(nfkd, get<1>(data).u32, get<1>(data).u32);
  }

  // Load UCD NormalizationTest from standard input and perform required
  // conformance tests.
  string line;
  vector<string> words;
  vector<string> characters;
  vector<u32string> forms(5);
  vector<bool> tested_chars(0x110000);
  while (getline(cin, line)) {
    split(line, ';', words);
    if (words.size() != forms.size()) return cerr << "Cannot parse NormalizationTest line " << line << endl, 1;
    for (unsigned i = 0; i < words.size(); i++) {
      split(words[i], ' ', characters);
      forms[i].clear();
      for (auto&& character : characters)
        forms[i] += stoi(character, nullptr, 16);
    }

    test(nfc, forms[0], forms[1]);
    test(nfc, forms[1], forms[1]);
    test(nfc, forms[2], forms[1]);
    test(nfc, forms[3], forms[3]);
    test(nfc, forms[4], forms[3]);

    test(nfd, forms[0], forms[2]);
    test(nfd, forms[1], forms[2]);
    test(nfd, forms[2], forms[2]);
    test(nfd, forms[3], forms[4]);
    test(nfd, forms[4], forms[4]);

    test(nfkc, forms[0], forms[3]);
    test(nfkc, forms[1], forms[3]);
    test(nfkc, forms[2], forms[3]);
    test(nfkc, forms[3], forms[3]);
    test(nfkc, forms[4], forms[3]);

    test(nfkd, forms[0], forms[4]);
    test(nfkd, forms[1], forms[4]);
    test(nfkd, forms[2], forms[4]);
    test(nfkd, forms[3], forms[4]);
    test(nfkd, forms[4], forms[4]);

    if (forms[0].size() == 1) tested_chars[forms[0][0]] = true;
  }

  // One-letter strings not mentioned in NormalizationTest are fixed points.
  u32string letter(U" ");
  for (char32_t chr = 0; chr < tested_chars.size(); chr++)
    if (!tested_chars[chr]) {
      letter[0] = chr;
      test(nfc, letter, letter);
      test(nfd, letter, letter);
      test(nfkc, letter, letter);
      test(nfkd, letter, letter);
    }

  test_summary();

  return 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <memory>
#include <algorithm>
#include <vector>

#include "platform_tizen.h"
#include "platform_gl.h"
#include "urlWorker.h"

#include "log.h"

#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/syscall.h>

#include <fontconfig.h>
#include <dlog.h>

#define NUM_WORKERS 4

static bool s_isContinuousRendering = false;
static std::function<void()> s_renderCallbackFunction = nullptr;

static std::vector<std::string> s_fallbackFonts;
static FcConfig* s_fcConfig = nullptr;

static UrlWorker s_workers;

bool startUrlRequest(const std::string& _url, UrlCallback _callback) {
    s_workers.enqueue(std::make_unique<UrlTask>(_url, _callback));
    return true;
}

void cancelUrlRequest(const std::string& _url) {
}

void initUrlRequests(const char* proxyAddress) {
    s_workers.start(4, proxyAddress);
}

void stopUrlRequests() {
    s_workers.stop();
}

static bool s_update = false;
#ifdef  LOG_TAG
#undef  LOG_TAG
#endif
#define LOG_TAG "Tangram"

void logMsg(const char* fmt, ...) {

    va_list vl;
    va_start(vl, fmt);
    dlog_vprint(DLOG_WARN, LOG_TAG, fmt, vl);
    va_end(vl);
}

void setRenderCallbackFunction(std::function<void()> callback) {
    s_renderCallbackFunction = callback;
}

void setEvasGlAPI(Evas_GL_API *glApi) {
    __evas_gl_glapi = glApi;
}

void requestRender() {
    s_update = true;
    if (s_renderCallbackFunction) {
        s_renderCallbackFunction();
    }
}

bool shouldRender() {
    bool update = s_update;
    s_update = false;
    return update;
}

void setContinuousRendering(bool _isContinuous) {

    s_isContinuousRendering = _isContinuous;

}

bool isContinuousRendering() {

    return s_isContinuousRendering;

}

std::string stringFromFile(const char* _path) {

    size_t length = 0;
    unsigned char* bytes = bytesFromFile(_path, length);

    std::string out(reinterpret_cast<char*>(bytes), length);
    free(bytes);

    return out;
}

void initPlatformFontSetup() {

    static bool s_platformFontsInit = false;
    if (s_platformFontsInit) { return; }

    s_fcConfig = FcInitLoadConfigAndFonts();

    std::string style = "Regular";

    FcStrSet* fcLangs = FcGetLangs();
    FcStrList* fcLangList = FcStrListCreate(fcLangs);
    FcChar8* fcLang;
    while ((fcLang = FcStrListNext(fcLangList))) {
        FcValue fcStyleValue, fcLangValue;

        fcStyleValue.type = fcLangValue.type = FcType::FcTypeString;
        fcStyleValue.u.s = reinterpret_cast<const FcChar8*>(style.c_str());
        fcLangValue.u.s = fcLang;

        // create a pattern with style and family font properties
        FcPattern* pat = FcPatternCreate();

        FcPatternAdd(pat, FC_STYLE, fcStyleValue, true);
        FcPatternAdd(pat, FC_LANG, fcLangValue, true);
        //FcPatternPrint(pat);

        FcConfigSubstitute(s_fcConfig, pat, FcMatchPattern);
        FcDefaultSubstitute(pat);

        FcResult res;
        FcPattern* font = FcFontMatch(s_fcConfig, pat, &res);
        if (font) {
            FcChar8* file = nullptr;
            if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
                // Make sure this font file is not previously added.
                if (std::find(s_fallbackFonts.begin(), s_fallbackFonts.end(),
                              reinterpret_cast<char*>(file)) == s_fallbackFonts.end()) {
                    s_fallbackFonts.emplace_back(reinterpret_cast<char*>(file));
                }
            }
            FcPatternDestroy(font);
        }
        FcPatternDestroy(pat);
    }
    FcStrListDone(fcLangList);
    s_platformFontsInit = true;
}

std::vector<FontSourceHandle> systemFontFallbacksHandle() {

    initPlatformFontSetup();

    std::vector<FontSourceHandle> handles;

    for (auto path : s_fallbackFonts) {
        FontSourceHandle fontSourceHandle = [](size_t* _size) -> unsigned char* {
            LOG("Loading font %s", path.c_str());

            auto cdata = bytesFromFile(path.c_str(), *_size);

            return cdata;
        };

        handles.push_back(fontSourceHandle);
    }

    return handles;
}

std::string fontPath(const std::string& _name, const std::string& _weight,
                           const std::string& _face) {

    initPlatformFontSetup();

    if (!s_fcConfig) {
        return "";
    }

    std::string fontFile = "";
    FcValue fcFamily, fcFace, fcWeight;

    fcFamily.type = fcFace.type = fcWeight.type = FcType::FcTypeString;
    fcFamily.u.s = reinterpret_cast<const FcChar8*>(_name.c_str());
    fcWeight.u.s = reinterpret_cast<const FcChar8*>(_weight.c_str());
    fcFace.u.s = reinterpret_cast<const FcChar8*>(_face.c_str());

    // Create a pattern with family, style and weight font properties
    FcPattern* pattern = FcPatternCreate();

    FcPatternAdd(pattern, FC_FAMILY, fcFamily, true);
    FcPatternAdd(pattern, FC_STYLE, fcFace, true);
    FcPatternAdd(pattern, FC_WEIGHT, fcWeight, true);
    //FcPatternPrint(pattern);

    FcConfigSubstitute(s_fcConfig, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    FcResult res;
    FcPattern* font = FcFontMatch(s_fcConfig, pattern, &res);
    if (font) {
        FcChar8* file = nullptr;
        FcChar8* fontFamily = nullptr;
        if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch &&
            FcPatternGetString(font, FC_FAMILY, 0, &fontFamily) == FcResultMatch) {
            // We do not want the "best" match, but an "exact" or at least the same "family" match
            // We have fallbacks to cover rest here.
            if (strcmp(reinterpret_cast<const char*>(fontFamily), _name.c_str()) == 0) {
                fontFile = reinterpret_cast<const char*>(file);
            }
        }
        FcPatternDestroy(font);
    }

    FcPatternDestroy(pattern);

    return fontFile;
}

unsigned char* systemFont(const std::string& _name, const std::string& _weight, const std::string& _face, size_t* _size) {
    std::string path = fontPath(_name, _weight, _face);

    if (path.empty()) { return nullptr; }

    return bytesFromFile(path.c_str(), *_size);
}

unsigned char* bytesFromFile(const char* _path, size_t& _size) {

    if (!_path || strlen(_path) == 0) { return nullptr; }

    std::ifstream resource(_path, std::ifstream::ate | std::ifstream::binary);

    if(!resource.is_open()) {
        logMsg("Failed to read file at path: %s\n", _path);
        _size = 0;
        return nullptr;
    }

    _size = resource.tellg();

    resource.seekg(std::ifstream::beg);

    char* cdata = (char*) malloc(sizeof(char) * (_size));

    resource.read(cdata, _size);
    resource.close();

    return reinterpret_cast<unsigned char *>(cdata);
}

void setCurrentThreadPriority(int priority){
    int tid = syscall(SYS_gettid);
    //int  p1 = getpriority(PRIO_PROCESS, tid);

    setpriority(PRIO_PROCESS, tid, priority);

    //int  p2 = getpriority(PRIO_PROCESS, tid);
    //logMsg("set niceness: %d -> %d\n", p1, p2);
}

void initGLExtensions() {
     // glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArray");
     // glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArrays");
     // glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArrays");
}
<commit_msg>Fix system fonts on tizen<commit_after>#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <memory>
#include <algorithm>
#include <vector>

#include "platform_tizen.h"
#include "platform_gl.h"
#include "urlWorker.h"

#include "log.h"

#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/syscall.h>

#include <fontconfig.h>
#include <dlog.h>

#define NUM_WORKERS 4

static bool s_isContinuousRendering = false;
static std::function<void()> s_renderCallbackFunction = nullptr;

static std::vector<std::string> s_fallbackFonts;
static FcConfig* s_fcConfig = nullptr;

static UrlWorker s_workers;

bool startUrlRequest(const std::string& _url, UrlCallback _callback) {
    s_workers.enqueue(std::make_unique<UrlTask>(_url, _callback));
    return true;
}

void cancelUrlRequest(const std::string& _url) {
}

void initUrlRequests(const char* proxyAddress) {
    s_workers.start(4, proxyAddress);
}

void stopUrlRequests() {
    s_workers.stop();
}

static bool s_update = false;
#ifdef  LOG_TAG
#undef  LOG_TAG
#endif
#define LOG_TAG "Tangram"

void logMsg(const char* fmt, ...) {

    va_list vl;
    va_start(vl, fmt);
    dlog_vprint(DLOG_WARN, LOG_TAG, fmt, vl);
    va_end(vl);
}

void setRenderCallbackFunction(std::function<void()> callback) {
    s_renderCallbackFunction = callback;
}

void setEvasGlAPI(Evas_GL_API *glApi) {
    __evas_gl_glapi = glApi;
}

void requestRender() {
    s_update = true;
    if (s_renderCallbackFunction) {
        s_renderCallbackFunction();
    }
}

bool shouldRender() {
    bool update = s_update;
    s_update = false;
    return update;
}

void setContinuousRendering(bool _isContinuous) {

    s_isContinuousRendering = _isContinuous;

}

bool isContinuousRendering() {

    return s_isContinuousRendering;

}

std::string stringFromFile(const char* _path) {

    size_t length = 0;
    unsigned char* bytes = bytesFromFile(_path, length);

    std::string out(reinterpret_cast<char*>(bytes), length);
    free(bytes);

    return out;
}

void initPlatformFontSetup() {

    static bool s_platformFontsInit = false;
    if (s_platformFontsInit) { return; }

    s_fcConfig = FcInitLoadConfigAndFonts();

    std::string style = "Regular";

    FcStrSet* fcLangs = FcGetLangs();
    FcStrList* fcLangList = FcStrListCreate(fcLangs);
    FcChar8* fcLang;
    while ((fcLang = FcStrListNext(fcLangList))) {
        FcValue fcStyleValue, fcLangValue;

        fcStyleValue.type = fcLangValue.type = FcType::FcTypeString;
        fcStyleValue.u.s = reinterpret_cast<const FcChar8*>(style.c_str());
        fcLangValue.u.s = fcLang;

        // create a pattern with style and family font properties
        FcPattern* pat = FcPatternCreate();

        FcPatternAdd(pat, FC_STYLE, fcStyleValue, true);
        FcPatternAdd(pat, FC_LANG, fcLangValue, true);
        //FcPatternPrint(pat);

        FcConfigSubstitute(s_fcConfig, pat, FcMatchPattern);
        FcDefaultSubstitute(pat);

        FcResult res;
        FcPattern* font = FcFontMatch(s_fcConfig, pat, &res);
        if (font) {
            FcChar8* file = nullptr;
            if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
                // Make sure this font file is not previously added.
                if (std::find(s_fallbackFonts.begin(), s_fallbackFonts.end(),
                              reinterpret_cast<char*>(file)) == s_fallbackFonts.end()) {
                    s_fallbackFonts.emplace_back(reinterpret_cast<char*>(file));
                }
            }
            FcPatternDestroy(font);
        }
        FcPatternDestroy(pat);
    }
    FcStrListDone(fcLangList);
    s_platformFontsInit = true;
}

std::vector<FontSourceHandle> systemFontFallbacksHandle() {

    initPlatformFontSetup();

    std::vector<FontSourceHandle> handles;

    for (auto& path : s_fallbackFonts) {
        FontSourceHandle fontSourceHandle = [&](size_t* _size) -> unsigned char* {
            LOG("Loading font %s", path.c_str());

            auto cdata = bytesFromFile(path.c_str(), *_size);

            return cdata;
        };

        handles.push_back(fontSourceHandle);
    }

    return handles;
}

std::string fontPath(const std::string& _name, const std::string& _weight,
                           const std::string& _face) {

    initPlatformFontSetup();

    if (!s_fcConfig) {
        return "";
    }

    std::string fontFile = "";
    FcValue fcFamily, fcFace, fcWeight;

    fcFamily.type = fcFace.type = fcWeight.type = FcType::FcTypeString;
    fcFamily.u.s = reinterpret_cast<const FcChar8*>(_name.c_str());
    fcWeight.u.s = reinterpret_cast<const FcChar8*>(_weight.c_str());
    fcFace.u.s = reinterpret_cast<const FcChar8*>(_face.c_str());

    // Create a pattern with family, style and weight font properties
    FcPattern* pattern = FcPatternCreate();

    FcPatternAdd(pattern, FC_FAMILY, fcFamily, true);
    FcPatternAdd(pattern, FC_STYLE, fcFace, true);
    FcPatternAdd(pattern, FC_WEIGHT, fcWeight, true);
    //FcPatternPrint(pattern);

    FcConfigSubstitute(s_fcConfig, pattern, FcMatchPattern);
    FcDefaultSubstitute(pattern);

    FcResult res;
    FcPattern* font = FcFontMatch(s_fcConfig, pattern, &res);
    if (font) {
        FcChar8* file = nullptr;
        FcChar8* fontFamily = nullptr;
        if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch &&
            FcPatternGetString(font, FC_FAMILY, 0, &fontFamily) == FcResultMatch) {
            // We do not want the "best" match, but an "exact" or at least the same "family" match
            // We have fallbacks to cover rest here.
            if (strcmp(reinterpret_cast<const char*>(fontFamily), _name.c_str()) == 0) {
                fontFile = reinterpret_cast<const char*>(file);
            }
        }
        FcPatternDestroy(font);
    }

    FcPatternDestroy(pattern);

    return fontFile;
}

unsigned char* systemFont(const std::string& _name, const std::string& _weight, const std::string& _face, size_t* _size) {
    std::string path = fontPath(_name, _weight, _face);

    if (path.empty()) { return nullptr; }

    return bytesFromFile(path.c_str(), *_size);
}

unsigned char* bytesFromFile(const char* _path, size_t& _size) {

    if (!_path || strlen(_path) == 0) { return nullptr; }

    std::ifstream resource(_path, std::ifstream::ate | std::ifstream::binary);

    if(!resource.is_open()) {
        logMsg("Failed to read file at path: %s\n", _path);
        _size = 0;
        return nullptr;
    }

    _size = resource.tellg();

    resource.seekg(std::ifstream::beg);

    char* cdata = (char*) malloc(sizeof(char) * (_size));

    resource.read(cdata, _size);
    resource.close();

    return reinterpret_cast<unsigned char *>(cdata);
}

void setCurrentThreadPriority(int priority){
    int tid = syscall(SYS_gettid);
    //int  p1 = getpriority(PRIO_PROCESS, tid);

    setpriority(PRIO_PROCESS, tid, priority);

    //int  p2 = getpriority(PRIO_PROCESS, tid);
    //logMsg("set niceness: %d -> %d\n", p1, p2);
}

void initGLExtensions() {
     // glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYPROC)glfwGetProcAddress("glBindVertexArray");
     // glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSPROC)glfwGetProcAddress("glDeleteVertexArrays");
     // glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSPROC)glfwGetProcAddress("glGenVertexArrays");
}
<|endoftext|>


<commit_before>//
//  Sequence.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 29/04/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#include "Sequence.hpp"

using namespace InstructionSet::M68k;

template <Step... T> struct Steps {
	static constexpr uint16_t value = 0;
};

template <Step F, Step... T> struct Steps<F, T...> {
	static constexpr uint16_t value = uint16_t(F) | uint16_t(Steps<T...>::value << 3);
};

template<Model model> uint16_t Sequence<model>::steps_for(Operation operation) {
	switch(operation) {
		// This handles a NOP, and not much else.
		default: return 0;

		//
		// Single operand, read-modify-write.
		//
		case Operation::NBCD:	return Steps<
			Step::FetchOp1,
			Step::Perform,
			Step::StoreOp1
		>::value;

		//
		// Two operand, read-write.
		//
		case Operation::MOVEb: 	case Operation::MOVEw: 	case Operation::MOVEl:
		case Operation::MOVEAw:	case Operation::MOVEAl:
		return Steps<
			Step::FetchOp1,
			Step::Perform,
			Step::StoreOp2
		>::value;

		//
		// Two operand, read-modify-write.
		//
		case Operation::ABCD:	case Operation::SBCD:
		case Operation::ADDb: 	case Operation::ADDw: 	case Operation::ADDl:
		case Operation::ADDAw:	case Operation::ADDAl:
		case Operation::ADDXb: 	case Operation::ADDXw: 	case Operation::ADDXl:
		case Operation::SUBb: 	case Operation::SUBw: 	case Operation::SUBl:
		case Operation::SUBAw:	case Operation::SUBAl:
		case Operation::SUBXb: 	case Operation::SUBXw: 	case Operation::SUBXl:
		return Steps<
			Step::FetchOp1,
			Step::FetchOp2,
			Step::Perform,
			Step::StoreOp2
		>::value;
	}
}

template<Model model> Sequence<model>::Sequence(Operation operation) : steps_(steps_for(operation)) {}

template class InstructionSet::M68k::Sequence<Model::M68000>;
template class InstructionSet::M68k::Sequence<Model::M68010>;
template class InstructionSet::M68k::Sequence<Model::M68020>;
template class InstructionSet::M68k::Sequence<Model::M68030>;
template class InstructionSet::M68k::Sequence<Model::M68040>;
<commit_msg>Attempt to game out LEA, PEA. Add various special MOVEs.<commit_after>//
//  Sequence.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 29/04/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#include "Sequence.hpp"

using namespace InstructionSet::M68k;

template <Step... T> struct Steps {
	static constexpr uint16_t value = 0;
};

template <Step F, Step... T> struct Steps<F, T...> {
	static constexpr uint16_t value = uint16_t(F) | uint16_t(Steps<T...>::value << 3);
};

template<Model model> uint16_t Sequence<model>::steps_for(Operation operation) {
	switch(operation) {
		// This handles a NOP, and not much else.
		default: return 0;

		//
		// No operands that require fetching.
		//
		case Operation::LEA:
		return Steps<
			Step::Perform
		>::value;

		//
		// No logic, custom bus activity required.
		//
		case Operation::PEA:
		return Steps<
			Step::SpecificBusActivity
		>::value;

		//
		// Single operand, read.
		//
		case Operation::MOVEtoSR:	case Operation::MOVEtoCCR:	case Operation::MOVEtoUSP:
		case Operation::ORItoSR:	case Operation::ORItoCCR:
		case Operation::ANDItoSR:	case Operation::ANDItoCCR:
		case Operation::EORItoSR:	case Operation::EORItoCCR:
		return Steps<
			Step::FetchOp1,
			Step::Perform
		>::value;

		//
		// Single operand, write.
		//
		case Operation::MOVEfromSR:	case Operation::MOVEfromUSP:
		return Steps<
			Step::Perform,
			Step::StoreOp1
		>::value;

		//
		// Single operand, read-modify-write.
		//
		case Operation::NBCD:	return Steps<
			Step::FetchOp1,
			Step::Perform,
			Step::StoreOp1
		>::value;

		//
		// Two operand, read-write.
		//
		case Operation::MOVEb: 	case Operation::MOVEw: 	case Operation::MOVEl:
		case Operation::MOVEAw:	case Operation::MOVEAl:
		return Steps<
			Step::FetchOp1,
			Step::Perform,
			Step::StoreOp2
		>::value;

		//
		// Two operand, read-modify-write.
		//
		case Operation::ABCD:	case Operation::SBCD:
		case Operation::ADDb: 	case Operation::ADDw: 	case Operation::ADDl:
		case Operation::ADDAw:	case Operation::ADDAl:
		case Operation::ADDXb: 	case Operation::ADDXw: 	case Operation::ADDXl:
		case Operation::SUBb: 	case Operation::SUBw: 	case Operation::SUBl:
		case Operation::SUBAw:	case Operation::SUBAl:
		case Operation::SUBXb: 	case Operation::SUBXw: 	case Operation::SUBXl:
		return Steps<
			Step::FetchOp1,
			Step::FetchOp2,
			Step::Perform,
			Step::StoreOp2
		>::value;
	}
}

template<Model model> Sequence<model>::Sequence(Operation operation) : steps_(steps_for(operation)) {}

template class InstructionSet::M68k::Sequence<Model::M68000>;
template class InstructionSet::M68k::Sequence<Model::M68010>;
template class InstructionSet::M68k::Sequence<Model::M68020>;
template class InstructionSet::M68k::Sequence<Model::M68030>;
template class InstructionSet::M68k::Sequence<Model::M68040>;
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "AcquisitionWidget.h"

#include "ui_AcquisitionWidget.h"

#include "AcquisitionClient.h"
#include "ActiveObjects.h"

#include <pqApplicationCore.h>
#include <pqSettings.h>
#include <vtkSMProxy.h>

#include <vtkCamera.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkImageData.h>
#include <vtkImageProperty.h>
#include <vtkImageSlice.h>
#include <vtkImageSliceMapper.h>
#include <vtkInteractorStyleRubberBand2D.h>
#include <vtkRenderer.h>
#include <vtkScalarsToColors.h>
#include <vtkTIFFReader.h>

#include <QBuffer>
#include <QCloseEvent>
#include <QDebug>
#include <QDir>
#include <QFile>

namespace tomviz {

AcquisitionWidget::AcquisitionWidget(QWidget* parent)
  : QWidget(parent), m_ui(new Ui::AcquisitionWidget),
    m_client(new AcquisitionClient("http://localhost:8080/acquisition", this))
{
  m_ui->setupUi(this);
  this->setWindowFlags(Qt::Dialog);

  connect(m_ui->connectButton, SIGNAL(clicked(bool)), SLOT(connectToServer()));
  connect(m_ui->previewButton, SIGNAL(clicked(bool)), SLOT(setTiltAngle()));

  vtkNew<vtkGenericOpenGLRenderWindow> window;
  m_ui->imageWidget->SetRenderWindow(window.Get());
  m_ui->imageWidget->GetRenderWindow()->AddRenderer(m_renderer.Get());
  m_ui->imageWidget->GetInteractor()->SetInteractorStyle(
    m_defaultInteractorStyle.Get());
  m_defaultInteractorStyle->SetRenderOnMouseMove(true);

  m_renderer->SetBackground(1.0, 1.0, 1.0);
  m_renderer->SetViewport(0.0, 0.0, 1.0, 1.0);

  readSettings();
}

AcquisitionWidget::~AcquisitionWidget() = default;

void AcquisitionWidget::closeEvent(QCloseEvent* event)
{
  writeSettings();
  event->accept();
}

void AcquisitionWidget::readSettings()
{
  auto settings = pqApplicationCore::instance()->settings();
  if (!settings->contains("acquisition/geometry")) {
    return;
  }
  settings->beginGroup("acquisition");
  setGeometry(settings->value("geometry").toRect());
  m_ui->splitter->restoreState(settings->value("splitterSizes").toByteArray());
  m_ui->hostnameEdit->setText(
    settings->value("hostname", "localhost").toString());
  m_ui->portEdit->setText(settings->value("port", "8080").toString());
  settings->endGroup();
}

void AcquisitionWidget::writeSettings()
{
  auto settings = pqApplicationCore::instance()->settings();
  settings->beginGroup("acquisition");
  settings->setValue("geometry", geometry());
  settings->setValue("splitterSizes", m_ui->splitter->saveState());
  settings->setValue("hostname", m_ui->hostnameEdit->text());
  settings->setValue("port", m_ui->portEdit->text());
  settings->endGroup();
}

void AcquisitionWidget::connectToServer()
{
  m_ui->statusEdit->setText("Attempting to connect to server...");
  m_client->setUrl("http://" + m_ui->hostnameEdit->text() + ":" +
                   m_ui->portEdit->text() + "/acquisition");
  auto request = m_client->connect(QJsonObject());
  connect(request, SIGNAL(finished(QJsonValue)), SLOT(onConnect()));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::onConnect()
{
  m_ui->statusEdit->setText("Connected to " + m_client->url() + "!!!");
  m_ui->connectButton->setEnabled(false);
  m_ui->disconnectButton->setEnabled(true);
  setAcquireParameters();
}

void AcquisitionWidget::disconnectFromServer()
{
  m_ui->statusEdit->setText("Disconnecting");
  auto request = m_client->disconnect(QJsonObject());
  connect(request, SIGNAL(finished(QJsonValue)), SLOT(onDisconnect()));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::onDisconnect()
{
  m_ui->statusEdit->setText("Disconnected");
  m_ui->connectButton->setEnabled(true);
  m_ui->disconnectButton->setEnabled(false);
}

void AcquisitionWidget::setAcquireParameters()
{
  QJsonObject params;
  auto request = m_client->acquisition_params(params);
  connect(request, SIGNAL(finished(QJsonValue)),
          SLOT(acquireParameterResponse(QJsonValue)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::acquireParameterResponse(const QJsonValue& result)
{
  if (result.isObject()) {
    auto resultObject = result.toObject();
    if (resultObject.contains("units") && resultObject["units"].isString()) {
      m_units = resultObject["units"].toString();
    }
    // Careful, at least in the impllementation examinend, X/Y are in metres.
    if (resultObject.contains("calX") && resultObject["calX"].isDouble()) {
      m_calX = resultObject["calX"].toDouble();
    }
    if (resultObject.contains("calY") && resultObject["calY"].isDouble()) {
      m_calX = resultObject["calY"].toDouble();
    }
    m_ui->statusEdit->setText("Pixel dimensionality received");
    QString pixelSize = QString::number(m_calX * 1e9) + " x " +
                        QString::number(m_calY * 1e9) + " nm";
    m_ui->pixelSize->setText(pixelSize);
  }
}

void AcquisitionWidget::setTiltAngle()
{
  QJsonObject params;
  params["angle"] = m_ui->tiltAngleSpinBox->value();
  auto request = m_client->tilt_params(params);
  connect(request, SIGNAL(finished(QJsonValue)),
          SLOT(acquirePreview(QJsonValue)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);

  m_ui->previewButton->setEnabled(false);
  m_ui->acquireButton->setEnabled(false);
}

void AcquisitionWidget::acquirePreview(const QJsonValue& result)
{
  // This should be the actual angle the stage is at.
  if (result.isDouble()) {
    m_tiltAngle = result.toDouble(-69.99);
    m_ui->tiltAngle->setText(QString::number(result.toDouble(-69.99), 'g', 2));
  }

  auto request = m_client->preview_scan();
  connect(request, SIGNAL(finished(QString, QByteArray)),
          SLOT(previewReady(QString, QByteArray)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::previewReady(QString mimeType, QByteArray result)
{
  if (mimeType != "image/tiff") {
    qDebug() << "image/tiff is the only supported mime type right now.\n"
             << mimeType << "\n";
    return;
  }

  QDir dir(QDir::homePath() + "/tomviz-data");
  if (!dir.exists()) {
    dir.mkpath(dir.path());
  }

  QString path = "/tomviz_";

  if (m_tiltAngle > 0.0) {
    path.append('+');
  }
  path.append(QString::number(m_tiltAngle, 'g', 2));
  path.append(".tiff");

  QFile file(dir.path() + path);
  file.open(QIODevice::WriteOnly);
  file.write(result);
  qDebug() << "Data file:" << file.fileName();
  file.close();

  vtkNew<vtkTIFFReader> reader;
  reader->SetFileName(file.fileName().toLatin1());
  reader->Update();
  m_imageData = reader->GetOutput();
  m_imageSlice->GetProperty()->SetInterpolationTypeToNearest();
  m_imageSliceMapper->SetInputData(m_imageData.Get());
  m_imageSliceMapper->Update();
  m_imageSlice->SetMapper(m_imageSliceMapper.Get());
  m_renderer->AddViewProp(m_imageSlice.Get());
  resetCamera();
  m_ui->imageWidget->update();

  if (ActiveObjects::instance().activeDataSource()) {
    auto proxy = ActiveObjects::instance().activeDataSource()->colorMap();
    m_lut = vtkScalarsToColors::SafeDownCast(proxy->GetClientSideObject());
  } else {
    //    m_lut = vtkSmartPointer<vtkScalarsToColors>::New();
  }
  if (m_lut) {
    m_imageSlice->GetProperty()->SetLookupTable(m_lut.Get());
  }

  m_ui->previewButton->setEnabled(true);
  m_ui->acquireButton->setEnabled(true);
}

void AcquisitionWidget::resetCamera()
{
  vtkCamera* camera = m_renderer->GetActiveCamera();
  double* bounds = m_imageData->GetBounds();
  vtkVector3d point;
  point[0] = 0.5 * (bounds[0] + bounds[1]);
  point[1] = 0.5 * (bounds[2] + bounds[3]);
  point[2] = 0.5 * (bounds[4] + bounds[5]);
  camera->SetFocalPoint(point.GetData());
  point[2] += 50 + 0.5 * (bounds[4] + bounds[5]);
  camera->SetPosition(point.GetData());
  camera->SetViewUp(0.0, 1.0, 0.0);
  camera->ParallelProjectionOn();
  double parallelScale;
  if (bounds[1] - bounds[0] < bounds[3] - bounds[2]) {
    parallelScale = 0.5 * (bounds[3] - bounds[2] + 1);
  } else {
    parallelScale = 0.5 * (bounds[1] - bounds[0] + 1);
  }
  camera->SetParallelScale(parallelScale);
  double clippingRange[2];
  camera->GetClippingRange(clippingRange);
  clippingRange[1] = clippingRange[0] + (bounds[5] - bounds[4] + 50);
  camera->SetClippingRange(clippingRange);
}

void AcquisitionWidget::onError(const QString& errorMessage,
                                const QJsonValue& errorData)
{
  qDebug() << errorMessage;
  qDebug() << errorData;
}
}
<commit_msg>Connect up the disconnect button<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "AcquisitionWidget.h"

#include "ui_AcquisitionWidget.h"

#include "AcquisitionClient.h"
#include "ActiveObjects.h"

#include <pqApplicationCore.h>
#include <pqSettings.h>
#include <vtkSMProxy.h>

#include <vtkCamera.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkImageData.h>
#include <vtkImageProperty.h>
#include <vtkImageSlice.h>
#include <vtkImageSliceMapper.h>
#include <vtkInteractorStyleRubberBand2D.h>
#include <vtkRenderer.h>
#include <vtkScalarsToColors.h>
#include <vtkTIFFReader.h>

#include <QBuffer>
#include <QCloseEvent>
#include <QDebug>
#include <QDir>
#include <QFile>

namespace tomviz {

AcquisitionWidget::AcquisitionWidget(QWidget* parent)
  : QWidget(parent), m_ui(new Ui::AcquisitionWidget),
    m_client(new AcquisitionClient("http://localhost:8080/acquisition", this))
{
  m_ui->setupUi(this);
  this->setWindowFlags(Qt::Dialog);

  connect(m_ui->connectButton, SIGNAL(clicked(bool)), SLOT(connectToServer()));
  connect(m_ui->disconnectButton, SIGNAL(clicked(bool)),
          SLOT(disconnectFromServer()));
  connect(m_ui->previewButton, SIGNAL(clicked(bool)), SLOT(setTiltAngle()));

  vtkNew<vtkGenericOpenGLRenderWindow> window;
  m_ui->imageWidget->SetRenderWindow(window.Get());
  m_ui->imageWidget->GetRenderWindow()->AddRenderer(m_renderer.Get());
  m_ui->imageWidget->GetInteractor()->SetInteractorStyle(
    m_defaultInteractorStyle.Get());
  m_defaultInteractorStyle->SetRenderOnMouseMove(true);

  m_renderer->SetBackground(1.0, 1.0, 1.0);
  m_renderer->SetViewport(0.0, 0.0, 1.0, 1.0);

  readSettings();
}

AcquisitionWidget::~AcquisitionWidget() = default;

void AcquisitionWidget::closeEvent(QCloseEvent* event)
{
  writeSettings();
  event->accept();
}

void AcquisitionWidget::readSettings()
{
  auto settings = pqApplicationCore::instance()->settings();
  if (!settings->contains("acquisition/geometry")) {
    return;
  }
  settings->beginGroup("acquisition");
  setGeometry(settings->value("geometry").toRect());
  m_ui->splitter->restoreState(settings->value("splitterSizes").toByteArray());
  m_ui->hostnameEdit->setText(
    settings->value("hostname", "localhost").toString());
  m_ui->portEdit->setText(settings->value("port", "8080").toString());
  settings->endGroup();
}

void AcquisitionWidget::writeSettings()
{
  auto settings = pqApplicationCore::instance()->settings();
  settings->beginGroup("acquisition");
  settings->setValue("geometry", geometry());
  settings->setValue("splitterSizes", m_ui->splitter->saveState());
  settings->setValue("hostname", m_ui->hostnameEdit->text());
  settings->setValue("port", m_ui->portEdit->text());
  settings->endGroup();
}

void AcquisitionWidget::connectToServer()
{
  m_ui->statusEdit->setText("Attempting to connect to server...");
  m_client->setUrl("http://" + m_ui->hostnameEdit->text() + ":" +
                   m_ui->portEdit->text() + "/acquisition");
  auto request = m_client->connect(QJsonObject());
  connect(request, SIGNAL(finished(QJsonValue)), SLOT(onConnect()));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::onConnect()
{
  m_ui->statusEdit->setText("Connected to " + m_client->url() + "!!!");
  m_ui->connectButton->setEnabled(false);
  m_ui->disconnectButton->setEnabled(true);
  setAcquireParameters();
}

void AcquisitionWidget::disconnectFromServer()
{
  m_ui->statusEdit->setText("Disconnecting");
  auto request = m_client->disconnect(QJsonObject());
  connect(request, SIGNAL(finished(QJsonValue)), SLOT(onDisconnect()));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::onDisconnect()
{
  m_ui->statusEdit->setText("Disconnected");
  m_ui->connectButton->setEnabled(true);
  m_ui->disconnectButton->setEnabled(false);
}

void AcquisitionWidget::setAcquireParameters()
{
  QJsonObject params;
  auto request = m_client->acquisition_params(params);
  connect(request, SIGNAL(finished(QJsonValue)),
          SLOT(acquireParameterResponse(QJsonValue)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::acquireParameterResponse(const QJsonValue& result)
{
  if (result.isObject()) {
    auto resultObject = result.toObject();
    if (resultObject.contains("units") && resultObject["units"].isString()) {
      m_units = resultObject["units"].toString();
    }
    // Careful, at least in the impllementation examinend, X/Y are in metres.
    if (resultObject.contains("calX") && resultObject["calX"].isDouble()) {
      m_calX = resultObject["calX"].toDouble();
    }
    if (resultObject.contains("calY") && resultObject["calY"].isDouble()) {
      m_calX = resultObject["calY"].toDouble();
    }
    m_ui->statusEdit->setText("Pixel dimensionality received");
    QString pixelSize = QString::number(m_calX * 1e9) + " x " +
                        QString::number(m_calY * 1e9) + " nm";
    m_ui->pixelSize->setText(pixelSize);
  }
}

void AcquisitionWidget::setTiltAngle()
{
  QJsonObject params;
  params["angle"] = m_ui->tiltAngleSpinBox->value();
  auto request = m_client->tilt_params(params);
  connect(request, SIGNAL(finished(QJsonValue)),
          SLOT(acquirePreview(QJsonValue)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);

  m_ui->previewButton->setEnabled(false);
  m_ui->acquireButton->setEnabled(false);
}

void AcquisitionWidget::acquirePreview(const QJsonValue& result)
{
  // This should be the actual angle the stage is at.
  if (result.isDouble()) {
    m_tiltAngle = result.toDouble(-69.99);
    m_ui->tiltAngle->setText(QString::number(result.toDouble(-69.99), 'g', 2));
  }

  auto request = m_client->preview_scan();
  connect(request, SIGNAL(finished(QString, QByteArray)),
          SLOT(previewReady(QString, QByteArray)));
  connect(request, &AcquisitionClientRequest::error, this,
          &AcquisitionWidget::onError);
}

void AcquisitionWidget::previewReady(QString mimeType, QByteArray result)
{
  if (mimeType != "image/tiff") {
    qDebug() << "image/tiff is the only supported mime type right now.\n"
             << mimeType << "\n";
    return;
  }

  QDir dir(QDir::homePath() + "/tomviz-data");
  if (!dir.exists()) {
    dir.mkpath(dir.path());
  }

  QString path = "/tomviz_";

  if (m_tiltAngle > 0.0) {
    path.append('+');
  }
  path.append(QString::number(m_tiltAngle, 'g', 2));
  path.append(".tiff");

  QFile file(dir.path() + path);
  file.open(QIODevice::WriteOnly);
  file.write(result);
  qDebug() << "Data file:" << file.fileName();
  file.close();

  vtkNew<vtkTIFFReader> reader;
  reader->SetFileName(file.fileName().toLatin1());
  reader->Update();
  m_imageData = reader->GetOutput();
  m_imageSlice->GetProperty()->SetInterpolationTypeToNearest();
  m_imageSliceMapper->SetInputData(m_imageData.Get());
  m_imageSliceMapper->Update();
  m_imageSlice->SetMapper(m_imageSliceMapper.Get());
  m_renderer->AddViewProp(m_imageSlice.Get());
  resetCamera();
  m_ui->imageWidget->update();

  if (ActiveObjects::instance().activeDataSource()) {
    auto proxy = ActiveObjects::instance().activeDataSource()->colorMap();
    m_lut = vtkScalarsToColors::SafeDownCast(proxy->GetClientSideObject());
  } else {
    //    m_lut = vtkSmartPointer<vtkScalarsToColors>::New();
  }
  if (m_lut) {
    m_imageSlice->GetProperty()->SetLookupTable(m_lut.Get());
  }

  m_ui->previewButton->setEnabled(true);
  m_ui->acquireButton->setEnabled(true);
}

void AcquisitionWidget::resetCamera()
{
  vtkCamera* camera = m_renderer->GetActiveCamera();
  double* bounds = m_imageData->GetBounds();
  vtkVector3d point;
  point[0] = 0.5 * (bounds[0] + bounds[1]);
  point[1] = 0.5 * (bounds[2] + bounds[3]);
  point[2] = 0.5 * (bounds[4] + bounds[5]);
  camera->SetFocalPoint(point.GetData());
  point[2] += 50 + 0.5 * (bounds[4] + bounds[5]);
  camera->SetPosition(point.GetData());
  camera->SetViewUp(0.0, 1.0, 0.0);
  camera->ParallelProjectionOn();
  double parallelScale;
  if (bounds[1] - bounds[0] < bounds[3] - bounds[2]) {
    parallelScale = 0.5 * (bounds[3] - bounds[2] + 1);
  } else {
    parallelScale = 0.5 * (bounds[1] - bounds[0] + 1);
  }
  camera->SetParallelScale(parallelScale);
  double clippingRange[2];
  camera->GetClippingRange(clippingRange);
  clippingRange[1] = clippingRange[0] + (bounds[5] - bounds[4] + 50);
  camera->SetClippingRange(clippingRange);
}

void AcquisitionWidget::onError(const QString& errorMessage,
                                const QJsonValue& errorData)
{
  qDebug() << errorMessage;
  qDebug() << errorData;
}
}
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "vtkChartHistogram.h"

#include "vtkAxis.h"
#include "vtkCommand.h"
#include "vtkContext2D.h"
#include "vtkContextMouseEvent.h"
#include "vtkContextScene.h"
#include "vtkObjectFactory.h"
#include "vtkPen.h"
#include "vtkPlot.h"
#include "vtkPlotBar.h"
#include "vtkTransform2D.h"

//-----------------------------------------------------------------------------
class vtkHistogramMarker : public vtkPlot
{
public:
  static vtkHistogramMarker * New();
  double PositionX;

  bool Paint(vtkContext2D *painter) override
  {
    vtkNew<vtkPen> pen;
    pen->SetColor(255, 0, 0, 255);
    pen->SetWidth(2.0);
    painter->ApplyPen(pen.Get());
    painter->DrawLine(PositionX, 0, PositionX, 1e9);
    return true;
  }
};
vtkStandardNewMacro(vtkHistogramMarker)

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartHistogram)

vtkChartHistogram::vtkChartHistogram()
{
  this->SetBarWidthFraction(1.0);
  this->SetRenderEmpty(true);
  this->SetAutoAxes(false);
  this->ZoomWithMouseWheelOff();
  this->GetAxis(vtkAxis::LEFT)->SetTitle("");
  this->GetAxis(vtkAxis::BOTTOM)->SetTitle("");
  this->GetAxis(vtkAxis::BOTTOM)->SetBehavior(vtkAxis::FIXED);
  this->GetAxis(vtkAxis::BOTTOM)->SetRange(0, 255);
  this->GetAxis(vtkAxis::LEFT)->SetBehavior(vtkAxis::FIXED);
  this->GetAxis(vtkAxis::LEFT)->SetRange(0.0001, 10);
  this->GetAxis(vtkAxis::LEFT)->SetMinimumLimit(1);
  this->GetAxis(vtkAxis::LEFT)->SetLogScale(true);
}

//-----------------------------------------------------------------------------
bool vtkChartHistogram::MouseDoubleClickEvent(const vtkContextMouseEvent &m)
{
  // Determine the location of the click, and emit something we can listen to!
  vtkPlotBar *histo = nullptr;
  if (this->GetNumberOfPlots() > 0)
  {
    histo = vtkPlotBar::SafeDownCast(this->GetPlot(0));
  }
  if (!histo)
  {
    return false;
  }
  this->CalculateUnscaledPlotTransform(histo->GetXAxis(), histo->GetYAxis(),
                                       this->Transform.Get());
  vtkVector2f pos;
  this->Transform->InverseTransformPoints(m.GetScenePos().GetData(), pos.GetData(),
                                          1);
  this->PositionX = pos.GetX();
  this->Marker->PositionX = this->PositionX;
  this->Marker->Modified();
  this->Scene->SetDirty(true);
  if (this->GetNumberOfPlots() == 1)
  {
    // Work around a bug in the charts - ensure corner is invalid for the plot.
    this->Marker->SetXAxis(nullptr);
    this->Marker->SetYAxis(nullptr);
    this->AddPlot(this->Marker.Get());
  }
  this->InvokeEvent(vtkCommand::CursorChangedEvent);
  return true;
}
<commit_msg>Made the right axis visible, fixed, and go 0->1<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "vtkChartHistogram.h"

#include "vtkAxis.h"
#include "vtkCommand.h"
#include "vtkContext2D.h"
#include "vtkContextMouseEvent.h"
#include "vtkContextScene.h"
#include "vtkObjectFactory.h"
#include "vtkPen.h"
#include "vtkPlot.h"
#include "vtkPlotBar.h"
#include "vtkTransform2D.h"

//-----------------------------------------------------------------------------
class vtkHistogramMarker : public vtkPlot
{
public:
  static vtkHistogramMarker * New();
  double PositionX;

  bool Paint(vtkContext2D *painter) override
  {
    vtkNew<vtkPen> pen;
    pen->SetColor(255, 0, 0, 255);
    pen->SetWidth(2.0);
    painter->ApplyPen(pen.Get());
    painter->DrawLine(PositionX, 0, PositionX, 1e9);
    return true;
  }
};
vtkStandardNewMacro(vtkHistogramMarker)

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartHistogram)

vtkChartHistogram::vtkChartHistogram()
{
  this->SetBarWidthFraction(1.0);
  this->SetRenderEmpty(true);
  this->SetAutoAxes(false);
  this->ZoomWithMouseWheelOff();
  this->GetAxis(vtkAxis::LEFT)->SetTitle("");
  this->GetAxis(vtkAxis::BOTTOM)->SetTitle("");
  this->GetAxis(vtkAxis::BOTTOM)->SetBehavior(vtkAxis::FIXED);
  this->GetAxis(vtkAxis::BOTTOM)->SetRange(0, 255);
  this->GetAxis(vtkAxis::LEFT)->SetBehavior(vtkAxis::FIXED);
  this->GetAxis(vtkAxis::LEFT)->SetRange(0.0001, 10);
  this->GetAxis(vtkAxis::LEFT)->SetMinimumLimit(1);
  this->GetAxis(vtkAxis::LEFT)->SetLogScale(true);
  this->GetAxis(vtkAxis::RIGHT)->SetBehavior(vtkAxis::FIXED);
  this->GetAxis(vtkAxis::RIGHT)->SetRange(0.0, 1.0);
  this->GetAxis(vtkAxis::RIGHT)->SetVisible(true);
}

//-----------------------------------------------------------------------------
bool vtkChartHistogram::MouseDoubleClickEvent(const vtkContextMouseEvent &m)
{
  // Determine the location of the click, and emit something we can listen to!
  vtkPlotBar *histo = nullptr;
  if (this->GetNumberOfPlots() > 0)
  {
    histo = vtkPlotBar::SafeDownCast(this->GetPlot(0));
  }
  if (!histo)
  {
    return false;
  }
  this->CalculateUnscaledPlotTransform(histo->GetXAxis(), histo->GetYAxis(),
                                       this->Transform.Get());
  vtkVector2f pos;
  this->Transform->InverseTransformPoints(m.GetScenePos().GetData(), pos.GetData(),
                                          1);
  this->PositionX = pos.GetX();
  this->Marker->PositionX = this->PositionX;
  this->Marker->Modified();
  this->Scene->SetDirty(true);
  if (this->GetNumberOfPlots() == 1)
  {
    // Work around a bug in the charts - ensure corner is invalid for the plot.
    this->Marker->SetXAxis(nullptr);
    this->Marker->SetYAxis(nullptr);
    this->AddPlot(this->Marker.Get());
  }
  this->InvokeEvent(vtkCommand::CursorChangedEvent);
  return true;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//

#include "OpenCLFE.h"

#include "bif/bifbase.hpp"
#include "frontend.hpp"
#include "os/os.hpp"
#include "top.hpp"
#include "utils/libUtils.h"
#include "utils/options.hpp"
#include "utils/target_mappings.h"

#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/StringRef.h"

#include <string>
#include <sstream>
#include <fstream>

amdcl::ClangOCLFrontend::ClangOCLFrontend(aclCompiler* cl, aclBinary* elf,
                                          aclLogFunction log)
       : Frontend(cl, elf, log){}

/// @brief This function generates the required command-line options to
/// call the ClangOCLFE library.
int amdcl::ClangOCLFrontend::compileCommand(const std::string& src) {

  std::vector<const char*> argsToClang;
  std::string tempFileName = amd::Os::getTempFileName();
  std::string logFileName = tempFileName + ".log";
  std::string inpCLFileName = tempFileName + ".cl";
  std::string logFromClang;
  int ret = 0;

  aclBinary *elf = Elf();
  amd::option::Options* amdOpts = (amd::option::Options*)elf->options;

  // Following are the options passed to the ClangOCLFE library
  // and then to Clang itself.

  // Passing the compiler FE options to clang.
  if (amdOpts) {
    for (std::vector<std::string>::const_iterator it = amdOpts->clangOptions.begin();
         it != amdOpts->clangOptions.end(); ++it) {
      argsToClang.push_back((*it).c_str());
    }
  }

  // Other options are passed using OptionsInfo structure.
  clc2::OptionsInfo ClangOptions;

  ClangOptions.InFilename = inpCLFileName;

  // Generate target triple.
  // TODO: Refine the triple as necessary.
  uint32_t chipName = elf->target.chip_id;
  assert(chipName < familySet[elf->target.arch_id].children_size &&
         "Cannot index past end of array!");
  switch (elf->target.arch_id) {
    default:
      log_ += "\nerror: Unknown target device ID!\n";
      ret |= 1;
      return ret;
      break;
    case aclX86:
    case aclAMDIL:
    case aclHSAIL:
      // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631
      if (sizeof(void*) != 4) {
        log_ += "\nerror: 32-bit kernels not supported on a 64-bit executable\n";
        ret |= 1;
        return ret;
      }
      ClangOptions.TargetArch = llvm::Triple::spir;
      break;
    case aclX64:
    case aclAMDIL64:
    case aclHSAIL64:
      // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631
      if (sizeof(void*) != 8) {
        log_ += "\nerror: 64-bit kernels not supported on a 32-bit executable\n";
        ret |= 1;
        return ret;
      }
      ClangOptions.TargetArch = llvm::Triple::spir64;
      break;
  };

  // Copy the source to a buffer. Note that the input
  // file itself is not passed to the ClangOCLFE library. It is a passed
  // as a string for compilation.

  llvm::MemoryBuffer *srcBuffer =
       llvm::MemoryBuffer::getMemBuffer(src, inpCLFileName.c_str(),
                                        true);
  llvm::OwningPtr<llvm::MemoryBuffer> srcBufferPtr(srcBuffer);
  ClangOptions.Src.swap(srcBufferPtr);
  assert(ClangOptions.Src.get() && "ClangOCLFE: Memory Buffer"
                    " initialization error\n");

  // Set Pre-processor output if user asks for it.
  if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_I)) {
    ClangOptions.PreProcOut = amdOpts->getDumpFileName(".i");
  }

  // Set the LLVMContext for the front-end compilation.
  ClangOptions.CompilerContext = &Context();

  if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_CL)) {
    std::string inpCLFileName = amdOpts->getDumpFileName(".cl");
    std::fstream f;
    f.open(inpCLFileName.c_str(), (std::fstream::out | std::fstream::binary));
    f.write(src.data(), src.length());
    f.close();
  }

  //Start the compilation
  uint64_t start_time = 0, stop_time = 0;

    if (Options()->oVariables->EnableBuildTiming) {
    start_time = amd::Os::timeNanos();
  }

  if (
#if WITH_VERSION_0_8
      !checkFlag(aclutGetCaps(Elf()), capSaveSOURCE)
#elif WITH_VERSION_0_9
      !Options()->oVariables->BinSOURCE
#else
#error "The current version was not handled correctly here."
#endif
      ) {
    CL()->clAPI.remSec(CL(), Elf(), aclSOURCE);
  }

  // Pass OpenCL version option to Clang
  llvm::StringRef OCLVer(amdOpts->oVariables->CLStd);
  if (OCLVer.equals("CL1.2")) {
    ClangOptions.OCLVer = clc2::OCL_12;
  } else if (OCLVer.equals("CL2.0")) {
	ClangOptions.OCLVer = clc2::OCL_20;
  } else {
    llvm_unreachable("Unknown OpenCL version");
  }

  // Call the Clang Front-end to generate serialized llvm::Module
  // from the OpenCL source.
#ifdef ANDROID
  // We will not exercise Clang for RenderScript.
  log_ += "\nerror: Clang front-end compilation unsupported on Android!\n";
  ret |= 1;
  return ret;
#else
  if (!parseOCLSource(ClangOptions, argsToClang, &Source(), &logFromClang)) {
      log_ += logFromClang;
      log_ += "\nerror: Clang front-end compilation failed!\n";
      ret |= 1;
      return ret;
  }
#endif

  if (Options()->oVariables->EnableBuildTiming) {
    stop_time = amd::Os::timeNanos();
    std::stringstream tmp_ss;
    tmp_ss << "    OpenCL FE time: "
      << (stop_time - start_time)/1000ULL
      << "us\n";
    appendLogToCL(CL(), tmp_ss.str());
  }

  llvmbinary_ = loadBitcode(Source());

  if (!llvmbinary_) {
    ret |= 1;
  }

  if (!ret &&
#if WITH_VERSION_0_8
      checkFlag(aclutGetCaps(Elf()), capSaveLLVMIR)
#elif WITH_VERSION_0_9
      Options()->oVariables->BinLLVMIR
#else
#error "The current version was not handled correctly here."
#endif
      ) {
    CL()->clAPI.insSec(CL(), Elf(), Source().data(),
        Source().size(), aclLLVMIR);
  } else {
    CL()->clAPI.remSec(CL(), Elf(), aclLLVMIR);
  }
  log_ += logFromClang;
  if (isCpuTarget(Elf()->target)
      && Options()->oVariables->EnableDebug) {
    Options()->sourceFileName_ = inpCLFileName;
  } else {
    amd::Os::unlink(inpCLFileName.c_str());
  }
  return ret;
}
<commit_msg>P4 to Git Change 1058650 by shivara@shivaram_llvmmerge_dt on 2014/07/24 01:26:41<commit_after>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//

#include "OpenCLFE.h"

#include "bif/bifbase.hpp"
#include "frontend.hpp"
#include "os/os.hpp"
#include "top.hpp"
#include "utils/libUtils.h"
#include "utils/options.hpp"
#include "utils/target_mappings.h"

#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/StringRef.h"

#include <string>
#include <sstream>
#include <fstream>

amdcl::ClangOCLFrontend::ClangOCLFrontend(aclCompiler* cl, aclBinary* elf,
                                          aclLogFunction log)
       : Frontend(cl, elf, log){}

/// @brief This function generates the required command-line options to
/// call the ClangOCLFE library.
int amdcl::ClangOCLFrontend::compileCommand(const std::string& src) {

  std::vector<const char*> argsToClang;
  std::string tempFileName = amd::Os::getTempFileName();
  std::string logFileName = tempFileName + ".log";
  std::string inpCLFileName = tempFileName + ".cl";
  std::string logFromClang;
  int ret = 0;

  aclBinary *elf = Elf();
  amd::option::Options* amdOpts = (amd::option::Options*)elf->options;

  // Following are the options passed to the ClangOCLFE library
  // and then to Clang itself.

  // Passing the compiler FE options to clang.
  if (amdOpts) {
    for (std::vector<std::string>::const_iterator it = amdOpts->clangOptions.begin();
         it != amdOpts->clangOptions.end(); ++it) {
      argsToClang.push_back((*it).c_str());
    }
  }
  if (Options()->oVariables->ImageSupport) {
    argsToClang.push_back ("-D__IMAGE_SUPPORT__=1 ");
  }

  if (Options()->oVariables->FastFMA) {
    argsToClang.push_back ("-DFP_FAST_FMA=1 ");
  }

  if (Options()->oVariables->FastFMAF) {
    argsToClang.push_back ("-DFP_FAST_FMAF=1 ");
  }

  argsToClang.push_back ("-D__AMD__=1 ");

  // Other options are passed using OptionsInfo structure.
  clc2::OptionsInfo ClangOptions;

  ClangOptions.InFilename = inpCLFileName;

  // Generate target triple.
  // TODO: Refine the triple as necessary.
  uint32_t chipName = elf->target.chip_id;
  assert(chipName < familySet[elf->target.arch_id].children_size &&
         "Cannot index past end of array!");
  switch (elf->target.arch_id) {
    default:
      log_ += "\nerror: Unknown target device ID!\n";
      ret |= 1;
      return ret;
      break;
    case aclX86:
    case aclAMDIL:
    case aclHSAIL:
      // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631
      if (sizeof(void*) != 4) {
        log_ += "\nerror: 32-bit kernels not supported on a 64-bit executable\n";
        ret |= 1;
        return ret;
      }
      ClangOptions.TargetArch = llvm::Triple::spir;
      break;
    case aclX64:
    case aclAMDIL64:
    case aclHSAIL64:
      // See bug: http://ocltc.amd.com/bugs/show_bug.cgi?id=9631
      if (sizeof(void*) != 8) {
        log_ += "\nerror: 64-bit kernels not supported on a 32-bit executable\n";
        ret |= 1;
        return ret;
      }
      ClangOptions.TargetArch = llvm::Triple::spir64;
      break;
  };

  // Copy the source to a buffer. Note that the input
  // file itself is not passed to the ClangOCLFE library. It is a passed
  // as a string for compilation.

  llvm::MemoryBuffer *srcBuffer =
       llvm::MemoryBuffer::getMemBuffer(src, inpCLFileName.c_str(),
                                        true);
  llvm::OwningPtr<llvm::MemoryBuffer> srcBufferPtr(srcBuffer);
  ClangOptions.Src.swap(srcBufferPtr);
  assert(ClangOptions.Src.get() && "ClangOCLFE: Memory Buffer"
                    " initialization error\n");

  // Set Pre-processor output if user asks for it.
  if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_I)) {
    ClangOptions.PreProcOut = amdOpts->getDumpFileName(".i");
  }

  // Set the LLVMContext for the front-end compilation.
  ClangOptions.CompilerContext = &Context();

  if (amdOpts && amdOpts->isDumpFlagSet(amd::option::DUMP_CL)) {
    std::string inpCLFileName = amdOpts->getDumpFileName(".cl");
    std::fstream f;
    f.open(inpCLFileName.c_str(), (std::fstream::out | std::fstream::binary));
    f.write(src.data(), src.length());
    f.close();
  }

  //Start the compilation
  uint64_t start_time = 0, stop_time = 0;

    if (Options()->oVariables->EnableBuildTiming) {
    start_time = amd::Os::timeNanos();
  }

  if (
#if WITH_VERSION_0_8
      !checkFlag(aclutGetCaps(Elf()), capSaveSOURCE)
#elif WITH_VERSION_0_9
      !Options()->oVariables->BinSOURCE
#else
#error "The current version was not handled correctly here."
#endif
      ) {
    CL()->clAPI.remSec(CL(), Elf(), aclSOURCE);
  }

  // Pass OpenCL version option to Clang
  llvm::StringRef OCLVer(amdOpts->oVariables->CLStd);
  if (OCLVer.equals("CL1.2")) {
    ClangOptions.OCLVer = clc2::OCL_12;
  } else if (OCLVer.equals("CL2.0")) {
	ClangOptions.OCLVer = clc2::OCL_20;
  } else {
    llvm_unreachable("Unknown OpenCL version");
  }

  // Call the Clang Front-end to generate serialized llvm::Module
  // from the OpenCL source.
#ifdef ANDROID
  // We will not exercise Clang for RenderScript.
  log_ += "\nerror: Clang front-end compilation unsupported on Android!\n";
  ret |= 1;
  return ret;
#else
  if (!parseOCLSource(ClangOptions, argsToClang, &Source(), &logFromClang)) {
      log_ += logFromClang;
      log_ += "\nerror: Clang front-end compilation failed!\n";
      ret |= 1;
      return ret;
  }
#endif

  if (Options()->oVariables->EnableBuildTiming) {
    stop_time = amd::Os::timeNanos();
    std::stringstream tmp_ss;
    tmp_ss << "    OpenCL FE time: "
      << (stop_time - start_time)/1000ULL
      << "us\n";
    appendLogToCL(CL(), tmp_ss.str());
  }

  llvmbinary_ = loadBitcode(Source());

  if (!llvmbinary_) {
    ret |= 1;
  }

  if (!ret &&
#if WITH_VERSION_0_8
      checkFlag(aclutGetCaps(Elf()), capSaveLLVMIR)
#elif WITH_VERSION_0_9
      Options()->oVariables->BinLLVMIR
#else
#error "The current version was not handled correctly here."
#endif
      ) {
    CL()->clAPI.insSec(CL(), Elf(), Source().data(),
        Source().size(), aclLLVMIR);
  } else {
    CL()->clAPI.remSec(CL(), Elf(), aclLLVMIR);
  }
  log_ += logFromClang;
  if (isCpuTarget(Elf()->target)
      && Options()->oVariables->EnableDebug) {
    Options()->sourceFileName_ = inpCLFileName;
  } else {
    amd::Os::unlink(inpCLFileName.c_str());
  }
  return ret;
}
<|endoftext|>