<commit_before>#include "rdb_protocol/serialize_datum.hpp"

#include <string>
#include <vector>

#include "containers/archive/stl_types.hpp"
#include "containers/archive/versioned.hpp"
#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/error.hpp"

namespace ql {

enum class datum_serialized_type_t {
    R_ARRAY = 1,
    R_BOOL = 2,
    R_NULL = 3,
    DOUBLE = 4,
    R_OBJECT = 5,
    R_STR = 6,
    INT_NEGATIVE = 7,
    INT_POSITIVE = 8,
};

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(datum_serialized_type_t, int8_t,
                                      datum_serialized_type_t::R_ARRAY,
                                      datum_serialized_type_t::INT_POSITIVE);

void datum_serialize(write_message_t *wm, datum_serialized_type_t type) {
    serialize<cluster_version_t::LATEST_OVERALL>(wm, type);
}

MUST_USE archive_result_t datum_deserialize(read_stream_t *s,
                                            datum_serialized_type_t *type) {
    return deserialize<cluster_version_t::LATEST_OVERALL>(s, type);
}

// This looks like it duplicates code of other deserialization functions.  It does.
// Keeping this separate means that we don't have to worry about whether datum
// serialization has changed from cluster version to cluster version.

// Keep in sync with datum_serialize.
size_t datum_serialized_size(const std::vector<counted_t<const datum_t> > &v) {
    size_t ret = varint_uint64_serialized_size(v.size());
    for (auto it = v.begin(), e = v.end(); it != e; ++it) {
        ret += datum_serialized_size(*it);
    }
    return ret;
}

// Keep in sync with datum_serialized_size.
void datum_serialize(write_message_t *wm,
                     const std::vector<counted_t<const datum_t> > &v) {
    serialize_varint_uint64(wm, v.size());
    for (auto it = v.begin(), e = v.end(); it != e; ++it) {
        datum_serialize(wm, *it);
    }
}

MUST_USE archive_result_t
datum_deserialize(read_stream_t *s, std::vector<counted_t<const datum_t> > *v) {
    v->clear();

    uint64_t sz;
    archive_result_t res = deserialize_varint_uint64(s, &sz);
    if (bad(res)) { return res; }

    if (sz > std::numeric_limits<size_t>::max()) {
        return archive_result_t::RANGE_ERROR;
    }

    v->resize(sz);
    for (uint64_t i = 0; i < sz; ++i) {
        res = datum_deserialize(s, &(*v)[i]);
        if (bad(res)) { return res; }
    }

    return archive_result_t::SUCCESS;
}

size_t datum_serialized_size(const std::string &s) {
    return serialize_universal_size(s);
}
void datum_serialize(write_message_t *wm, const std::string &s) {
    serialize_universal(wm, s);
}
MUST_USE archive_result_t datum_deserialize(read_stream_t *s, std::string *out) {
    return deserialize_universal(s, out);
}

size_t datum_serialized_size(
        const std::map<std::string, counted_t<const datum_t> > &m) {
    size_t ret = varint_uint64_serialized_size(m.size());
    for (auto it = m.begin(), e = m.end(); it != e; ++it) {
        ret += datum_serialized_size(it->first);
        ret += datum_serialized_size(it->second);
    }
    return ret;
}

void datum_serialize(write_message_t *wm,
                     const std::map<std::string, counted_t<const datum_t> > &m) {
    serialize_varint_uint64(wm, m.size());
    for (auto it = m.begin(), e = m.end(); it != e; ++it) {
        datum_serialize(wm, it->first);
        datum_serialize(wm, it->second);
    }
}

MUST_USE archive_result_t datum_deserialize(
        read_stream_t *s,
        std::map<std::string, counted_t<const datum_t> > *m) {
    m->clear();

    uint64_t sz;
    archive_result_t res = deserialize_varint_uint64(s, &sz);
    if (bad(res)) { return res; }

    if (sz > std::numeric_limits<size_t>::max()) {
        return archive_result_t::RANGE_ERROR;
    }

    // Using position should make this function take linear time, not
    // sz*log(sz) time.
    auto position = m->begin();

    for (uint64_t i = 0; i < sz; ++i) {
        std::pair<std::string, counted_t<const datum_t> > p;
        res = datum_deserialize(s, &p.first);
        if (bad(res)) { return res; }
        res = datum_deserialize(s, &p.second);
        if (bad(res)) { return res; }
        position = m->insert(position, std::move(p));
    }

    return archive_result_t::SUCCESS;
}

size_t datum_serialized_size(const counted_t<const datum_t> &datum) {
    r_sanity_check(datum.has());
    size_t sz = 1; // 1 byte for the type
    switch (datum->get_type()) {
    case datum_t::R_ARRAY: {
        sz += datum_serialized_size(datum->as_array());
    } break;
    case datum_t::R_BOOL: {
        sz += serialize_universal_size_t<bool>::value;
    } break;
    case datum_t::R_NULL: break;
    case datum_t::R_NUM: {
        double d = datum->as_num();
        int64_t i;
        if (number_as_integer(d, &i)) {
            sz += varint_uint64_serialized_size(i < 0 ? -i : i);
        } else {
            sz += serialize_universal_size_t<double>::value;
        }
    } break;
    case datum_t::R_OBJECT: {
        sz += datum_serialized_size(datum->as_object());
    } break;
    case datum_t::R_STR: {
        sz += datum_serialized_size(datum->as_str());
    } break;
    case datum_t::UNINITIALIZED:  // fall through
    default:
        unreachable();
    }
    return sz;
}
void datum_serialize(write_message_t *wm, const counted_t<const datum_t> &datum) {
    r_sanity_check(datum.has());
    switch (datum->get_type()) {
    case datum_t::R_ARRAY: {
        datum_serialize(wm, datum_serialized_type_t::R_ARRAY);
        const std::vector<counted_t<const datum_t> > &value = datum->as_array();
        datum_serialize(wm, value);
    } break;
    case datum_t::R_BOOL: {
        datum_serialize(wm, datum_serialized_type_t::R_BOOL);
        bool value = datum->as_bool();
        serialize_universal(wm, value);
    } break;
    case datum_t::R_NULL: {
        datum_serialize(wm, datum_serialized_type_t::R_NULL);
    } break;
    case datum_t::R_NUM: {
        double value = datum->as_num();
        int64_t i;
        if (number_as_integer(value, &i)) {
            // We serialize the signed-zero double, -0.0, with INT_NEGATIVE.

            // so we can use `signbit` in a GCC 4.4.3-compatible way
            using namespace std;  // NOLINT(build/namespaces)
            if (signbit(value)) {
                datum_serialize(wm, datum_serialized_type_t::INT_NEGATIVE);
                serialize_varint_uint64(wm, -i);
            } else {
                datum_serialize(wm, datum_serialized_type_t::INT_POSITIVE);
                serialize_varint_uint64(wm, i);
            }
        } else {
            datum_serialize(wm, datum_serialized_type_t::DOUBLE);
            serialize_universal(wm, value);
        }
    } break;
    case datum_t::R_OBJECT: {
        datum_serialize(wm, datum_serialized_type_t::R_OBJECT);
        datum_serialize(wm, datum->as_object());
    } break;
    case datum_t::R_STR: {
        datum_serialize(wm, datum_serialized_type_t::R_STR);
        const wire_string_t &value = datum->as_str();
        datum_serialize(wm, value);
    } break;
    case datum_t::UNINITIALIZED:  // fall through
    default:
        unreachable();
    }
}
archive_result_t datum_deserialize(read_stream_t *s, counted_t<const datum_t> *datum) {
    datum_serialized_type_t type;
    archive_result_t res = datum_deserialize(s, &type);
    if (bad(res)) {
        return res;
    }

    switch (type) {
    case datum_serialized_type_t::R_ARRAY: {
        std::vector<counted_t<const datum_t> > value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_BOOL: {
        bool value;
        res = deserialize_universal(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(datum_t::R_BOOL, value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_NULL: {
        datum->reset(new datum_t(datum_t::R_NULL));
    } break;
    case datum_serialized_type_t::DOUBLE: {
        double value;
        res = deserialize_universal(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::INT_NEGATIVE:  // fall through
    case datum_serialized_type_t::INT_POSITIVE: {
        uint64_t unsigned_value;
        res = deserialize_varint_uint64(s, &unsigned_value);
        if (bad(res)) {
            return res;
        }
        if (unsigned_value > max_dbl_int) {
            return archive_result_t::RANGE_ERROR;
        }
        const double d = unsigned_value;
        double value;
        if (type == datum_serialized_type_t::INT_NEGATIVE) {
            // This might deserialize the signed-zero double, -0.0.
            value = -d;
        } else {
            value = d;
        }
        try {
            datum->reset(new datum_t(value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_OBJECT: {
        std::map<std::string, counted_t<const datum_t> > value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_STR: {
        scoped_ptr_t<wire_string_t> value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        rassert(value.has());
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    default:
        return archive_result_t::RANGE_ERROR;
    }

    return archive_result_t::SUCCESS;
}

template <cluster_version_t W>
void serialize(write_message_t *wm,
               const empty_ok_t<const counted_t<const datum_t> > &datum) {
    const counted_t<const datum_t> *pointer = datum.get();
    const bool has = pointer->has();
    serialize<W>(wm, has);
    if (has) {
        serialize<W>(wm, *pointer);
    }
}

INSTANTIATE_SERIALIZE_FOR_CLUSTER_AND_DISK(empty_ok_t<const counted_t<const datum_t> >);

template <cluster_version_t W>
archive_result_t deserialize(read_stream_t *s,
                             empty_ok_ref_t<counted_t<const datum_t> > datum) {
    bool has;
    archive_result_t res = deserialize<W>(s, &has);
    if (bad(res)) {
        return res;
    }

    counted_t<const datum_t> *pointer = datum.get();

    if (!has) {
        pointer->reset();
        return archive_result_t::SUCCESS;
    } else {
        return deserialize<W>(s, pointer);
    }
}

template archive_result_t deserialize<cluster_version_t::v1_13>(
        read_stream_t *s,
        empty_ok_ref_t<counted_t<const datum_t> > datum);
template archive_result_t deserialize<cluster_version_t::v1_13_2_is_latest>(
        read_stream_t *s,
        empty_ok_ref_t<counted_t<const datum_t> > datum);

}  // namespace ql
<commit_msg>Add an include in serialize_datum.cc.<commit_after>#include "rdb_protocol/serialize_datum.hpp"

#include <cmath>
#include <string>
#include <vector>

#include "containers/archive/stl_types.hpp"
#include "containers/archive/versioned.hpp"
#include "rdb_protocol/datum.hpp"
#include "rdb_protocol/error.hpp"

namespace ql {

enum class datum_serialized_type_t {
    R_ARRAY = 1,
    R_BOOL = 2,
    R_NULL = 3,
    DOUBLE = 4,
    R_OBJECT = 5,
    R_STR = 6,
    INT_NEGATIVE = 7,
    INT_POSITIVE = 8,
};

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(datum_serialized_type_t, int8_t,
                                      datum_serialized_type_t::R_ARRAY,
                                      datum_serialized_type_t::INT_POSITIVE);

void datum_serialize(write_message_t *wm, datum_serialized_type_t type) {
    serialize<cluster_version_t::LATEST_OVERALL>(wm, type);
}

MUST_USE archive_result_t datum_deserialize(read_stream_t *s,
                                            datum_serialized_type_t *type) {
    return deserialize<cluster_version_t::LATEST_OVERALL>(s, type);
}

// This looks like it duplicates code of other deserialization functions.  It does.
// Keeping this separate means that we don't have to worry about whether datum
// serialization has changed from cluster version to cluster version.

// Keep in sync with datum_serialize.
size_t datum_serialized_size(const std::vector<counted_t<const datum_t> > &v) {
    size_t ret = varint_uint64_serialized_size(v.size());
    for (auto it = v.begin(), e = v.end(); it != e; ++it) {
        ret += datum_serialized_size(*it);
    }
    return ret;
}

// Keep in sync with datum_serialized_size.
void datum_serialize(write_message_t *wm,
                     const std::vector<counted_t<const datum_t> > &v) {
    serialize_varint_uint64(wm, v.size());
    for (auto it = v.begin(), e = v.end(); it != e; ++it) {
        datum_serialize(wm, *it);
    }
}

MUST_USE archive_result_t
datum_deserialize(read_stream_t *s, std::vector<counted_t<const datum_t> > *v) {
    v->clear();

    uint64_t sz;
    archive_result_t res = deserialize_varint_uint64(s, &sz);
    if (bad(res)) { return res; }

    if (sz > std::numeric_limits<size_t>::max()) {
        return archive_result_t::RANGE_ERROR;
    }

    v->resize(sz);
    for (uint64_t i = 0; i < sz; ++i) {
        res = datum_deserialize(s, &(*v)[i]);
        if (bad(res)) { return res; }
    }

    return archive_result_t::SUCCESS;
}

size_t datum_serialized_size(const std::string &s) {
    return serialize_universal_size(s);
}
void datum_serialize(write_message_t *wm, const std::string &s) {
    serialize_universal(wm, s);
}
MUST_USE archive_result_t datum_deserialize(read_stream_t *s, std::string *out) {
    return deserialize_universal(s, out);
}

size_t datum_serialized_size(
        const std::map<std::string, counted_t<const datum_t> > &m) {
    size_t ret = varint_uint64_serialized_size(m.size());
    for (auto it = m.begin(), e = m.end(); it != e; ++it) {
        ret += datum_serialized_size(it->first);
        ret += datum_serialized_size(it->second);
    }
    return ret;
}

void datum_serialize(write_message_t *wm,
                     const std::map<std::string, counted_t<const datum_t> > &m) {
    serialize_varint_uint64(wm, m.size());
    for (auto it = m.begin(), e = m.end(); it != e; ++it) {
        datum_serialize(wm, it->first);
        datum_serialize(wm, it->second);
    }
}

MUST_USE archive_result_t datum_deserialize(
        read_stream_t *s,
        std::map<std::string, counted_t<const datum_t> > *m) {
    m->clear();

    uint64_t sz;
    archive_result_t res = deserialize_varint_uint64(s, &sz);
    if (bad(res)) { return res; }

    if (sz > std::numeric_limits<size_t>::max()) {
        return archive_result_t::RANGE_ERROR;
    }

    // Using position should make this function take linear time, not
    // sz*log(sz) time.
    auto position = m->begin();

    for (uint64_t i = 0; i < sz; ++i) {
        std::pair<std::string, counted_t<const datum_t> > p;
        res = datum_deserialize(s, &p.first);
        if (bad(res)) { return res; }
        res = datum_deserialize(s, &p.second);
        if (bad(res)) { return res; }
        position = m->insert(position, std::move(p));
    }

    return archive_result_t::SUCCESS;
}

size_t datum_serialized_size(const counted_t<const datum_t> &datum) {
    r_sanity_check(datum.has());
    size_t sz = 1; // 1 byte for the type
    switch (datum->get_type()) {
    case datum_t::R_ARRAY: {
        sz += datum_serialized_size(datum->as_array());
    } break;
    case datum_t::R_BOOL: {
        sz += serialize_universal_size_t<bool>::value;
    } break;
    case datum_t::R_NULL: break;
    case datum_t::R_NUM: {
        double d = datum->as_num();
        int64_t i;
        if (number_as_integer(d, &i)) {
            sz += varint_uint64_serialized_size(i < 0 ? -i : i);
        } else {
            sz += serialize_universal_size_t<double>::value;
        }
    } break;
    case datum_t::R_OBJECT: {
        sz += datum_serialized_size(datum->as_object());
    } break;
    case datum_t::R_STR: {
        sz += datum_serialized_size(datum->as_str());
    } break;
    case datum_t::UNINITIALIZED:  // fall through
    default:
        unreachable();
    }
    return sz;
}
void datum_serialize(write_message_t *wm, const counted_t<const datum_t> &datum) {
    r_sanity_check(datum.has());
    switch (datum->get_type()) {
    case datum_t::R_ARRAY: {
        datum_serialize(wm, datum_serialized_type_t::R_ARRAY);
        const std::vector<counted_t<const datum_t> > &value = datum->as_array();
        datum_serialize(wm, value);
    } break;
    case datum_t::R_BOOL: {
        datum_serialize(wm, datum_serialized_type_t::R_BOOL);
        bool value = datum->as_bool();
        serialize_universal(wm, value);
    } break;
    case datum_t::R_NULL: {
        datum_serialize(wm, datum_serialized_type_t::R_NULL);
    } break;
    case datum_t::R_NUM: {
        double value = datum->as_num();
        int64_t i;
        if (number_as_integer(value, &i)) {
            // We serialize the signed-zero double, -0.0, with INT_NEGATIVE.

            // so we can use `signbit` in a GCC 4.4.3-compatible way
            using namespace std;  // NOLINT(build/namespaces)
            if (signbit(value)) {
                datum_serialize(wm, datum_serialized_type_t::INT_NEGATIVE);
                serialize_varint_uint64(wm, -i);
            } else {
                datum_serialize(wm, datum_serialized_type_t::INT_POSITIVE);
                serialize_varint_uint64(wm, i);
            }
        } else {
            datum_serialize(wm, datum_serialized_type_t::DOUBLE);
            serialize_universal(wm, value);
        }
    } break;
    case datum_t::R_OBJECT: {
        datum_serialize(wm, datum_serialized_type_t::R_OBJECT);
        datum_serialize(wm, datum->as_object());
    } break;
    case datum_t::R_STR: {
        datum_serialize(wm, datum_serialized_type_t::R_STR);
        const wire_string_t &value = datum->as_str();
        datum_serialize(wm, value);
    } break;
    case datum_t::UNINITIALIZED:  // fall through
    default:
        unreachable();
    }
}
archive_result_t datum_deserialize(read_stream_t *s, counted_t<const datum_t> *datum) {
    datum_serialized_type_t type;
    archive_result_t res = datum_deserialize(s, &type);
    if (bad(res)) {
        return res;
    }

    switch (type) {
    case datum_serialized_type_t::R_ARRAY: {
        std::vector<counted_t<const datum_t> > value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_BOOL: {
        bool value;
        res = deserialize_universal(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(datum_t::R_BOOL, value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_NULL: {
        datum->reset(new datum_t(datum_t::R_NULL));
    } break;
    case datum_serialized_type_t::DOUBLE: {
        double value;
        res = deserialize_universal(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::INT_NEGATIVE:  // fall through
    case datum_serialized_type_t::INT_POSITIVE: {
        uint64_t unsigned_value;
        res = deserialize_varint_uint64(s, &unsigned_value);
        if (bad(res)) {
            return res;
        }
        if (unsigned_value > max_dbl_int) {
            return archive_result_t::RANGE_ERROR;
        }
        const double d = unsigned_value;
        double value;
        if (type == datum_serialized_type_t::INT_NEGATIVE) {
            // This might deserialize the signed-zero double, -0.0.
            value = -d;
        } else {
            value = d;
        }
        try {
            datum->reset(new datum_t(value));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_OBJECT: {
        std::map<std::string, counted_t<const datum_t> > value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    case datum_serialized_type_t::R_STR: {
        scoped_ptr_t<wire_string_t> value;
        res = datum_deserialize(s, &value);
        if (bad(res)) {
            return res;
        }
        rassert(value.has());
        try {
            datum->reset(new datum_t(std::move(value)));
        } catch (const base_exc_t &) {
            return archive_result_t::RANGE_ERROR;
        }
    } break;
    default:
        return archive_result_t::RANGE_ERROR;
    }

    return archive_result_t::SUCCESS;
}

template <cluster_version_t W>
void serialize(write_message_t *wm,
               const empty_ok_t<const counted_t<const datum_t> > &datum) {
    const counted_t<const datum_t> *pointer = datum.get();
    const bool has = pointer->has();
    serialize<W>(wm, has);
    if (has) {
        serialize<W>(wm, *pointer);
    }
}

INSTANTIATE_SERIALIZE_FOR_CLUSTER_AND_DISK(empty_ok_t<const counted_t<const datum_t> >);

template <cluster_version_t W>
archive_result_t deserialize(read_stream_t *s,
                             empty_ok_ref_t<counted_t<const datum_t> > datum) {
    bool has;
    archive_result_t res = deserialize<W>(s, &has);
    if (bad(res)) {
        return res;
    }

    counted_t<const datum_t> *pointer = datum.get();

    if (!has) {
        pointer->reset();
        return archive_result_t::SUCCESS;
    } else {
        return deserialize<W>(s, pointer);
    }
}

template archive_result_t deserialize<cluster_version_t::v1_13>(
        read_stream_t *s,
        empty_ok_ref_t<counted_t<const datum_t> > datum);
template archive_result_t deserialize<cluster_version_t::v1_13_2_is_latest>(
        read_stream_t *s,
        empty_ok_ref_t<counted_t<const datum_t> > datum);

}  // namespace ql
<|endoftext|>


<commit_before>// This code is part of the project "Ligra: A Lightweight Graph Processing
// Framework for Shared Memory", presented at Principles and Practice of
// Parallel Programming, 2013.
// Copyright (c) 2013 Julian Shun and Guy Blelloch
//
// 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 "ligra.h"

struct BFS_F {
  uintE* Parents;
  BFS_F(uintE* _Parents) : Parents(_Parents) {}
  inline bool update (uintE s, uintE d) { //Update
    if(Parents[d] == UINT_E_MAX) { Parents[d] = s; return 1; }
    else return 0;
  }
  inline bool updateAtomic (uintE s, uintE d){ //atomic version of Update
    return (CAS(&Parents[d],UINT_E_MAX,s));
  }
  //cond function checks if vertex has been visited yet
  inline bool cond (uintE d) { return (Parents[d] == UINT_E_MAX); }
};

template <class vertex>
void Compute(graph<vertex>& GA, commandLine P) {
  long start = P.getOptionLongValue("-r",0);
  long n = GA.n;
  //creates Parents array, initialized to all -1, except for start
  uintE* Parents = newA(uintE,n);
  parallel_for(long i=0;i<n;i++) Parents[i] = UINT_E_MAX;
  Parents[start] = start;
  vertexSubset Frontier(n,start); //creates initial frontier
  while(!Frontier.isEmpty()){ //loop until frontier is empty
    vertexSubset output = edgeMap(GA, Frontier, BFS_F(Parents));
    Frontier.del();
    Frontier = output; //set new frontier
  }
  Frontier.del();
  free(Parents);
}
<commit_msg>[trace] apps: BFS: trace partens property access<commit_after>// This code is part of the project "Ligra: A Lightweight Graph Processing
// Framework for Shared Memory", presented at Principles and Practice of
// Parallel Programming, 2013.
// Copyright (c) 2013 Julian Shun and Guy Blelloch
//
// 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 "ligra.h"

struct BFS_F {
  uintE* Parents;
  BFS_F(uintE* _Parents) : Parents(_Parents) {}
  inline bool update (uintE s, uintE d) { //Update
    TRACE_PROP_READ(d);
    if(Parents[d] == UINT_E_MAX) { TRACE_PROP_WRITE(d); Parents[d] = s; return 1; }
    else return 0;
  }
  inline bool updateAtomic (uintE s, uintE d){ //atomic version of Update
    TRACE_PROP_RW(d);
    return (CAS(&Parents[d],UINT_E_MAX,s));
  }
  //cond function checks if vertex has been visited yet
  inline bool cond (uintE d) { TRACE_PROP_READ(d); return (Parents[d] == UINT_E_MAX); }
};

template <class vertex>
void Compute(graph<vertex>& GA, commandLine P) {
  long start = P.getOptionLongValue("-r",0);
  long n = GA.n;
  //creates Parents array, initialized to all -1, except for start
  uintE* Parents = newA(uintE,n);
  parallel_for(long i=0;i<n;i++) {TRACE_PROP_WRITE(i); Parents[i] = UINT_E_MAX; }
  Parents[start] = start; TRACE_PROP_WRITE(start);
  vertexSubset Frontier(n,start); //creates initial frontier
  while(!Frontier.isEmpty()){ //loop until frontier is empty
    vertexSubset output = edgeMap(GA, Frontier, BFS_F(Parents));
    Frontier.del();
    Frontier = output; //set new frontier
  }
  Frontier.del();
  free(Parents);
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <ctime>
#include "core/core.h"

Core::Core()
  : mPathfinder(*this)
{
}

Core::~Core() {
}

const std::list<Player*>& Core::players() {
  return mPlayers;
}

const Event& Core::currentEvent() {
  return *mCurrentEvent;
}

const Player& Core::currentPlayer() {
  return *mCurrentPlayer;
}

Unit* Core::selectedUnit() {
  return mSelectedUnit;
}

std::list<Unit*>& Core::units() {
  return mUnits;
}

Pathfinder& Core::pathfinder() {
  return mPathfinder;
}

void Core::setSelectedUnit(Unit* unit) {
  mSelectedUnit = unit;
}

void Core::setCurrentEvent(Event* event) {
  mCurrentEvent = event;
}

void Core::setCurrentPlayer(Player* player) {
  mCurrentPlayer = player;
}

void Core::createLocalHuman(int id) {
  auto p = new Player;
  mPlayers.push_back(p);
  p->id = id;
  p->lastSeenEventID = HAVE_NOT_SEEN_ANY_EVENTS;
}

void Core::initLocalPlayers(std::vector<int> unitIDs) {
  for (int id : unitIDs) {
    createLocalHuman(id);
  }
  mCurrentPlayer = mPlayers.back();
}

bool Core::inboard(const V2i& p) const {
  return p.x() >= 0 && p.y() >= 0
      && p.x() < MAP_X && p.y() < MAP_Y;
}

Tile& Core::tile(const V2i& p) {
  assert(inboard(p));
  return mMap[p.y()][p.x()];
}

V2i Core::incV2i(const V2i& pos) const {
  assert(inboard(pos));
  V2i newPos = pos;
  newPos.setX(pos.x() + 1);
  if (newPos.x() == MAP_X) {
    newPos.setX(0);
    newPos.setY(newPos.y() + 1);
  }
  return newPos;
}

int Core::getNewEventID() {
  if (!mEvents.empty()) {
    return mEvents.back()->id + 1;
  } else {
    return 0;
  }
}

void Core::refreshUnits(int playerID) {
  for (auto u : units()) {
    if (u->playerID == playerID) {
      u->actionPoints = getUnitType(u->typeID).actionPoints;
    }
  }
}

// Undo all events that this player have not seen yet
void Core::undoUnshownEvents() {
  if (mEvents.size() == 0) {
    return;
  }
  auto i = mEvents.end();
  --i;
  while (i != mEvents.begin()) {
    auto event = *i;
    if (event->id == mCurrentPlayer->lastSeenEventID) {
      break;
    }
    undoEvent(*event);
    --i;
  }
}

void Core::applyEvent(const Event& e) {
  mCurrentPlayer->lastSeenEventID = e.id;
  switch (e.t) {
  case EventTypeID::MOVE:
    applyEventMove(*this, e.e.move);
    break;
  case EventTypeID::END_TURN:
    applyEventEndTurn(*this, e.e.endTurn);
    break;
  default:
    die("event: applyEvent(): "
        "unknown event '%d'\n", e.t);
    break;
  }
  // updateUnitsVisibility();
}

bool Core::isEventVisible(const Event& e) const {
  switch (e.t) {
  case EventTypeID::MOVE:
    return isVisibleEventMove(*this, e.e.move);
  case EventTypeID::END_TURN:
    return true;
  default:
    die("event: isEventVisible(): "
        "unknown event '%d'\n", e.t);
    return true;
  }
}

// TODO simplify
void Core::applyInvisibleEvents() {
  Event* e = getNextEventNode();
  while (e) {
    assert(e);
    if (!isEventVisible(*e)) {
      applyEvent(*e);
    } else {
      break;
    }
    e = getNext(mEvents, e);
    assert(e);
  }
}

// TODO: Called before getNextEvent
bool Core::unshownEventsLeft() {
  applyInvisibleEvents();
  if (mEvents.size() == 0) {
    return false;
  } else {
    auto e = mEvents.back();
    return e->id != mCurrentPlayer->lastSeenEventID;
  }
}

// Always called after applyInvisibleEvents
Event* Core::getNextEvent() {
  int id = mCurrentPlayer->lastSeenEventID; // shortcut
  assert(mEvents.size() > 0);
  if (id == HAVE_NOT_SEEN_ANY_EVENTS) {
    return mEvents.front();
  }
  for (auto e : mEvents) {
    if (e->id == id) {
      return getNext(mEvents, e);
    }
  }
  return nullptr;
}

void Core::addEvent(Event* e) {
  assert(e);
  e->id = getNewEventID();
  mEvents.push_back(e);
  // event2log(*e);
#if 0
  // TODO
  if (!isLocal) {
    sendEvent(e);
  }
#else
  // UNUSED(sendEvent);
#endif
}

bool Core::isLosClear(const V2i& from, const V2i& to) {
  Los los(from, to);
  for (V2i p = los.getNext(); !los.isFinished(); p = los.getNext()) {
    if (unitAt(p) || tile(p).obstacle) {
      return false;
    }
  }
  return true;
}

#define FOR_EACH_TILE(p) \
  for (p = V2i(0, 0); inboard(p); p = incV2i(p))

void Core::cleanFow() {
  V2i p;
  FOR_EACH_TILE(p) {
    tile(p).fow = 0;
  }
}

void Core::calculateFow() {
  assert(mCurrentPlayer);
  cleanFow();
  V2i p;
  FOR_EACH_TILE(p) {
    for (auto u : mUnits) {
      int maxDist = getUnitType(u->typeID).rangeOfVision;
      bool isPlayerOk = (u->playerID == mCurrentPlayer->id);
      bool isDistanceOk = (p.distance(u->pos) < maxDist);
      bool isLosOk = isLosClear(p, u->pos);
      if (isPlayerOk && isDistanceOk && isLosOk) {
        tile(p).fow++;
      }
    }
  }
}

Unit* Core::unitAt(const V2i& pos) {
  for (auto u : mUnits) {
    if (u->pos == pos) {
      return u;
    }
  }
  return nullptr;
}

Unit* Core::id2unit(int id) {
  for (auto u : mUnits) {
    if (u->id == id) {
      return u;
    }
  }
  return nullptr;
}

int Core::getNewUnitID() {
  if (mUnits.size() > 0) {
    auto lastUnit = mUnits.back();
    return lastUnit->id + 1;
  } else {
    return 0;
  }
}

void Core::addUnit(const V2i& p, int playerID) {
  auto u = new Unit;
  assert(inboard(p));
  assert(playerID >= 0 && playerID < 16);
  u->id = getNewUnitID();
  u->pos = p;
  u->playerID = playerID;
  u->dir = static_cast<Dir>(rnd(0, 7));
  u->typeID = rnd(0, (int)UnitTypeID::COUNT - 1);
  u->actionPoints = getUnitType(u->typeID).actionPoints;
  mUnits.push_back(u);
  calculateFow();
#if 0
  buildFowArray(&vaFogOfWar);
#endif
}

void Core::killUnit(Unit* u) {
  // deleteNode(&units, data2node(units, u));
  mUnits.remove(u);
  delete u;
  if (mSelectedUnit) {
    mPathfinder.fillMap(*mSelectedUnit);
    calculateFow();
#if 0
    buildWalkableArray(&vaWalkableMap);
    buildFowArray(&vaFogOfWar);
#endif
  }
}

void Core::shoot(Unit *shooter, Unit *target) {
  if (isLosClear(shooter->pos, target->pos)) {
    killUnit(target);
  }
}

void Core::initUnits() {
  mSelectedUnit = nullptr;
  for (int i = 0; i < 8; i++) {
    V2i p = V2i(rnd(0, MAP_X - 1), rnd(0, MAP_Y - 1));
    if (!tile(p).obstacle && !unitAt(p)) {
      addUnit(p, rnd(0, 1));
    } else {
      i--;
    }
  }
}

void Core::initObstacles() {
  V2i p;
  FOR_EACH_TILE(p) {
    tile(p).obstacle = ((rand() % 100) > 85);
  }
}

void Core::initPlayers() {
  initLocalPlayers({0, 1});
}

void Core::initLogic() {
  srand(time(nullptr));
  initUnitTypes();
  mPathfinder.cleanMap();
  cleanFow();
  initPlayers();
  initObstacles();
  initUnits();
  calculateFow();
}

void Core::undoEvent(const Event& e) {
  switch (e.t) {
  case EventTypeID::MOVE:
    undoEventMove(*this, e.e.move);
    break;
  case EventTypeID::END_TURN:
    // empty
    // TODO: die()?
    break;
  default:
    die("event: undoEvent(): "
        "unknown event type '%d'\n", e.t);
    break;
  }
  // updateUnitsVisibility();
}

// TODO: rename.
Event* Core::getNextEventNode() {
  // Node *node;
  int id = mCurrentPlayer->lastSeenEventID; // shortcut
  if (mEvents.size() == 0) {
    return nullptr;
  }
  if (id == HAVE_NOT_SEEN_ANY_EVENTS) {
    return mEvents.front();
  }
  // find last seen event
  Event *e = nullptr;
  for (auto e : mEvents) {
    if (e->id == id) {
      break;
    }
  }
  if (!e) {
    return nullptr;
  } else {
    return getNext(mEvents, e);
  }
}

void Core::event2log(const Event& e) {
  UNUSED(e);
  // TODO
}

void Core::sendEvent(const Event& e) {
  UNUSED(e);
  // TODO
}
<commit_msg>Fixed initial unit rotation<commit_after>// See LICENSE file for copyright and license details.

#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <ctime>
#include "core/core.h"

Core::Core()
  : mPathfinder(*this)
{
}

Core::~Core() {
}

const std::list<Player*>& Core::players() {
  return mPlayers;
}

const Event& Core::currentEvent() {
  return *mCurrentEvent;
}

const Player& Core::currentPlayer() {
  return *mCurrentPlayer;
}

Unit* Core::selectedUnit() {
  return mSelectedUnit;
}

std::list<Unit*>& Core::units() {
  return mUnits;
}

Pathfinder& Core::pathfinder() {
  return mPathfinder;
}

void Core::setSelectedUnit(Unit* unit) {
  mSelectedUnit = unit;
}

void Core::setCurrentEvent(Event* event) {
  mCurrentEvent = event;
}

void Core::setCurrentPlayer(Player* player) {
  mCurrentPlayer = player;
}

void Core::createLocalHuman(int id) {
  auto p = new Player;
  mPlayers.push_back(p);
  p->id = id;
  p->lastSeenEventID = HAVE_NOT_SEEN_ANY_EVENTS;
}

void Core::initLocalPlayers(std::vector<int> unitIDs) {
  for (int id : unitIDs) {
    createLocalHuman(id);
  }
  mCurrentPlayer = mPlayers.back();
}

bool Core::inboard(const V2i& p) const {
  return p.x() >= 0 && p.y() >= 0
      && p.x() < MAP_X && p.y() < MAP_Y;
}

Tile& Core::tile(const V2i& p) {
  assert(inboard(p));
  return mMap[p.y()][p.x()];
}

V2i Core::incV2i(const V2i& pos) const {
  assert(inboard(pos));
  V2i newPos = pos;
  newPos.setX(pos.x() + 1);
  if (newPos.x() == MAP_X) {
    newPos.setX(0);
    newPos.setY(newPos.y() + 1);
  }
  return newPos;
}

int Core::getNewEventID() {
  if (!mEvents.empty()) {
    return mEvents.back()->id + 1;
  } else {
    return 0;
  }
}

void Core::refreshUnits(int playerID) {
  for (auto u : units()) {
    if (u->playerID == playerID) {
      u->actionPoints = getUnitType(u->typeID).actionPoints;
    }
  }
}

// Undo all events that this player have not seen yet
void Core::undoUnshownEvents() {
  if (mEvents.size() == 0) {
    return;
  }
  auto i = mEvents.end();
  --i;
  while (i != mEvents.begin()) {
    auto event = *i;
    if (event->id == mCurrentPlayer->lastSeenEventID) {
      break;
    }
    undoEvent(*event);
    --i;
  }
}

void Core::applyEvent(const Event& e) {
  mCurrentPlayer->lastSeenEventID = e.id;
  switch (e.t) {
  case EventTypeID::MOVE:
    applyEventMove(*this, e.e.move);
    break;
  case EventTypeID::END_TURN:
    applyEventEndTurn(*this, e.e.endTurn);
    break;
  default:
    die("event: applyEvent(): "
        "unknown event '%d'\n", e.t);
    break;
  }
  // updateUnitsVisibility();
}

bool Core::isEventVisible(const Event& e) const {
  switch (e.t) {
  case EventTypeID::MOVE:
    return isVisibleEventMove(*this, e.e.move);
  case EventTypeID::END_TURN:
    return true;
  default:
    die("event: isEventVisible(): "
        "unknown event '%d'\n", e.t);
    return true;
  }
}

// TODO simplify
void Core::applyInvisibleEvents() {
  Event* e = getNextEventNode();
  while (e) {
    assert(e);
    if (!isEventVisible(*e)) {
      applyEvent(*e);
    } else {
      break;
    }
    e = getNext(mEvents, e);
    assert(e);
  }
}

// TODO: Called before getNextEvent
bool Core::unshownEventsLeft() {
  applyInvisibleEvents();
  if (mEvents.size() == 0) {
    return false;
  } else {
    auto e = mEvents.back();
    return e->id != mCurrentPlayer->lastSeenEventID;
  }
}

// Always called after applyInvisibleEvents
Event* Core::getNextEvent() {
  int id = mCurrentPlayer->lastSeenEventID; // shortcut
  assert(mEvents.size() > 0);
  if (id == HAVE_NOT_SEEN_ANY_EVENTS) {
    return mEvents.front();
  }
  for (auto e : mEvents) {
    if (e->id == id) {
      return getNext(mEvents, e);
    }
  }
  return nullptr;
}

void Core::addEvent(Event* e) {
  assert(e);
  e->id = getNewEventID();
  mEvents.push_back(e);
  // event2log(*e);
#if 0
  // TODO
  if (!isLocal) {
    sendEvent(e);
  }
#else
  // UNUSED(sendEvent);
#endif
}

bool Core::isLosClear(const V2i& from, const V2i& to) {
  Los los(from, to);
  for (V2i p = los.getNext(); !los.isFinished(); p = los.getNext()) {
    if (unitAt(p) || tile(p).obstacle) {
      return false;
    }
  }
  return true;
}

#define FOR_EACH_TILE(p) \
  for (p = V2i(0, 0); inboard(p); p = incV2i(p))

void Core::cleanFow() {
  V2i p;
  FOR_EACH_TILE(p) {
    tile(p).fow = 0;
  }
}

void Core::calculateFow() {
  assert(mCurrentPlayer);
  cleanFow();
  V2i p;
  FOR_EACH_TILE(p) {
    for (auto u : mUnits) {
      int maxDist = getUnitType(u->typeID).rangeOfVision;
      bool isPlayerOk = (u->playerID == mCurrentPlayer->id);
      bool isDistanceOk = (p.distance(u->pos) < maxDist);
      bool isLosOk = isLosClear(p, u->pos);
      if (isPlayerOk && isDistanceOk && isLosOk) {
        tile(p).fow++;
      }
    }
  }
}

Unit* Core::unitAt(const V2i& pos) {
  for (auto u : mUnits) {
    if (u->pos == pos) {
      return u;
    }
  }
  return nullptr;
}

Unit* Core::id2unit(int id) {
  for (auto u : mUnits) {
    if (u->id == id) {
      return u;
    }
  }
  return nullptr;
}

int Core::getNewUnitID() {
  if (mUnits.size() > 0) {
    auto lastUnit = mUnits.back();
    return lastUnit->id + 1;
  } else {
    return 0;
  }
}

void Core::addUnit(const V2i& p, int playerID) {
  auto u = new Unit;
  assert(inboard(p));
  assert(playerID >= 0 && playerID < 16);
  u->id = getNewUnitID();
  u->pos = p;
  u->playerID = playerID;
  u->dir = static_cast<Dir>(rnd(0, 6 - 1));
  u->typeID = rnd(0, (int)UnitTypeID::COUNT - 1);
  u->actionPoints = getUnitType(u->typeID).actionPoints;
  mUnits.push_back(u);
  calculateFow();
#if 0
  buildFowArray(&vaFogOfWar);
#endif
}

void Core::killUnit(Unit* u) {
  // deleteNode(&units, data2node(units, u));
  mUnits.remove(u);
  delete u;
  if (mSelectedUnit) {
    mPathfinder.fillMap(*mSelectedUnit);
    calculateFow();
#if 0
    buildWalkableArray(&vaWalkableMap);
    buildFowArray(&vaFogOfWar);
#endif
  }
}

void Core::shoot(Unit *shooter, Unit *target) {
  if (isLosClear(shooter->pos, target->pos)) {
    killUnit(target);
  }
}

void Core::initUnits() {
  mSelectedUnit = nullptr;
  for (int i = 0; i < 8; i++) {
    V2i p = V2i(rnd(0, MAP_X - 1), rnd(0, MAP_Y - 1));
    if (!tile(p).obstacle && !unitAt(p)) {
      addUnit(p, rnd(0, 1));
    } else {
      i--;
    }
  }
}

void Core::initObstacles() {
  V2i p;
  FOR_EACH_TILE(p) {
    tile(p).obstacle = ((rand() % 100) > 85);
  }
}

void Core::initPlayers() {
  initLocalPlayers({0, 1});
}

void Core::initLogic() {
  srand(time(nullptr));
  initUnitTypes();
  mPathfinder.cleanMap();
  cleanFow();
  initPlayers();
  initObstacles();
  initUnits();
  calculateFow();
}

void Core::undoEvent(const Event& e) {
  switch (e.t) {
  case EventTypeID::MOVE:
    undoEventMove(*this, e.e.move);
    break;
  case EventTypeID::END_TURN:
    // empty
    // TODO: die()?
    break;
  default:
    die("event: undoEvent(): "
        "unknown event type '%d'\n", e.t);
    break;
  }
  // updateUnitsVisibility();
}

// TODO: rename.
Event* Core::getNextEventNode() {
  // Node *node;
  int id = mCurrentPlayer->lastSeenEventID; // shortcut
  if (mEvents.size() == 0) {
    return nullptr;
  }
  if (id == HAVE_NOT_SEEN_ANY_EVENTS) {
    return mEvents.front();
  }
  // find last seen event
  Event *e = nullptr;
  for (auto e : mEvents) {
    if (e->id == id) {
      break;
    }
  }
  if (!e) {
    return nullptr;
  } else {
    return getNext(mEvents, e);
  }
}

void Core::event2log(const Event& e) {
  UNUSED(e);
  // TODO
}

void Core::sendEvent(const Event& e) {
  UNUSED(e);
  // TODO
}
<|endoftext|>


<commit_before>#include "core/image.h"

#include <iostream>

#include "core/assert.h"
#include "core/numeric.h"

#define STB_IMAGE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_image_write.h"

#include "core/log.h"
#include "core/decompress.h"

namespace euphoria::core
{
    LOG_SPECIFY_DEFAULT_LOGGER("core.image")

    void
    Image::MakeInvalid()
    {
        components.resize(0);
        width_     = 0;
        height_    = 0;
        has_alpha_ = false;

        ASSERT(!IsValid());
    }

    int
    Image::GetPixelByteSize() const
    {
        return has_alpha_ ? 4 : 3;
    }

    void
    Image::SetupWithAlphaSupport(
            int image_width,
            int image_height,
            int default_value)
    {
        Setup(image_width, image_height, true, default_value);
    }

    void
    Image::SetupNoAlphaSupport(
            int image_width,
            int image_height,
            int default_value)
    {
        Setup(image_width, image_height, false, default_value);
    }

    void
    Image::Setup(
            int  image_width,
            int  image_height,
            bool alpha,
            int  default_value)
    {
        ASSERTX(image_width > 0, image_width);
        ASSERTX(image_height > 0, image_height);

        width_     = image_width;
        height_    = image_height;
        has_alpha_ = alpha;

        components.resize(0);  // clear all pixels
        const unsigned int size = width_ * height_ * GetPixelByteSize();
        if(default_value < 0)
        {
            components.resize(size);
        }
        else
        {
            ASSERT(default_value <= 255);
            components.resize(size, static_cast<unsigned char>(default_value));
        }

        ASSERT(IsValid());
    }

    int
    Image::GetPixelIndex(int x, int y) const
    {
        ASSERT(x >= 0 && x < width_);
        ASSERT(y >= 0 && y < height_);

        return (y * width_ + x) * GetPixelByteSize();
    }

    void
    Image::SetPixel(int x, int y, const Rgbai& color)
    {
        SetPixel(x, y, color.r, color.g, color.b, color.a);
    }

    void
    Image::SetPixel(
            int           x,
            int           y,
            unsigned char r,
            unsigned char g,
            unsigned char b,
            unsigned char a)
    {
        ASSERTX(IsWithinInclusivei(0, x, GetWidth() - 1), x, GetWidth() - 1);
        ASSERTX(IsWithinInclusivei(0, y, GetHeight() - 1), y, GetHeight() - 1);

        const auto base_index      = GetPixelIndex(x, y);
        components[base_index + 0] = r;
        components[base_index + 1] = g;
        components[base_index + 2] = b;

        if(has_alpha_)
        {
            components[base_index + 3] = a;
        }
    }

    Rgbai
    Image::GetPixel(int x, int y) const
    {
        ASSERT(IsWithinInclusivei(0, x, GetWidth() - 1));
        ASSERT(IsWithinInclusivei(0, y, GetHeight() - 1));

        const auto base_index = GetPixelIndex(x, y);

        const auto red   = components[base_index + 0];
        const auto green = components[base_index + 1];
        const auto blue  = components[base_index + 2];

        if(has_alpha_)
        {
            const auto alpha = components[base_index + 3];
            return Rgbai {Rgbi {red, green, blue}, alpha};
        }
        else
        {
            return Rgbi {red, green, blue};
        }
    }

    bool
    Image::IsValid() const
    {
        return width_ > 0 && height_ > 0;
    }

    int
    Image::GetWidth() const
    {
        return width_;
    }

    int
    Image::GetHeight() const
    {
        return height_;
    }

    bool
    Image::HasAlpha() const
    {
        return has_alpha_;
    }

    const unsigned char*
    Image::GetPixelData() const
    {
        return &components[0];
    }

    namespace  // local
    {
        void
        DetermineImageSize(void* context, void* /*unused*/, int size)
        {
            ASSERT(size >= 0);
            auto* total_size = static_cast<int*>(context);
            *total_size += size;
        }

        void
        WriteToMemoryChunkFile(void* context, void* data, int size)
        {
            ASSERT(size >= 0);
            auto* file = static_cast<MemoryChunkFile*>(context);
            file->Write(data, size);
        }
    }  // namespace

    int
    WriteImageData(
            stbi_write_func* func,
            void*            context,
            int              w,
            int              h,
            int              comp,
            const void*      data,
            ImageWriteFormat format,
            int              jpeg_quality)
    {
        switch(format)
        {
        case ImageWriteFormat::PNG:
            return stbi_write_png_to_func(func, context, w, h, comp, data, 0);
        case ImageWriteFormat::BMP:
            return stbi_write_bmp_to_func(func, context, w, h, comp, data);
        case ImageWriteFormat::TGA:
            return stbi_write_tga_to_func(func, context, w, h, comp, data);
        case ImageWriteFormat::JPEG:
            return stbi_write_jpg_to_func(
                    func, context, w, h, comp, data, jpeg_quality);
        default: DIE("Unhandled case"); return 0;
        }
    }

    std::shared_ptr<MemoryChunk>
    Image::Write(ImageWriteFormat format, int jpeg_quality) const
    {
        const int number_of_components = has_alpha_ ? 4 : 3;

        std::vector<unsigned char> pixels(
                width_ * height_ * number_of_components, 0);
        for(int y = 0; y < height_; y += 1)
        {
            const int iy = height_ - (y + 1);

            ASSERTX(IsWithinInclusivei(0, iy, height_ - 1), iy, y, height_);
            for(int x = 0; x < width_; x += 1)
            {
                const int target_index
                        = (x + width_ * y) * number_of_components;
                const int source_index
                        = (x + width_ * iy) * number_of_components;
                for(int component = 0; component < number_of_components;
                    component += 1)
                {
                    pixels[target_index + component]
                            = components[source_index + component];
                }
            }
        }

        int size        = 0;
        int size_result = WriteImageData(
                DetermineImageSize,
                &size,
                GetWidth(),
                GetHeight(),
                number_of_components,
                &pixels[0],
                format,
                jpeg_quality);
        if(size_result == 0)
        {
            return MemoryChunk::Null();
        }

        ASSERT(size > 0);
        MemoryChunkFile file {MemoryChunk::Alloc(size)};
        int             write_result = WriteImageData(
                WriteToMemoryChunkFile,
                &file,
                GetWidth(),
                GetHeight(),
                number_of_components,
                &pixels[0],
                format,
                jpeg_quality);
        if(write_result == 0)
        {
            return MemoryChunk::Null();
        }

        return file.data;
    }

    namespace
    {
        unsigned char
        Select(int           ch,
               unsigned char a,
               unsigned char b,
               unsigned char c,
               unsigned char d)
        {
            switch(ch)
            {
            case 1:  // grey
                return a;
            case 2:  // grey, alpha
                return b;
            case 3:  // red, green, blue
                return c;
            case 4:  // red, green, blue, alpha
                return d;
            default: DIE("unhandled Select channel"); return 0;
            }
        }
    }  // namespace

    ImageLoadResult
    LoadImage(vfs::FileSystem* fs, const std::string& path, AlphaLoad alpha)
    {
        auto file_memory = fs->ReadFile(path);
        if(file_memory == nullptr)
        {
            ImageLoadResult result;
            result.error = "File doesnt exist";
            result.image.MakeInvalid();
            LOG_ERROR("Failed to open " << path << ": File doesnt exist.");
            return result;
        }

        return LoadImage(file_memory, path, alpha);
    }

    ImageLoadResult
    LoadImage(
            std::shared_ptr<MemoryChunk> file_memory,
            const std::string&           path,
            AlphaLoad                    alpha)
    {
        int channels     = 0;
        int image_width  = 0;
        int image_height = 0;

        // signed to unsigned cast is probably ok since both are considered to be
        // a chuck of memory
        // https://stackoverflow.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-whatever
        unsigned char* data = stbi_load_from_memory(
                reinterpret_cast<unsigned char*>(
                        file_memory->GetData()),  // NOLINT
                file_memory->GetSize(),
                &image_width,
                &image_height,
                &channels,
                0);

        if(data == nullptr)
        {
            ImageLoadResult result;
            result.error = stbi_failure_reason();
            result.image.MakeInvalid();
            LOG_ERROR("Failed to read " << path << ": " << result.error);
            return result;
        }

        bool has_alpha = false;
        if(alpha == AlphaLoad::Keep)
        {
            has_alpha = channels == 2 || channels == 4;
        }

        LOG_INFO(
                "Image: " << path << " " << image_width << "x" << image_height
                          << " alpha " << has_alpha << " channels "
                          << channels);

        ImageLoadResult result;
        if(has_alpha)
        {
            result.image.SetupWithAlphaSupport(image_width, image_height, -1);
        }
        else
        {
            result.image.SetupNoAlphaSupport(image_width, image_height, -1);
        }

        for(int y = 0; y < image_height; ++y)
        {
            for(int x = 0; x < image_width; ++x)
            {
                const int src_index = (y * image_width + x) * channels;

                // get component values
                const unsigned char zero = 0;
                const unsigned char c1
                        = data[src_index + 0];  // NOLINT no garbage value
                const unsigned char c2
                        = (channels <= 1) ? zero : data[src_index + 1];
                const unsigned char c3
                        = (channels <= 2) ? zero : data[src_index + 2];
                const unsigned char c4
                        = (channels <= 3) ? zero : data[src_index + 3];

                // Gray, Gray+alpha, RGB, RGB+alpha:     gr   gra  rgb  rgba
                const unsigned char r = c1;  //           c1   c1   c1    c1
                const unsigned char g = Select(channels, c1, c1, c2, c2);
                const unsigned char b = Select(channels, c1, c1, c3, c3);
                const unsigned char a = Select(channels, 255, c2, 255, c4);

                result.image.SetPixel(x, image_height - (y + 1), r, g, b, a);
            }
        }

        stbi_image_free(data);
        return result;
    }

    ImageLoadResult
    LoadImage(
            void* compressed_data,
            int compressed_size,
            const std::string&           path,
            AlphaLoad                    alpha)
    {
        Decompress dec;
        const unsigned int decompressed_size = Decompress::stb_decompress_length((const unsigned char*)compressed_data);
        auto decompressed = MemoryChunk::Alloc(decompressed_size);
        const auto len = dec.stb_decompress(reinterpret_cast<unsigned char*>(decompressed->GetData()),
            reinterpret_cast<const unsigned char*>(compressed_data),
            static_cast<unsigned int>(compressed_size));
        if(len == 0)
        {
            ImageLoadResult result;
            result.error = "failed to decompress before loading image";
            result.image.MakeInvalid();
            return result;
        }

        return LoadImage(decompressed, path, alpha);
    }

}  // namespace euphoria::core
<commit_msg>replaced assert with assertx for easier debugging<commit_after>#include "core/image.h"

#include <iostream>

#include "core/assert.h"
#include "core/numeric.h"

#define STB_IMAGE_IMPLEMENTATION
#define STBI_FAILURE_USERMSG
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_image_write.h"

#include "core/log.h"
#include "core/decompress.h"

namespace euphoria::core
{
    LOG_SPECIFY_DEFAULT_LOGGER("core.image")

    void
    Image::MakeInvalid()
    {
        components.resize(0);
        width_     = 0;
        height_    = 0;
        has_alpha_ = false;

        ASSERT(!IsValid());
    }

    int
    Image::GetPixelByteSize() const
    {
        return has_alpha_ ? 4 : 3;
    }

    void
    Image::SetupWithAlphaSupport(
            int image_width,
            int image_height,
            int default_value)
    {
        Setup(image_width, image_height, true, default_value);
    }

    void
    Image::SetupNoAlphaSupport(
            int image_width,
            int image_height,
            int default_value)
    {
        Setup(image_width, image_height, false, default_value);
    }

    void
    Image::Setup(
            int  image_width,
            int  image_height,
            bool alpha,
            int  default_value)
    {
        ASSERTX(image_width > 0, image_width);
        ASSERTX(image_height > 0, image_height);

        width_     = image_width;
        height_    = image_height;
        has_alpha_ = alpha;

        components.resize(0);  // clear all pixels
        const unsigned int size = width_ * height_ * GetPixelByteSize();
        if(default_value < 0)
        {
            components.resize(size);
        }
        else
        {
            ASSERT(default_value <= 255);
            components.resize(size, static_cast<unsigned char>(default_value));
        }

        ASSERT(IsValid());
    }

    int
    Image::GetPixelIndex(int x, int y) const
    {
        ASSERT(x >= 0 && x < width_);
        ASSERT(y >= 0 && y < height_);

        return (y * width_ + x) * GetPixelByteSize();
    }

    void
    Image::SetPixel(int x, int y, const Rgbai& color)
    {
        SetPixel(x, y, color.r, color.g, color.b, color.a);
    }

    void
    Image::SetPixel(
            int           x,
            int           y,
            unsigned char r,
            unsigned char g,
            unsigned char b,
            unsigned char a)
    {
        ASSERTX(IsWithinInclusivei(0, x, GetWidth() - 1), x, GetWidth() - 1);
        ASSERTX(IsWithinInclusivei(0, y, GetHeight() - 1), y, GetHeight() - 1);

        const auto base_index      = GetPixelIndex(x, y);
        components[base_index + 0] = r;
        components[base_index + 1] = g;
        components[base_index + 2] = b;

        if(has_alpha_)
        {
            components[base_index + 3] = a;
        }
    }

    Rgbai
    Image::GetPixel(int x, int y) const
    {
        ASSERTX(IsWithinInclusivei(0, x, GetWidth() - 1), x, GetWidth());
        ASSERTX(IsWithinInclusivei(0, y, GetHeight() - 1), y, GetHeight());

        const auto base_index = GetPixelIndex(x, y);

        const auto red   = components[base_index + 0];
        const auto green = components[base_index + 1];
        const auto blue  = components[base_index + 2];

        if(has_alpha_)
        {
            const auto alpha = components[base_index + 3];
            return Rgbai {Rgbi {red, green, blue}, alpha};
        }
        else
        {
            return Rgbi {red, green, blue};
        }
    }

    bool
    Image::IsValid() const
    {
        return width_ > 0 && height_ > 0;
    }

    int
    Image::GetWidth() const
    {
        return width_;
    }

    int
    Image::GetHeight() const
    {
        return height_;
    }

    bool
    Image::HasAlpha() const
    {
        return has_alpha_;
    }

    const unsigned char*
    Image::GetPixelData() const
    {
        return &components[0];
    }

    namespace  // local
    {
        void
        DetermineImageSize(void* context, void* /*unused*/, int size)
        {
            ASSERT(size >= 0);
            auto* total_size = static_cast<int*>(context);
            *total_size += size;
        }

        void
        WriteToMemoryChunkFile(void* context, void* data, int size)
        {
            ASSERT(size >= 0);
            auto* file = static_cast<MemoryChunkFile*>(context);
            file->Write(data, size);
        }
    }  // namespace

    int
    WriteImageData(
            stbi_write_func* func,
            void*            context,
            int              w,
            int              h,
            int              comp,
            const void*      data,
            ImageWriteFormat format,
            int              jpeg_quality)
    {
        switch(format)
        {
        case ImageWriteFormat::PNG:
            return stbi_write_png_to_func(func, context, w, h, comp, data, 0);
        case ImageWriteFormat::BMP:
            return stbi_write_bmp_to_func(func, context, w, h, comp, data);
        case ImageWriteFormat::TGA:
            return stbi_write_tga_to_func(func, context, w, h, comp, data);
        case ImageWriteFormat::JPEG:
            return stbi_write_jpg_to_func(
                    func, context, w, h, comp, data, jpeg_quality);
        default: DIE("Unhandled case"); return 0;
        }
    }

    std::shared_ptr<MemoryChunk>
    Image::Write(ImageWriteFormat format, int jpeg_quality) const
    {
        const int number_of_components = has_alpha_ ? 4 : 3;

        std::vector<unsigned char> pixels(
                width_ * height_ * number_of_components, 0);
        for(int y = 0; y < height_; y += 1)
        {
            const int iy = height_ - (y + 1);

            ASSERTX(IsWithinInclusivei(0, iy, height_ - 1), iy, y, height_);
            for(int x = 0; x < width_; x += 1)
            {
                const int target_index
                        = (x + width_ * y) * number_of_components;
                const int source_index
                        = (x + width_ * iy) * number_of_components;
                for(int component = 0; component < number_of_components;
                    component += 1)
                {
                    pixels[target_index + component]
                            = components[source_index + component];
                }
            }
        }

        int size        = 0;
        int size_result = WriteImageData(
                DetermineImageSize,
                &size,
                GetWidth(),
                GetHeight(),
                number_of_components,
                &pixels[0],
                format,
                jpeg_quality);
        if(size_result == 0)
        {
            return MemoryChunk::Null();
        }

        ASSERT(size > 0);
        MemoryChunkFile file {MemoryChunk::Alloc(size)};
        int             write_result = WriteImageData(
                WriteToMemoryChunkFile,
                &file,
                GetWidth(),
                GetHeight(),
                number_of_components,
                &pixels[0],
                format,
                jpeg_quality);
        if(write_result == 0)
        {
            return MemoryChunk::Null();
        }

        return file.data;
    }

    namespace
    {
        unsigned char
        Select(int           ch,
               unsigned char a,
               unsigned char b,
               unsigned char c,
               unsigned char d)
        {
            switch(ch)
            {
            case 1:  // grey
                return a;
            case 2:  // grey, alpha
                return b;
            case 3:  // red, green, blue
                return c;
            case 4:  // red, green, blue, alpha
                return d;
            default: DIE("unhandled Select channel"); return 0;
            }
        }
    }  // namespace

    ImageLoadResult
    LoadImage(vfs::FileSystem* fs, const std::string& path, AlphaLoad alpha)
    {
        auto file_memory = fs->ReadFile(path);
        if(file_memory == nullptr)
        {
            ImageLoadResult result;
            result.error = "File doesnt exist";
            result.image.MakeInvalid();
            LOG_ERROR("Failed to open " << path << ": File doesnt exist.");
            return result;
        }

        return LoadImage(file_memory, path, alpha);
    }

    ImageLoadResult
    LoadImage(
            std::shared_ptr<MemoryChunk> file_memory,
            const std::string&           path,
            AlphaLoad                    alpha)
    {
        int channels     = 0;
        int image_width  = 0;
        int image_height = 0;

        // signed to unsigned cast is probably ok since both are considered to be
        // a chuck of memory
        // https://stackoverflow.com/questions/310451/should-i-use-static-cast-or-reinterpret-cast-when-casting-a-void-to-whatever
        unsigned char* data = stbi_load_from_memory(
                reinterpret_cast<unsigned char*>(
                        file_memory->GetData()),  // NOLINT
                file_memory->GetSize(),
                &image_width,
                &image_height,
                &channels,
                0);

        if(data == nullptr)
        {
            ImageLoadResult result;
            result.error = stbi_failure_reason();
            result.image.MakeInvalid();
            LOG_ERROR("Failed to read " << path << ": " << result.error);
            return result;
        }

        bool has_alpha = false;
        if(alpha == AlphaLoad::Keep)
        {
            has_alpha = channels == 2 || channels == 4;
        }

        LOG_INFO(
                "Image: " << path << " " << image_width << "x" << image_height
                          << " alpha " << has_alpha << " channels "
                          << channels);

        ImageLoadResult result;
        if(has_alpha)
        {
            result.image.SetupWithAlphaSupport(image_width, image_height, -1);
        }
        else
        {
            result.image.SetupNoAlphaSupport(image_width, image_height, -1);
        }

        for(int y = 0; y < image_height; ++y)
        {
            for(int x = 0; x < image_width; ++x)
            {
                const int src_index = (y * image_width + x) * channels;

                // get component values
                const unsigned char zero = 0;
                const unsigned char c1
                        = data[src_index + 0];  // NOLINT no garbage value
                const unsigned char c2
                        = (channels <= 1) ? zero : data[src_index + 1];
                const unsigned char c3
                        = (channels <= 2) ? zero : data[src_index + 2];
                const unsigned char c4
                        = (channels <= 3) ? zero : data[src_index + 3];

                // Gray, Gray+alpha, RGB, RGB+alpha:     gr   gra  rgb  rgba
                const unsigned char r = c1;  //           c1   c1   c1    c1
                const unsigned char g = Select(channels, c1, c1, c2, c2);
                const unsigned char b = Select(channels, c1, c1, c3, c3);
                const unsigned char a = Select(channels, 255, c2, 255, c4);

                result.image.SetPixel(x, image_height - (y + 1), r, g, b, a);
            }
        }

        stbi_image_free(data);
        return result;
    }

    ImageLoadResult
    LoadImage(
            void* compressed_data,
            int compressed_size,
            const std::string&           path,
            AlphaLoad                    alpha)
    {
        Decompress dec;
        const unsigned int decompressed_size = Decompress::stb_decompress_length((const unsigned char*)compressed_data);
        auto decompressed = MemoryChunk::Alloc(decompressed_size);
        const auto len = dec.stb_decompress(reinterpret_cast<unsigned char*>(decompressed->GetData()),
            reinterpret_cast<const unsigned char*>(compressed_data),
            static_cast<unsigned int>(compressed_size));
        if(len == 0)
        {
            ImageLoadResult result;
            result.error = "failed to decompress before loading image";
            result.image.MakeInvalid();
            return result;
        }

        return LoadImage(decompressed, path, alpha);
    }

}  // namespace euphoria::core
<|endoftext|>


<commit_before>// @(#)root/graf:$Name:  $:$Id: TMarker.cxx,v 1.4 2000/11/21 20:26:41 brun Exp $
// Author: Rene Brun   12/05/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <stdlib.h>
#include <fstream.h>
#include <iostream.h>

#include "TROOT.h"
#include "TVirtualPad.h"
#include "TMarker.h"
#include "TVirtualX.h"
#include "TMath.h"
#include "TPoint.h"
#include "TText.h"

ClassImp(TMarker)

//______________________________________________________________________________
//
// Manages Markers. Marker attributes are managed by TAttMarker.
// The list of standard ROOT markers is shown in this picture
//Begin_Html
/*

*/
//End_Html
//

//______________________________________________________________________________
TMarker::TMarker(): TObject(), TAttMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker default constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  ==========================
   fX = 0;
   fY = 0;
}
//______________________________________________________________________________
TMarker::TMarker(Double_t x, Double_t y, Int_t marker)
      :TObject(), TAttMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker normal constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
   fX = x;
   fY = y;
   fMarkerStyle = marker;
}

//______________________________________________________________________________
TMarker::~TMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker default destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
}

//______________________________________________________________________________
TMarker::TMarker(const TMarker &marker)
{
   ((TMarker&)marker).Copy(*this);
}

//______________________________________________________________________________
void TMarker::Copy(TObject &obj)
{
//*-*-*-*-*-*-*-*-*-*-*Copy this marker to marker*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  ==========================

   TObject::Copy(obj);
   TAttMarker::Copy(((TMarker&)obj));
   ((TMarker&)obj).fX = fX;
   ((TMarker&)obj).fY = fY;
}

//______________________________________________________________________________
void TMarker::DisplayMarkerTypes()
{
//*-*-*-*-*-*-*-*-*-*-*Display the table of markers with their numbers*-*-*-*
//*-*                  ===============================================

  TMarker *marker = new TMarker();
  marker->SetMarkerSize(3);
  TText *text = new TText();
  text->SetTextFont(62);
  text->SetTextAlign(22);
  text->SetTextSize(0.1);
  char atext[] = "       ";
  Double_t x = 0;
  Double_t dx = 1/12.0;
  for (Int_t i=1;i<12;i++) {
     x += dx;
     sprintf(atext,"%d",i);
     marker->SetMarkerStyle(i);
     marker->DrawMarker(x,.35);
     text->DrawText(x,.17,atext);
     sprintf(atext,"%d",i+19);
     marker->SetMarkerStyle(i+19);
     marker->DrawMarker(x,.8);
     text->DrawText(x,.62,atext);
  }
  delete marker;
  delete text;
}

//______________________________________________________________________________
Int_t TMarker::DistancetoPrimitive(Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Compute distance from point px,py to a marker*-*-*-*-*-*
//*-*                  ===========================================
//  Compute the closest distance of approach from point px,py to this marker.
//  The distance is computed in pixels units.
//

   const Int_t kMaxDiff = 10;
   Int_t pxm  = gPad->XtoAbsPixel(fX);
   Int_t pym  = gPad->YtoAbsPixel(fY);
   Int_t dist = (px-pxm)*(px-pxm) + (py-pym)*(py-pym);

   if (dist > kMaxDiff) return 9999;
   return dist;
}

//______________________________________________________________________________
void TMarker::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with its current attributes*-*-*-*-*-*-*
//*-*                  ============================================

   AppendPad(option);

}

//______________________________________________________________________________
void TMarker::DrawMarker(Double_t x, Double_t y)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with new coordinates*-*-*-*-*-*-*-*-*-*
//*-*                  =====================================
   TMarker *newmarker = new TMarker(x, y, 1);
   TAttMarker::Copy(*newmarker);
   newmarker->SetBit(kCanDelete);
   newmarker->AppendPad();
}

//______________________________________________________________________________
void TMarker::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-*
//*-*                  =========================================
//  This member function is called when a marker is clicked with the locator
//
//  If Left button is clicked on a marker, the marker is moved to
//     a new position when the mouse button is released.
//

   TPoint p;
   static Int_t pxold, pyold;

   if (!gPad->IsEditable()) return;

   switch (event) {

   case kButton1Down:
      gVirtualX->SetTextColor(-1);  // invalidate current text color (use xor mode)
      TAttMarker::Modify();  //Change marker attributes only if necessary

      // No break !!!

   case kMouseMotion:
      pxold = px;  pyold = py;
      gPad->SetCursor(kMove);
      break;

   case kButton1Motion:
      p.fX = pxold; p.fY = pyold;
      gVirtualX->DrawPolyMarker(1, &p);
      p.fX = px; p.fY = py;
      gVirtualX->DrawPolyMarker(1, &p);
      pxold = px;  pyold = py;
      break;

   case kButton1Up:
      fX = gPad->AbsPixeltoX(px);
      fY = gPad->AbsPixeltoY(py);
      gPad->Modified(kTRUE);
      gVirtualX->SetTextColor(-1);
      break;
   }
}

//______________________________________________________________________________
void TMarker::ls(Option_t *) const
{
//*-*-*-*-*-*-*-*-*-*-*-*List this marker with its attributes*-*-*-*-*-*-*-*-*
//*-*                    ====================================
   TROOT::IndentLevel();
   printf("Marker  X=%f Y=%f marker type=%d\n",fX,fY,fMarkerStyle);
}

//______________________________________________________________________________
void TMarker::Paint(Option_t *)
{
//*-*-*-*-*-*-*-*-*-*-*Paint this marker with its current attributes*-*-*-*-*-*-*
//*-*                  =============================================
   PaintMarker(fX,fY);
}

//______________________________________________________________________________
void TMarker::PaintMarker(Double_t x, Double_t y)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with new coordinates*-*-*-*-*-*-*-*-*-*
//*-*                  =====================================

   TAttMarker::Modify();  //Change line attributes only if necessary
   gPad->PaintPolyMarker(1,&x,&y,"");
}

//______________________________________________________________________________
void TMarker::PaintMarkerNDC(Double_t, Double_t)
{
//*-*-*-*-*-*-*-*Draw this marker with new coordinates in NDC*-*-*-*-*-*-*-*-*-*
//*-*            ============================================

}

//______________________________________________________________________________
void TMarker::Print(Option_t *) const
{
//*-*-*-*-*-*-*-*-*-*-*Dump this marker with its attributes*-*-*-*-*-*-*-*-*-*
//*-*                  ====================================

   printf("Marker  X=%f Y=%f",fX,fY);
   if (GetMarkerColor() != 1) printf(" Color=%d",GetMarkerColor());
   if (GetMarkerStyle() != 1) printf(" MarkerStyle=%d",GetMarkerStyle());
   if (GetMarkerSize()  != 1) printf(" MarkerSize=%f",GetMarkerSize());
   printf("\n");
}

//______________________________________________________________________________
void TMarker::SavePrimitive(ofstream &out, Option_t *)
{
    // Save primitive as a C++ statement(s) on output stream out

   if (gROOT->ClassSaved(TMarker::Class())) {
       out<<"   ";
   } else {
       out<<"   TMarker *";
   }
   out<<"marker = new TMarker("<<fX<<","<<fY<<","<<fMarkerStyle<<");"<<endl;

   SaveMarkerAttributes(out,"marker",1,1,1);

   out<<"   marker->Draw();"<<endl;
}

//______________________________________________________________________________
void TMarker::Streamer(TBuffer &R__b)
{
   // Stream an object of class TMarker.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         TMarker::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      TObject::Streamer(R__b);
      TAttMarker::Streamer(R__b);
      Float_t x,y;
      R__b >> x;  fX = x;
      R__b >> y;  fY = y;
      //====end of old versions

   } else {
      TMarker::Class()->WriteBuffer(R__b,this);
   }
}
<commit_msg>In TMarker::Paintmarker, disable clip to frame by default. TMarkers may be used by TLegend and should not be clipped in this case to the frame boundary.<commit_after>// @(#)root/graf:$Name:  $:$Id: TMarker.cxx,v 1.5 2000/12/13 15:13:50 brun Exp $
// Author: Rene Brun   12/05/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include <stdlib.h>
#include <fstream.h>
#include <iostream.h>

#include "TROOT.h"
#include "TVirtualPad.h"
#include "TMarker.h"
#include "TVirtualX.h"
#include "TMath.h"
#include "TPoint.h"
#include "TText.h"

ClassImp(TMarker)

//______________________________________________________________________________
//
// Manages Markers. Marker attributes are managed by TAttMarker.
// The list of standard ROOT markers is shown in this picture
//Begin_Html
/*

*/
//End_Html
//

//______________________________________________________________________________
TMarker::TMarker(): TObject(), TAttMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker default constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  ==========================
   fX = 0;
   fY = 0;
}
//______________________________________________________________________________
TMarker::TMarker(Double_t x, Double_t y, Int_t marker)
      :TObject(), TAttMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker normal constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
   fX = x;
   fY = y;
   fMarkerStyle = marker;
}

//______________________________________________________________________________
TMarker::~TMarker()
{
//*-*-*-*-*-*-*-*-*-*-*Marker default destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  =========================
}

//______________________________________________________________________________
TMarker::TMarker(const TMarker &marker)
{
   ((TMarker&)marker).Copy(*this);
}

//______________________________________________________________________________
void TMarker::Copy(TObject &obj)
{
//*-*-*-*-*-*-*-*-*-*-*Copy this marker to marker*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                  ==========================

   TObject::Copy(obj);
   TAttMarker::Copy(((TMarker&)obj));
   ((TMarker&)obj).fX = fX;
   ((TMarker&)obj).fY = fY;
}

//______________________________________________________________________________
void TMarker::DisplayMarkerTypes()
{
//*-*-*-*-*-*-*-*-*-*-*Display the table of markers with their numbers*-*-*-*
//*-*                  ===============================================

  TMarker *marker = new TMarker();
  marker->SetMarkerSize(3);
  TText *text = new TText();
  text->SetTextFont(62);
  text->SetTextAlign(22);
  text->SetTextSize(0.1);
  char atext[] = "       ";
  Double_t x = 0;
  Double_t dx = 1/12.0;
  for (Int_t i=1;i<12;i++) {
     x += dx;
     sprintf(atext,"%d",i);
     marker->SetMarkerStyle(i);
     marker->DrawMarker(x,.35);
     text->DrawText(x,.17,atext);
     sprintf(atext,"%d",i+19);
     marker->SetMarkerStyle(i+19);
     marker->DrawMarker(x,.8);
     text->DrawText(x,.62,atext);
  }
  delete marker;
  delete text;
}

//______________________________________________________________________________
Int_t TMarker::DistancetoPrimitive(Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Compute distance from point px,py to a marker*-*-*-*-*-*
//*-*                  ===========================================
//  Compute the closest distance of approach from point px,py to this marker.
//  The distance is computed in pixels units.
//

   const Int_t kMaxDiff = 10;
   Int_t pxm  = gPad->XtoAbsPixel(fX);
   Int_t pym  = gPad->YtoAbsPixel(fY);
   Int_t dist = (px-pxm)*(px-pxm) + (py-pym)*(py-pym);

   if (dist > kMaxDiff) return 9999;
   return dist;
}

//______________________________________________________________________________
void TMarker::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with its current attributes*-*-*-*-*-*-*
//*-*                  ============================================

   AppendPad(option);

}

//______________________________________________________________________________
void TMarker::DrawMarker(Double_t x, Double_t y)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with new coordinates*-*-*-*-*-*-*-*-*-*
//*-*                  =====================================
   TMarker *newmarker = new TMarker(x, y, 1);
   TAttMarker::Copy(*newmarker);
   newmarker->SetBit(kCanDelete);
   newmarker->AppendPad();
}

//______________________________________________________________________________
void TMarker::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
//*-*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-*
//*-*                  =========================================
//  This member function is called when a marker is clicked with the locator
//
//  If Left button is clicked on a marker, the marker is moved to
//     a new position when the mouse button is released.
//

   TPoint p;
   static Int_t pxold, pyold;

   if (!gPad->IsEditable()) return;

   switch (event) {

   case kButton1Down:
      gVirtualX->SetTextColor(-1);  // invalidate current text color (use xor mode)
      TAttMarker::Modify();  //Change marker attributes only if necessary

      // No break !!!

   case kMouseMotion:
      pxold = px;  pyold = py;
      gPad->SetCursor(kMove);
      break;

   case kButton1Motion:
      p.fX = pxold; p.fY = pyold;
      gVirtualX->DrawPolyMarker(1, &p);
      p.fX = px; p.fY = py;
      gVirtualX->DrawPolyMarker(1, &p);
      pxold = px;  pyold = py;
      break;

   case kButton1Up:
      fX = gPad->AbsPixeltoX(px);
      fY = gPad->AbsPixeltoY(py);
      gPad->Modified(kTRUE);
      gVirtualX->SetTextColor(-1);
      break;
   }
}

//______________________________________________________________________________
void TMarker::ls(Option_t *) const
{
//*-*-*-*-*-*-*-*-*-*-*-*List this marker with its attributes*-*-*-*-*-*-*-*-*
//*-*                    ====================================
   TROOT::IndentLevel();
   printf("Marker  X=%f Y=%f marker type=%d\n",fX,fY,fMarkerStyle);
}

//______________________________________________________________________________
void TMarker::Paint(Option_t *)
{
//*-*-*-*-*-*-*-*-*-*-*Paint this marker with its current attributes*-*-*-*-*-*-*
//*-*                  =============================================
   PaintMarker(fX,fY);
}

//______________________________________________________________________________
void TMarker::PaintMarker(Double_t x, Double_t y)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this marker with new coordinates*-*-*-*-*-*-*-*-*-*
//*-*                  =====================================

   TAttMarker::Modify();  //Change line attributes only if necessary
   gPad->PaintPolyMarker(-1,&x,&y,"");
}

//______________________________________________________________________________
void TMarker::PaintMarkerNDC(Double_t, Double_t)
{
//*-*-*-*-*-*-*-*Draw this marker with new coordinates in NDC*-*-*-*-*-*-*-*-*-*
//*-*            ============================================

}

//______________________________________________________________________________
void TMarker::Print(Option_t *) const
{
//*-*-*-*-*-*-*-*-*-*-*Dump this marker with its attributes*-*-*-*-*-*-*-*-*-*
//*-*                  ====================================

   printf("Marker  X=%f Y=%f",fX,fY);
   if (GetMarkerColor() != 1) printf(" Color=%d",GetMarkerColor());
   if (GetMarkerStyle() != 1) printf(" MarkerStyle=%d",GetMarkerStyle());
   if (GetMarkerSize()  != 1) printf(" MarkerSize=%f",GetMarkerSize());
   printf("\n");
}

//______________________________________________________________________________
void TMarker::SavePrimitive(ofstream &out, Option_t *)
{
    // Save primitive as a C++ statement(s) on output stream out

   if (gROOT->ClassSaved(TMarker::Class())) {
       out<<"   ";
   } else {
       out<<"   TMarker *";
   }
   out<<"marker = new TMarker("<<fX<<","<<fY<<","<<fMarkerStyle<<");"<<endl;

   SaveMarkerAttributes(out,"marker",1,1,1);

   out<<"   marker->Draw();"<<endl;
}

//______________________________________________________________________________
void TMarker::Streamer(TBuffer &R__b)
{
   // Stream an object of class TMarker.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 1) {
         TMarker::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      TObject::Streamer(R__b);
      TAttMarker::Streamer(R__b);
      Float_t x,y;
      R__b >> x;  fX = x;
      R__b >> y;  fY = y;
      //====end of old versions

   } else {
      TMarker::Class()->WriteBuffer(R__b,this);
   }
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <src/global/qbuildcfg.h>
#include "qsensorpluginloader_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>

#include "qsensorplugin.h"

QTM_BEGIN_NAMESPACE

QSensorPluginLoader::QSensorPluginLoader(const char *iid, const QString &location)
    : m_iid(iid)
{
    m_location = location + QLatin1String("/");
    load();
}

QSensorPluginLoader::~QSensorPluginLoader()
{
    Q_FOREACH (QPluginLoader *loader, m_loaders) {
        bool ok = loader->unload();
        if (!ok) qWarning() << "Cannot unload" << loader->fileName();
        delete loader;
    }
}

void QSensorPluginLoader::load()
{
    if (!m_plugins.isEmpty())
        return;

    QStringList     paths = QCoreApplication::libraryPaths();
    QString val = qt_mobility_configure_prefix_path_str;
    if(val.length() > 0){
        val += "/plugins";
        paths << val;
    }

    Q_FOREACH (QString const &path, paths) {
        QString pluginPathName(path + m_location);
        QDir pluginDir(pluginPathName);

        if (!pluginDir.exists())
            continue;

        Q_FOREACH (QString pluginLib, pluginDir.entryList(QDir::Files)) {
            QPluginLoader *loader = new QPluginLoader(pluginPathName + pluginLib);

            QObject *o = loader->instance();
            if (o != 0 && o->qt_metacast(m_iid) != 0) {
                QSensorPluginInterface *p = qobject_cast<QSensorPluginInterface*>(o);
                if (p != 0) {
                    m_plugins << p;
                    m_loaders << loader;
                } else {
                    loader->unload();
                    delete loader;
                }

                continue;
            } else {
                qWarning() << "QSensorPluginLoader: Failed to load plugin: " << pluginLib << loader->errorString();
            }
            delete o;
            loader->unload();
            delete loader;
        }
    }
}

QTM_END_NAMESPACE

<commit_msg>Fix some raw latin1 strings that got introduced.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <src/global/qbuildcfg.h>
#include "qsensorpluginloader_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>

#include "qsensorplugin.h"

QTM_BEGIN_NAMESPACE

QSensorPluginLoader::QSensorPluginLoader(const char *iid, const QString &location)
    : m_iid(iid)
{
    m_location = location + QLatin1String("/");
    load();
}

QSensorPluginLoader::~QSensorPluginLoader()
{
    Q_FOREACH (QPluginLoader *loader, m_loaders) {
        bool ok = loader->unload();
        if (!ok) qWarning() << "Cannot unload" << loader->fileName();
        delete loader;
    }
}

void QSensorPluginLoader::load()
{
    if (!m_plugins.isEmpty())
        return;

    QStringList     paths = QCoreApplication::libraryPaths();
    QString val = QLatin1String(qt_mobility_configure_prefix_path_str);
    if(val.length() > 0){
        val += QLatin1String("/plugins");
        paths << val;
    }

    Q_FOREACH (QString const &path, paths) {
        QString pluginPathName(path + m_location);
        QDir pluginDir(pluginPathName);

        if (!pluginDir.exists())
            continue;

        Q_FOREACH (QString pluginLib, pluginDir.entryList(QDir::Files)) {
            QPluginLoader *loader = new QPluginLoader(pluginPathName + pluginLib);

            QObject *o = loader->instance();
            if (o != 0 && o->qt_metacast(m_iid) != 0) {
                QSensorPluginInterface *p = qobject_cast<QSensorPluginInterface*>(o);
                if (p != 0) {
                    m_plugins << p;
                    m_loaders << loader;
                } else {
                    loader->unload();
                    delete loader;
                }

                continue;
            } else {
                qWarning() << "QSensorPluginLoader: Failed to load plugin: " << pluginLib << loader->errorString();
            }
            delete o;
            loader->unload();
            delete loader;
        }
    }
}

QTM_END_NAMESPACE

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsensorpluginloader_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>

#include "qsensorplugin.h"
#include "qmobilitypluginsearch.h"

QT_BEGIN_NAMESPACE

QSensorPluginLoader::QSensorPluginLoader()
{
    load();
}

QSensorPluginLoader::~QSensorPluginLoader()
{
    Q_FOREACH (QPluginLoader *loader, m_loaders) {
        bool ok = loader->unload();
        if (!ok) qWarning() << "Cannot unload" << loader->fileName();
        delete loader;
    }
}

QList<QObject*> QSensorPluginLoader::plugins() const
{
    return m_plugins;
}

void QSensorPluginLoader::load()
{
    if (!m_plugins.isEmpty())
        return;

    QStringList plugins = mobilityPlugins(QLatin1String("sensors"));

    /* Now discover the dynamic plugins */
    for (int i = 0; i < plugins.count(); i++) {
        QPluginLoader *loader = new QPluginLoader(plugins.at(i));

        QObject *o = loader->instance();
        if (o != 0) {
            QSensorPluginInterface *p = qobject_cast<QSensorPluginInterface*>(o);
            if (p != 0) {
                m_plugins << o;
                m_loaders << loader;
            } else {
                loader->unload();
                delete loader;
            }

            continue;
        }
        delete o;
        loader->unload();
        delete loader;
    }
}

QT_END_NAMESPACE

<commit_msg>report errors when plugins can't be loaded<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qsensorpluginloader_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>

#include "qsensorplugin.h"
#include "qmobilitypluginsearch.h"

QT_BEGIN_NAMESPACE

QSensorPluginLoader::QSensorPluginLoader()
{
    load();
}

QSensorPluginLoader::~QSensorPluginLoader()
{
    Q_FOREACH (QPluginLoader *loader, m_loaders) {
        bool ok = loader->unload();
        if (!ok) qWarning() << "Cannot unload" << loader->fileName();
        delete loader;
    }
}

QList<QObject*> QSensorPluginLoader::plugins() const
{
    return m_plugins;
}

void QSensorPluginLoader::load()
{
    if (!m_plugins.isEmpty())
        return;

    QStringList plugins = mobilityPlugins(QLatin1String("sensors"));
    bool reportErrors = (qgetenv("QT_DEBUG_PLUGINS") == "1");

    /* Now discover the dynamic plugins */
    for (int i = 0; i < plugins.count(); i++) {
        QPluginLoader *loader = new QPluginLoader(plugins.at(i));

        QObject *o = loader->instance();
        if (o != 0) {
            QSensorPluginInterface *p = qobject_cast<QSensorPluginInterface*>(o);
            if (p != 0) {
                m_plugins << o;
                m_loaders << loader;
            } else {
                if (reportErrors) {
                    qWarning() << plugins.at(i) << "is not a QSensorPluginInterface";
                }
                loader->unload();
                delete loader;
            }

            continue;
        } else {
            if (reportErrors) {
                qWarning() << loader->errorString();
            }
        }
        delete o;
        loader->unload();
        delete loader;
    }
}

QT_END_NAMESPACE

<|endoftext|>