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

#include <realm/object-store/set.hpp>
#include <realm/object-store/impl/set_notifier.hpp>
#include <realm/object-store/impl/realm_coordinator.hpp>
#include <realm/object-store/object_schema.hpp>
#include <realm/object-store/object_store.hpp>
#include <realm/object-store/results.hpp>
#include <realm/object-store/schema.hpp>
#include <realm/object-store/shared_realm.hpp>

namespace realm::object_store {
using namespace _impl;

Set::Set() noexcept = default;
Set::~Set() = default;
Set::Set(const Set&) = default;
Set::Set(Set&&) = default;
Set& Set::operator=(const Set&) = default;
Set& Set::operator=(Set&&) = default;

Set::Set(std::shared_ptr<Realm> r, const Obj& parent_obj, ColKey col)
    : Collection(std::move(r), parent_obj, col)
    , m_set_base(std::dynamic_pointer_cast<SetBase>(m_coll_base))
{
}

Set::Set(std::shared_ptr<Realm> r, const SetBase& set)
    : Collection(std::move(r), set)
    , m_set_base(std::dynamic_pointer_cast<SetBase>(m_coll_base))
{
}

Query Set::get_query() const
{
    verify_attached();
    if (m_type == PropertyType::Object) {
        return static_cast<LnkSet&>(*m_set_base).get_target_table()->where(as<Obj>());
    }
    throw std::runtime_error("not implemented");
}

ConstTableRef Set::get_target_table() const
{
    auto table = m_set_base->get_table();
    auto col = m_set_base->get_col_key();
    if (col.get_type() != col_type_Link)
        return nullptr;
    return table->get_link_target(col);
}

template <class T>
size_t Set::find(const T& value) const
{
    verify_attached();
    return as<T>().find(value);
}

size_t Set::find(Query&& q) const
{
    verify_attached();
    if (m_type == PropertyType::Object) {
        ObjKey key = get_query().and_query(std::move(q)).find();
        return key ? as<Obj>().find_first(key) : not_found;
    }
    throw std::runtime_error("not implemented");
}

template <typename T>
T Set::get(size_t row_ndx) const
{
    verify_valid_row(row_ndx);
    return as<T>().get(row_ndx);
}

template <class T>
std::pair<size_t, bool> Set::insert(T value)
{
    verify_in_transaction();
    return as<T>().insert(value);
}

template <class T>
std::pair<size_t, bool> Set::remove(const T& value)
{
    verify_in_transaction();
    return as<T>().erase(value);
}

util::Optional<Mixed> Set::max(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().max(col);
    size_t out_ndx = not_found;
    auto result = m_set_base->max(&out_ndx);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "max");
    }
    return out_ndx == not_found ? none : util::make_optional(result);
}

util::Optional<Mixed> Set::min(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().min(col);

    size_t out_ndx = not_found;
    auto result = m_set_base->min(&out_ndx);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "min");
    }
    return out_ndx == not_found ? none : util::make_optional(result);
}

Mixed Set::sum(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return *as_results().sum(col);

    auto result = m_set_base->sum();
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "sum");
    }
    return result;
}

util::Optional<Mixed> Set::average(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().average(col);
    size_t count = 0;
    auto result = m_set_base->avg(&count);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "average");
    }
    return count == 0 ? none : util::make_optional(result);
}

bool Set::operator==(const Set& rgt) const noexcept
{
    return m_set_base->get_table() == rgt.m_set_base->get_table() &&
           m_set_base->get_key() == rgt.m_set_base->get_key() &&
           m_set_base->get_col_key() == rgt.m_set_base->get_col_key();
}

Results Set::snapshot() const
{
    return as_results().snapshot();
}

Results Set::sort(SortDescriptor order) const
{
    verify_attached();
    if ((m_type == PropertyType::Object)) {
        return Results(m_realm, std::dynamic_pointer_cast<LnkSet>(m_set_base), util::none, std::move(order));
    }
    else {
        DescriptorOrdering o;
        o.append_sort(order);
        return Results(m_realm, m_set_base, std::move(o));
    }
}

Results Set::sort(const std::vector<std::pair<std::string, bool>>& keypaths) const
{
    return as_results().sort(keypaths);
}

Results Set::filter(Query q) const
{
    verify_attached();
    return Results(m_realm, std::dynamic_pointer_cast<LnkSet>(m_set_base), get_query().and_query(std::move(q)));
}

Set Set::freeze(const std::shared_ptr<Realm>& frozen_realm) const
{
    return Set(frozen_realm, *frozen_realm->import_copy_of(*m_set_base));
}

NotificationToken Set::add_notification_callback(CollectionChangeCallback cb) &
{
    if (m_notifier && !m_notifier->have_callbacks())
        m_notifier.reset();
    if (!m_notifier) {
        m_notifier = std::make_shared<SetNotifier>(m_realm, *m_set_base, m_type);
        RealmCoordinator::register_notifier(m_notifier);
    }
    return {m_notifier, m_notifier->add_callback(std::move(cb))};
}

#define REALM_PRIMITIVE_SET_TYPE(T)                                                                                \
    template T Set::get<T>(size_t) const;                                                                            \
    template size_t Set::find<T>(const T&) const;                                                                    \
    template std::pair<size_t, bool> Set::remove<T>(T const&);                                                       \
    template std::pair<size_t, bool> Set::insert<T>(T);

REALM_PRIMITIVE_SET_TYPE(bool)
REALM_PRIMITIVE_SET_TYPE(int64_t)
REALM_PRIMITIVE_SET_TYPE(float)
REALM_PRIMITIVE_SET_TYPE(double)
REALM_PRIMITIVE_SET_TYPE(StringData)
REALM_PRIMITIVE_SET_TYPE(BinaryData)
REALM_PRIMITIVE_SET_TYPE(Timestamp)
REALM_PRIMITIVE_SET_TYPE(ObjKey)
REALM_PRIMITIVE_SET_TYPE(ObjectId)
REALM_PRIMITIVE_SET_TYPE(Decimal)
REALM_PRIMITIVE_SET_TYPE(UUID)
REALM_PRIMITIVE_SET_TYPE(Mixed)
REALM_PRIMITIVE_SET_TYPE(util::Optional<bool>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<int64_t>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<float>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<double>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<ObjectId>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<UUID>)

#undef REALM_PRIMITIVE_SET_TYPE

template <>
std::pair<size_t, bool> Set::insert<int>(int value)
{
    return insert(int64_t(value));
}

template <>
std::pair<size_t, bool> Set::remove<int>(const int& value)
{
    return remove(int64_t(value));
}

std::pair<size_t, bool> Set::insert_any(Mixed value)
{
    verify_in_transaction();
    return m_set_base->insert_any(value);
}

Mixed Set::get_any(size_t ndx) const
{
    verify_valid_row(ndx);
    return m_set_base->get_any(ndx);
}

std::pair<size_t, bool> Set::remove_any(Mixed value)
{
    verify_in_transaction();
    return m_set_base->erase_any(value);
}

size_t Set::find_any(Mixed value) const
{
    return m_set_base->find_any(value);
}

void Set::delete_all()
{
    verify_in_transaction();
    if (m_type == PropertyType::Object)
        as<Obj>().remove_all_target_rows();
    else
        m_set_base->clear();
}

void Set::remove_all()
{
    verify_in_transaction();
    m_set_base->clear();
}

template <>
size_t Set::find<int>(const int& value) const
{
    return find(int64_t(value));
}

template <>
Obj Set::get<Obj>(size_t row_ndx) const
{
    verify_valid_row(row_ndx);
    auto& set = as<Obj>();
    return set.get_object(row_ndx);
}

template <>
size_t Set::find<Obj>(const Obj& obj) const
{
    verify_attached();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().find(obj.get_key());
}

template <>
std::pair<size_t, bool> Set::remove<Obj>(const Obj& obj)
{
    verify_in_transaction();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().erase(obj.get_key());
}

template <>
std::pair<size_t, bool> Set::insert<Obj>(Obj obj)
{
    verify_in_transaction();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().insert(obj.get_key());
}

bool Set::is_subset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_subset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_strict_subset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_strict_subset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_superset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_superset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_strict_superset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_strict_superset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::intersects(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().intersects(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::set_equals(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().set_equals(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_intersection(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_intersection(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_union(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_union(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_difference(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_difference(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_symmetric_difference(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_symmetric_difference(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

} // namespace realm::object_store

namespace {
size_t hash_combine()
{
    return 0;
}
template <typename T, typename... Rest>
size_t hash_combine(const T& v, Rest... rest)
{
    size_t h = hash_combine(rest...);
    h ^= std::hash<T>()(v) + 0x9e3779b9 + (h << 6) + (h >> 2);
    return h;
}
} // namespace

namespace std {
size_t hash<realm::object_store::Set>::operator()(realm::object_store::Set const& set) const
{
    auto& impl = *set.m_set_base;
    return hash_combine(impl.get_key().value, impl.get_table()->get_key().value, impl.get_col_key().value);
}
} // namespace std
<commit_msg>Satisfy the linter<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2020 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#include <realm/object-store/set.hpp>
#include <realm/object-store/impl/set_notifier.hpp>
#include <realm/object-store/impl/realm_coordinator.hpp>
#include <realm/object-store/object_schema.hpp>
#include <realm/object-store/object_store.hpp>
#include <realm/object-store/results.hpp>
#include <realm/object-store/schema.hpp>
#include <realm/object-store/shared_realm.hpp>

namespace realm::object_store {
using namespace _impl;

Set::Set() noexcept = default;
Set::~Set() = default;
Set::Set(const Set&) = default;
Set::Set(Set&&) = default;
Set& Set::operator=(const Set&) = default;
Set& Set::operator=(Set&&) = default;

Set::Set(std::shared_ptr<Realm> r, const Obj& parent_obj, ColKey col)
    : Collection(std::move(r), parent_obj, col)
    , m_set_base(std::dynamic_pointer_cast<SetBase>(m_coll_base))
{
}

Set::Set(std::shared_ptr<Realm> r, const SetBase& set)
    : Collection(std::move(r), set)
    , m_set_base(std::dynamic_pointer_cast<SetBase>(m_coll_base))
{
}

Query Set::get_query() const
{
    verify_attached();
    if (m_type == PropertyType::Object) {
        return static_cast<LnkSet&>(*m_set_base).get_target_table()->where(as<Obj>());
    }
    throw std::runtime_error("not implemented");
}

ConstTableRef Set::get_target_table() const
{
    auto table = m_set_base->get_table();
    auto col = m_set_base->get_col_key();
    if (col.get_type() != col_type_Link)
        return nullptr;
    return table->get_link_target(col);
}

template <class T>
size_t Set::find(const T& value) const
{
    verify_attached();
    return as<T>().find(value);
}

size_t Set::find(Query&& q) const
{
    verify_attached();
    if (m_type == PropertyType::Object) {
        ObjKey key = get_query().and_query(std::move(q)).find();
        return key ? as<Obj>().find_first(key) : not_found;
    }
    throw std::runtime_error("not implemented");
}

template <typename T>
T Set::get(size_t row_ndx) const
{
    verify_valid_row(row_ndx);
    return as<T>().get(row_ndx);
}

template <class T>
std::pair<size_t, bool> Set::insert(T value)
{
    verify_in_transaction();
    return as<T>().insert(value);
}

template <class T>
std::pair<size_t, bool> Set::remove(const T& value)
{
    verify_in_transaction();
    return as<T>().erase(value);
}

util::Optional<Mixed> Set::max(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().max(col);
    size_t out_ndx = not_found;
    auto result = m_set_base->max(&out_ndx);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "max");
    }
    return out_ndx == not_found ? none : util::make_optional(result);
}

util::Optional<Mixed> Set::min(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().min(col);

    size_t out_ndx = not_found;
    auto result = m_set_base->min(&out_ndx);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "min");
    }
    return out_ndx == not_found ? none : util::make_optional(result);
}

Mixed Set::sum(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return *as_results().sum(col);

    auto result = m_set_base->sum();
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "sum");
    }
    return result;
}

util::Optional<Mixed> Set::average(ColKey col) const
{
    if (get_type() == PropertyType::Object)
        return as_results().average(col);
    size_t count = 0;
    auto result = m_set_base->avg(&count);
    if (result.is_null()) {
        throw realm::Results::UnsupportedColumnTypeException(m_set_base->get_col_key(), m_set_base->get_table(),
                                                             "average");
    }
    return count == 0 ? none : util::make_optional(result);
}

bool Set::operator==(const Set& rgt) const noexcept
{
    return m_set_base->get_table() == rgt.m_set_base->get_table() &&
           m_set_base->get_key() == rgt.m_set_base->get_key() &&
           m_set_base->get_col_key() == rgt.m_set_base->get_col_key();
}

Results Set::snapshot() const
{
    return as_results().snapshot();
}

Results Set::sort(SortDescriptor order) const
{
    verify_attached();
    if ((m_type == PropertyType::Object)) {
        return Results(m_realm, std::dynamic_pointer_cast<LnkSet>(m_set_base), util::none, std::move(order));
    }
    else {
        DescriptorOrdering o;
        o.append_sort(order);
        return Results(m_realm, m_set_base, std::move(o));
    }
}

Results Set::sort(const std::vector<std::pair<std::string, bool>>& keypaths) const
{
    return as_results().sort(keypaths);
}

Results Set::filter(Query q) const
{
    verify_attached();
    return Results(m_realm, std::dynamic_pointer_cast<LnkSet>(m_set_base), get_query().and_query(std::move(q)));
}

Set Set::freeze(const std::shared_ptr<Realm>& frozen_realm) const
{
    return Set(frozen_realm, *frozen_realm->import_copy_of(*m_set_base));
}

NotificationToken Set::add_notification_callback(CollectionChangeCallback cb) &
{
    if (m_notifier && !m_notifier->have_callbacks())
        m_notifier.reset();
    if (!m_notifier) {
        m_notifier = std::make_shared<SetNotifier>(m_realm, *m_set_base, m_type);
        RealmCoordinator::register_notifier(m_notifier);
    }
    return {m_notifier, m_notifier->add_callback(std::move(cb))};
}

#define REALM_PRIMITIVE_SET_TYPE(T)                                                                                \
    template T Set::get<T>(size_t) const;                                                                            \
    template size_t Set::find<T>(const T&) const;                                                                    \
    template std::pair<size_t, bool> Set::remove<T>(T const&);                                                       \
    template std::pair<size_t, bool> Set::insert<T>(T);

REALM_PRIMITIVE_SET_TYPE(bool)
REALM_PRIMITIVE_SET_TYPE(int64_t)
REALM_PRIMITIVE_SET_TYPE(float)
REALM_PRIMITIVE_SET_TYPE(double)
REALM_PRIMITIVE_SET_TYPE(StringData)
REALM_PRIMITIVE_SET_TYPE(BinaryData)
REALM_PRIMITIVE_SET_TYPE(Timestamp)
REALM_PRIMITIVE_SET_TYPE(ObjKey)
REALM_PRIMITIVE_SET_TYPE(ObjectId)
REALM_PRIMITIVE_SET_TYPE(Decimal)
REALM_PRIMITIVE_SET_TYPE(UUID)
REALM_PRIMITIVE_SET_TYPE(Mixed)
REALM_PRIMITIVE_SET_TYPE(util::Optional<bool>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<int64_t>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<float>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<double>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<ObjectId>)
REALM_PRIMITIVE_SET_TYPE(util::Optional<UUID>)

#undef REALM_PRIMITIVE_SET_TYPE

template <>
std::pair<size_t, bool> Set::insert<int>(int value)
{
    return insert(int64_t(value));
}

template <>
std::pair<size_t, bool> Set::remove<int>(const int& value)
{
    return remove(int64_t(value));
}

std::pair<size_t, bool> Set::insert_any(Mixed value)
{
    verify_in_transaction();
    return m_set_base->insert_any(value);
}

Mixed Set::get_any(size_t ndx) const
{
    verify_valid_row(ndx);
    return m_set_base->get_any(ndx);
}

std::pair<size_t, bool> Set::remove_any(Mixed value)
{
    verify_in_transaction();
    return m_set_base->erase_any(value);
}

size_t Set::find_any(Mixed value) const
{
    return m_set_base->find_any(value);
}

void Set::delete_all()
{
    verify_in_transaction();
    if (m_type == PropertyType::Object)
        as<Obj>().remove_all_target_rows();
    else
        m_set_base->clear();
}

void Set::remove_all()
{
    verify_in_transaction();
    m_set_base->clear();
}

template <>
size_t Set::find<int>(const int& value) const
{
    return find(int64_t(value));
}

template <>
Obj Set::get<Obj>(size_t row_ndx) const
{
    verify_valid_row(row_ndx);
    auto& set = as<Obj>();
    return set.get_object(row_ndx);
}

template <>
size_t Set::find<Obj>(const Obj& obj) const
{
    verify_attached();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().find(obj.get_key());
}

template <>
std::pair<size_t, bool> Set::remove<Obj>(const Obj& obj)
{
    verify_in_transaction();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().erase(obj.get_key());
}

template <>
std::pair<size_t, bool> Set::insert<Obj>(Obj obj)
{
    verify_in_transaction();
    validate(obj);
    // FIXME: Handle Mixed / ObjLink
    return as<ObjKey>().insert(obj.get_key());
}

bool Set::is_subset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_subset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_strict_subset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_strict_subset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_superset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_superset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::is_strict_superset_of(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().is_strict_superset_of(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::intersects(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().intersects(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

bool Set::set_equals(const Set& rhs) const
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().set_equals(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_intersection(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_intersection(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_union(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_union(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_difference(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_difference(rhs.as<std::decay_t<decltype(*t)>>());
    });
}

void Set::assign_symmetric_difference(const Set& rhs)
{
    return dispatch([&](auto t) {
        return this->as<std::decay_t<decltype(*t)>>().assign_symmetric_difference(
            rhs.as<std::decay_t<decltype(*t)>>());
    });
}

} // namespace realm::object_store

namespace {
size_t hash_combine()
{
    return 0;
}
template <typename T, typename... Rest>
size_t hash_combine(const T& v, Rest... rest)
{
    size_t h = hash_combine(rest...);
    h ^= std::hash<T>()(v) + 0x9e3779b9 + (h << 6) + (h >> 2);
    return h;
}
} // namespace

namespace std {
size_t hash<realm::object_store::Set>::operator()(realm::object_store::Set const& set) const
{
    auto& impl = *set.m_set_base;
    return hash_combine(impl.get_key().value, impl.get_table()->get_key().value, impl.get_col_key().value);
}
} // namespace std
<|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \brief Constructs a ByteStream object with a stream
	*/

	inline ByteStream::ByteStream(Stream* stream)
	{
		m_context.stream = stream;
	}

	/*!
	* \brief Constructs a ByteStream object by move semantic
	*
	* \param stream ByteStream to move into this
	*/

	inline ByteStream::ByteStream(ByteStream&& stream) :
	m_ownedStream(std::move(stream.m_ownedStream)),
	m_context(stream.m_context)
	{
		stream.m_context.stream = nullptr;
	}

	/*!
	* \brief Destructs the object and calls FlushBits
	*
	* \remark Produces a NazaraWarning if flush did not work
	*
	* \see FlushBits
	*/

	inline ByteStream::~ByteStream()
	{
		if (!FlushBits())
			NazaraWarning("Failed to flush bits at serializer destruction");
	}

	/*!
	* \brief Gets the stream endianness
	* \return Type of the endianness
	*/

	inline Endianness ByteStream::GetDataEndianness() const
	{
		return m_context.endianness;
	}

	/*!
	* \brief Gets the size of the byte stream
	* \return Size of the stream
	*/

	inline Nz::UInt64 ByteStream::GetSize() const
	{
		if (m_context.stream)
			return m_context.stream->GetSize();
		else
			return 0;
	}

	/*!
	* \brief Gets the internal stream
	* \return Internal stream
	*/

	inline Stream* ByteStream::GetStream() const
	{
		return m_context.stream;
	}

	/*!
	* \brief Flushes the stream
	* \return true if flushing is successful
	*/

	inline bool ByteStream::FlushBits()
	{
		if (!m_context.stream)
			return true;

		if (m_context.currentBitPos != 8)
		{
			m_context.currentBitPos = 8; //< To prevent Serialize to flush bits itself

			if (!Serialize(m_context, m_context.currentByte))
				return false;
		}

		return true;
	}

	/*!
	* \brief Reads data
	* \return Number of data read
	*
	* \param ptr Preallocated buffer to contain information read
	* \param size Size of the read and thus of the buffer
	*/

	inline std::size_t ByteStream::Read(void* ptr, std::size_t size)
	{
		if (!m_context.stream)
			OnEmptyStream();

		FlushBits();
		return m_context.stream->Read(ptr, size);
	}

	/*!
	* \brief Sets the stream endianness
	*
	* \param endiannes Type of the endianness
	*/

	inline void ByteStream::SetDataEndianness(Endianness endiannes)
	{
		m_context.endianness = endiannes;
	}

	/*!
	* \brief Sets this with a stream
	*
	* \param stream Stream existing
	*
	* \remark Produces a NazaraAssert if stream is invalid
	*/

	inline void ByteStream::SetStream(Stream* stream)
	{
		NazaraAssert(stream, "Invalid stream");

		// We don't want to lose some bits..
		FlushBits();

		m_context.stream = stream;
		m_ownedStream.reset();
	}

	/*!
	* \brief Writes data
	* \return Number of data written
	*
	* \param buffer Preallocated buffer containing information to write
	* \param size Size of the writting and thus of the buffer
	*
	* \remark Produces a NazaraAssert if buffer is nullptr
	*/

	inline std::size_t ByteStream::Write(const void* data, std::size_t size)
	{
		if (!m_context.stream)
			OnEmptyStream();

		FlushBits();
		return m_context.stream->Write(data, size);
	}

	/*!
	* \brief Outputs a data from the stream
	* \return A reference to this
	*
	* \param value Value to unserialize
	*
	* \remark Produces a NazaraError if unserialization failed
	*/

	template<typename T>
	ByteStream& ByteStream::operator>>(T& value)
	{
		if (!m_context.stream)
			OnEmptyStream();

		if (!Unserialize(m_context, &value))
			NazaraError("Failed to serialize value");

		return *this;
	}

	/*!
	* \brief Adds the data to the stream
	* \return A reference to this
	*
	* \param value Value to serialize
	*
	* \remark Produces a NazaraError if serialization failed
	*/

	template<typename T>
	ByteStream& ByteStream::operator<<(const T& value)
	{
		if (!m_context.stream)
			OnEmptyStream();

		if (!Serialize(m_context, value))
			NazaraError("Failed to serialize value");

		return *this;
	}

	/*!
	* \brief Moves the other byte stream into this
	* \return A reference to this
	*
	* \param stream ByteStream to move in this
	*/

	inline ByteStream& ByteStream::operator=(ByteStream&& stream)
	{
		m_context = stream.m_context;
		m_ownedStream = std::move(stream.m_ownedStream);

		stream.m_context.stream = nullptr;

		return *this;
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Fix compilation<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \brief Constructs a ByteStream object with a stream
	*/

	inline ByteStream::ByteStream(Stream* stream)
	{
		m_context.stream = stream;
	}

	/*!
	* \brief Constructs a ByteStream object by move semantic
	*
	* \param stream ByteStream to move into this
	*/

	inline ByteStream::ByteStream(ByteStream&& stream) :
	m_ownedStream(std::move(stream.m_ownedStream)),
	m_context(stream.m_context)
	{
		stream.m_context.stream = nullptr;
	}

	/*!
	* \brief Destructs the object and calls FlushBits
	*
	* \remark Produces a NazaraWarning if flush did not work
	*
	* \see FlushBits
	*/

	inline ByteStream::~ByteStream()
	{
		if (!FlushBits())
			NazaraWarning("Failed to flush bits at serializer destruction");
	}

	/*!
	* \brief Gets the stream endianness
	* \return Type of the endianness
	*/

	inline Endianness ByteStream::GetDataEndianness() const
	{
		return m_context.endianness;
	}

	/*!
	* \brief Gets the size of the byte stream
	* \return Size of the stream
	*/

	inline Nz::UInt64 ByteStream::GetSize() const
	{
		if (m_context.stream)
			return m_context.stream->GetSize();
		else
			return 0;
	}

	/*!
	* \brief Gets the internal stream
	* \return Internal stream
	*/

	inline Stream* ByteStream::GetStream() const
	{
		return m_context.stream;
	}

	/*!
	* \brief Flushes the stream
	* \return true if flushing is successful
	*/

	inline bool ByteStream::FlushBits()
	{
		if (!m_context.stream)
			return true;

		if (m_context.writeBitPos != 8)
		{
			m_context.writeBitPos = 8; //< To prevent Serialize to flush bits itself

			if (!Serialize(m_context, m_context.writeByte))
				return false;
		}

		return true;
	}

	/*!
	* \brief Reads data
	* \return Number of data read
	*
	* \param ptr Preallocated buffer to contain information read
	* \param size Size of the read and thus of the buffer
	*/

	inline std::size_t ByteStream::Read(void* ptr, std::size_t size)
	{
		if (!m_context.stream)
			OnEmptyStream();

		FlushBits();
		return m_context.stream->Read(ptr, size);
	}

	/*!
	* \brief Sets the stream endianness
	*
	* \param endiannes Type of the endianness
	*/

	inline void ByteStream::SetDataEndianness(Endianness endiannes)
	{
		m_context.endianness = endiannes;
	}

	/*!
	* \brief Sets this with a stream
	*
	* \param stream Stream existing
	*
	* \remark Produces a NazaraAssert if stream is invalid
	*/

	inline void ByteStream::SetStream(Stream* stream)
	{
		NazaraAssert(stream, "Invalid stream");

		// We don't want to lose some bits..
		FlushBits();

		m_context.stream = stream;
		m_ownedStream.reset();
	}

	/*!
	* \brief Writes data
	* \return Number of data written
	*
	* \param buffer Preallocated buffer containing information to write
	* \param size Size of the writting and thus of the buffer
	*
	* \remark Produces a NazaraAssert if buffer is nullptr
	*/

	inline std::size_t ByteStream::Write(const void* data, std::size_t size)
	{
		if (!m_context.stream)
			OnEmptyStream();

		FlushBits();
		return m_context.stream->Write(data, size);
	}

	/*!
	* \brief Outputs a data from the stream
	* \return A reference to this
	*
	* \param value Value to unserialize
	*
	* \remark Produces a NazaraError if unserialization failed
	*/

	template<typename T>
	ByteStream& ByteStream::operator>>(T& value)
	{
		if (!m_context.stream)
			OnEmptyStream();

		if (!Unserialize(m_context, &value))
			NazaraError("Failed to serialize value");

		return *this;
	}

	/*!
	* \brief Adds the data to the stream
	* \return A reference to this
	*
	* \param value Value to serialize
	*
	* \remark Produces a NazaraError if serialization failed
	*/

	template<typename T>
	ByteStream& ByteStream::operator<<(const T& value)
	{
		if (!m_context.stream)
			OnEmptyStream();

		if (!Serialize(m_context, value))
			NazaraError("Failed to serialize value");

		return *this;
	}

	/*!
	* \brief Moves the other byte stream into this
	* \return A reference to this
	*
	* \param stream ByteStream to move in this
	*/

	inline ByteStream& ByteStream::operator=(ByteStream&& stream)
	{
		m_context = stream.m_context;
		m_ownedStream = std::move(stream.m_ownedStream);

		stream.m_context.stream = nullptr;

		return *this;
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Vaclav Slavik <vslavik@gmail.com>
 * All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the schemaation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

// xmlwrapp includes
#include "xmlwrapp/errors.h"

#include "utility.h"
#include "errors_impl.h"

namespace xml
{

error_handler_throw_on_error             throw_on_error;
error_handler_throw_on_error_or_warning  throw_on_error_or_warning;

// ------------------------------------------------------------------------
// xml::exception
// ------------------------------------------------------------------------

exception::exception(const std::string& what) : std::runtime_error(what)
{
}

exception::exception(const error_messages& what) : std::runtime_error(what.print())
{
}

// ------------------------------------------------------------------------
// xml::error_messages
// ------------------------------------------------------------------------

void error_messages::on_error(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_error));
    has_errors_ = true;
}

void error_messages::on_warning(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_warning));
    has_warnings_ = true;
}

std::string error_messages::print() const
{
    std::string buffer;

    messages_type::const_iterator begin(messages_.begin());
    messages_type::const_iterator end(messages_.end());
    for (messages_type::const_iterator k = begin; k != end; ++k)
    {
        if (k != begin)
            buffer += "\n";
        buffer += format_for_print(*k);
    }

    return buffer;
}

std::string error_messages::format_for_print(const error_message& msg) const
{
    switch (msg.type())
    {
        case error_message::type_error:
            return "error: " + msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }
}

// ------------------------------------------------------------------------
// libxml2 callbacks interface
// ------------------------------------------------------------------------

namespace impl
{

// Notice that these callbacks are called from C code, not C++. Although
// throwing exceptions through C code does work in some implementations, it
// is not guaranteed to. We therefore need to make sure no exception
// propagates outside of the callbacks by catching them.
//
// This is also the reason for errors_collector's existence: we cannot safely
// call error_handler's methods, because they may throw (it is in fact often
// desirable). So we collect the errors and "replay" them after returning from
// C code.

extern "C" void cb_messages_warning_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_warning(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_error_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_error(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_warning(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_WARNING(out, message);
}

extern "C" void cb_messages_error(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_ERROR(out, message);
}

void errors_collector::replay(error_handler& dest)
{
    const messages_type& msg = messages();

    for ( messages_type::const_iterator i = msg.begin();
          i != msg.end();
          ++i )
    {
        switch ( i->type() )
        {
            case error_message::type_error:
                dest.on_error(i->message());
                break;
            case error_message::type_warning:
                dest.on_warning(i->message());
                break;
        }
    }
}

std::string errors_collector::format_for_print(const error_message& msg) const
{
    // The errors_collector class is also used to provide backward
    // compatibility errors reporting in tree_parser and xslt::stylesheet. The
    // "error: " prefix wasn't included there, so don't add it now either so
    // that we don't break user UI output. On the other hand, include "warning:
    // " to make it clear these aren't errors.

    switch (msg.type())
    {
        case error_message::type_error:
            return msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }
}

} // namespace impl

} // namespace xml
<commit_msg>Silence bogus gcc warnings.<commit_after>/*
 * Copyright (C) 2013 Vaclav Slavik <vslavik@gmail.com>
 * All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the schemaation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

// xmlwrapp includes
#include "xmlwrapp/errors.h"

#include "utility.h"
#include "errors_impl.h"

namespace xml
{

error_handler_throw_on_error             throw_on_error;
error_handler_throw_on_error_or_warning  throw_on_error_or_warning;

// ------------------------------------------------------------------------
// xml::exception
// ------------------------------------------------------------------------

exception::exception(const std::string& what) : std::runtime_error(what)
{
}

exception::exception(const error_messages& what) : std::runtime_error(what.print())
{
}

// ------------------------------------------------------------------------
// xml::error_messages
// ------------------------------------------------------------------------

void error_messages::on_error(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_error));
    has_errors_ = true;
}

void error_messages::on_warning(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_warning));
    has_warnings_ = true;
}

std::string error_messages::print() const
{
    std::string buffer;

    messages_type::const_iterator begin(messages_.begin());
    messages_type::const_iterator end(messages_.end());
    for (messages_type::const_iterator k = begin; k != end; ++k)
    {
        if (k != begin)
            buffer += "\n";
        buffer += format_for_print(*k);
    }

    return buffer;
}

std::string error_messages::format_for_print(const error_message& msg) const
{
    switch (msg.type())
    {
        case error_message::type_error:
            return "error: " + msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

// ------------------------------------------------------------------------
// libxml2 callbacks interface
// ------------------------------------------------------------------------

namespace impl
{

// Notice that these callbacks are called from C code, not C++. Although
// throwing exceptions through C code does work in some implementations, it
// is not guaranteed to. We therefore need to make sure no exception
// propagates outside of the callbacks by catching them.
//
// This is also the reason for errors_collector's existence: we cannot safely
// call error_handler's methods, because they may throw (it is in fact often
// desirable). So we collect the errors and "replay" them after returning from
// C code.

extern "C" void cb_messages_warning_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_warning(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_error_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_error(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_warning(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_WARNING(out, message);
}

extern "C" void cb_messages_error(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_ERROR(out, message);
}

void errors_collector::replay(error_handler& dest)
{
    const messages_type& msg = messages();

    for ( messages_type::const_iterator i = msg.begin();
          i != msg.end();
          ++i )
    {
        switch ( i->type() )
        {
            case error_message::type_error:
                dest.on_error(i->message());
                break;
            case error_message::type_warning:
                dest.on_warning(i->message());
                break;
        }
    }
}

std::string errors_collector::format_for_print(const error_message& msg) const
{
    // The errors_collector class is also used to provide backward
    // compatibility errors reporting in tree_parser and xslt::stylesheet. The
    // "error: " prefix wasn't included there, so don't add it now either so
    // that we don't break user UI output. On the other hand, include "warning:
    // " to make it clear these aren't errors.

    switch (msg.type())
    {
        case error_message::type_error:
            return msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

} // namespace impl

} // namespace xml
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "common.h"
#include "eventpipebuffermanager.h"
#include "eventpipeeventinstance.h"
#include "sampleprofiler.h"
#include "hosting.h"
#include "threadsuspend.h"

#ifdef FEATURE_PERFTRACING

Volatile<BOOL> SampleProfiler::s_profilingEnabled = false;
Thread* SampleProfiler::s_pSamplingThread = NULL;
const WCHAR* SampleProfiler::s_providerName = W("Microsoft-DotNETCore-SampleProfiler");
EventPipeProvider* SampleProfiler::s_pEventPipeProvider = NULL;
EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL;
BYTE* SampleProfiler::s_pPayloadExternal = NULL;
BYTE* SampleProfiler::s_pPayloadManaged = NULL;
CLREventStatic SampleProfiler::s_threadShutdownEvent;
long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms

void SampleProfiler::Enable()
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        PRECONDITION(s_pSamplingThread == NULL);
        // Synchronization of multiple callers occurs in EventPipe::Enable.
        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
    }
    CONTRACTL_END;

    if(s_pEventPipeProvider == NULL)
    {
        s_pEventPipeProvider = EventPipe::CreateProvider(SL(s_providerName));
        s_pThreadTimeEvent = s_pEventPipeProvider->AddEvent(
            0, /* eventID */
            0, /* keywords */
            0, /* eventVersion */
            EventPipeEventLevel::Informational,
            false /* NeedStack */);
    }

    if(s_pPayloadExternal == NULL)
    {
        s_pPayloadExternal = new BYTE[sizeof(unsigned int)];
        *((unsigned int *)s_pPayloadExternal) = static_cast<unsigned int>(SampleProfilerSampleType::External);

        s_pPayloadManaged = new BYTE[sizeof(unsigned int)];
        *((unsigned int *)s_pPayloadManaged) = static_cast<unsigned int>(SampleProfilerSampleType::Managed);
    }

    s_profilingEnabled = true;
    s_pSamplingThread = SetupUnstartedThread();
    if(s_pSamplingThread->CreateNewThread(0, ThreadProc, NULL))
    {
        // Start the sampling thread.
        s_pSamplingThread->SetBackground(TRUE);
        s_pSamplingThread->StartThread();
    }
    else
    {
        _ASSERT(!"Unable to create sample profiler thread.");
    }
}

void SampleProfiler::Disable()
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        // Synchronization of multiple callers occurs in EventPipe::Disable.
        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
    }
    CONTRACTL_END;

    // Bail early if profiling is not enabled.
    if(!s_profilingEnabled)
    {
        return;
    }

    // Reset the event before shutdown.
    s_threadShutdownEvent.Reset();

    // The sampling thread will watch this value and exit
    // when profiling is disabled.
    s_profilingEnabled = false;

    // Wait for the sampling thread to clean itself up.
    s_threadShutdownEvent.Wait(0, FALSE /* bAlertable */);
}

void SampleProfiler::SetSamplingRate(long nanoseconds)
{
    LIMITED_METHOD_CONTRACT;
    s_samplingRateInNs = nanoseconds;
}

DWORD WINAPI SampleProfiler::ThreadProc(void *args)
{
    CONTRACTL
    {
        NOTHROW;
        GC_TRIGGERS;
        MODE_PREEMPTIVE;
        PRECONDITION(s_pSamplingThread != NULL);
    }
    CONTRACTL_END;

    // Complete thread initialization and start the profiling loop.
    if(s_pSamplingThread->HasStarted())
    {
        // Switch to pre-emptive mode so that this thread doesn't starve the GC.
        GCX_PREEMP();

        while(s_profilingEnabled)
        {
            // Check to see if we can suspend managed execution.
            if(ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
            {
                // Skip the current sample.
                PAL_nanosleep(s_samplingRateInNs);
                continue;
            }

            // Actually suspend managed execution.
            ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_OTHER);

            // Walk all managed threads and capture stacks.
            WalkManagedThreads();

            // Resume managed execution.
            ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);

            // Wait until it's time to sample again.
            PAL_nanosleep(s_samplingRateInNs);
        }
    }

    // Destroy the sampling thread when it is done running.
    DestroyThread(s_pSamplingThread);
    s_pSamplingThread = NULL;

    // Signal Disable() that the thread has been destroyed.
    s_threadShutdownEvent.Set();

    return S_OK;
}

// The thread store lock must already be held by the thread before this function
// is called.  ThreadSuspend::SuspendEE acquires the thread store lock.
void SampleProfiler::WalkManagedThreads()
{
    CONTRACTL
    {
        NOTHROW;
        GC_TRIGGERS;
        MODE_PREEMPTIVE;
    }
    CONTRACTL_END;

    Thread *pTargetThread = NULL;

    // Iterate over all managed threads.
    // Assumes that the ThreadStoreLock is held because we've suspended all threads.
    while ((pTargetThread = ThreadStore::GetThreadList(pTargetThread)) != NULL)
    {
        StackContents stackContents;

        // Walk the stack and write it out as an event.
        if(EventPipe::WalkManagedStackForThread(pTargetThread, stackContents) && !stackContents.IsEmpty())
        {
            // Set the payload.  If the GC mode on suspension > 0, then the thread was in cooperative mode.
            // Even though there are some cases where this is not managed code, we assume it is managed code here.
            // If the GC mode on suspension == 0 then the thread was in preemptive mode, which we qualify as external here.
            BYTE *pPayload = s_pPayloadExternal;
            if(pTargetThread->GetGCModeOnSuspension())
            {
                pPayload = s_pPayloadManaged;
            }

            // Write the sample.
            EventPipe::WriteSampleProfileEvent(s_pSamplingThread, s_pThreadTimeEvent, pTargetThread, stackContents, pPayload, c_payloadSize);
        }

        // Reset the GC mode.
        pTargetThread->ClearGCModeOnSuspension();
    }
}

#endif // FEATURE_PERFTRACING
<commit_msg>Don't create the sampling thread if the threadtime event is disabled. (#15473)<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "common.h"
#include "eventpipebuffermanager.h"
#include "eventpipeeventinstance.h"
#include "sampleprofiler.h"
#include "hosting.h"
#include "threadsuspend.h"

#ifdef FEATURE_PERFTRACING

Volatile<BOOL> SampleProfiler::s_profilingEnabled = false;
Thread* SampleProfiler::s_pSamplingThread = NULL;
const WCHAR* SampleProfiler::s_providerName = W("Microsoft-DotNETCore-SampleProfiler");
EventPipeProvider* SampleProfiler::s_pEventPipeProvider = NULL;
EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL;
BYTE* SampleProfiler::s_pPayloadExternal = NULL;
BYTE* SampleProfiler::s_pPayloadManaged = NULL;
CLREventStatic SampleProfiler::s_threadShutdownEvent;
long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms

void SampleProfiler::Enable()
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        PRECONDITION(s_pSamplingThread == NULL);
        // Synchronization of multiple callers occurs in EventPipe::Enable.
        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
    }
    CONTRACTL_END;

    if(s_pEventPipeProvider == NULL)
    {
        s_pEventPipeProvider = EventPipe::CreateProvider(SL(s_providerName));
        s_pThreadTimeEvent = s_pEventPipeProvider->AddEvent(
            0, /* eventID */
            0, /* keywords */
            0, /* eventVersion */
            EventPipeEventLevel::Informational,
            false /* NeedStack */);
    }

    // Check to see if the sample profiler event is enabled.  If it is not, do not spin up the sampling thread.
    if(!s_pThreadTimeEvent->IsEnabled())
    {
        return;
    }

    if(s_pPayloadExternal == NULL)
    {
        s_pPayloadExternal = new BYTE[sizeof(unsigned int)];
        *((unsigned int *)s_pPayloadExternal) = static_cast<unsigned int>(SampleProfilerSampleType::External);

        s_pPayloadManaged = new BYTE[sizeof(unsigned int)];
        *((unsigned int *)s_pPayloadManaged) = static_cast<unsigned int>(SampleProfilerSampleType::Managed);
    }

    s_profilingEnabled = true;
    s_pSamplingThread = SetupUnstartedThread();
    if(s_pSamplingThread->CreateNewThread(0, ThreadProc, NULL))
    {
        // Start the sampling thread.
        s_pSamplingThread->SetBackground(TRUE);
        s_pSamplingThread->StartThread();
    }
    else
    {
        _ASSERT(!"Unable to create sample profiler thread.");
    }
}

void SampleProfiler::Disable()
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        MODE_ANY;
        // Synchronization of multiple callers occurs in EventPipe::Disable.
        PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
    }
    CONTRACTL_END;

    // Bail early if profiling is not enabled.
    if(!s_profilingEnabled)
    {
        return;
    }

    // Reset the event before shutdown.
    s_threadShutdownEvent.Reset();

    // The sampling thread will watch this value and exit
    // when profiling is disabled.
    s_profilingEnabled = false;

    // Wait for the sampling thread to clean itself up.
    s_threadShutdownEvent.Wait(0, FALSE /* bAlertable */);
}

void SampleProfiler::SetSamplingRate(long nanoseconds)
{
    LIMITED_METHOD_CONTRACT;
    s_samplingRateInNs = nanoseconds;
}

DWORD WINAPI SampleProfiler::ThreadProc(void *args)
{
    CONTRACTL
    {
        NOTHROW;
        GC_TRIGGERS;
        MODE_PREEMPTIVE;
        PRECONDITION(s_pSamplingThread != NULL);
    }
    CONTRACTL_END;

    // Complete thread initialization and start the profiling loop.
    if(s_pSamplingThread->HasStarted())
    {
        // Switch to pre-emptive mode so that this thread doesn't starve the GC.
        GCX_PREEMP();

        while(s_profilingEnabled)
        {
            // Check to see if we can suspend managed execution.
            if(ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
            {
                // Skip the current sample.
                PAL_nanosleep(s_samplingRateInNs);
                continue;
            }

            // Actually suspend managed execution.
            ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_OTHER);

            // Walk all managed threads and capture stacks.
            WalkManagedThreads();

            // Resume managed execution.
            ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);

            // Wait until it's time to sample again.
            PAL_nanosleep(s_samplingRateInNs);
        }
    }

    // Destroy the sampling thread when it is done running.
    DestroyThread(s_pSamplingThread);
    s_pSamplingThread = NULL;

    // Signal Disable() that the thread has been destroyed.
    s_threadShutdownEvent.Set();

    return S_OK;
}

// The thread store lock must already be held by the thread before this function
// is called.  ThreadSuspend::SuspendEE acquires the thread store lock.
void SampleProfiler::WalkManagedThreads()
{
    CONTRACTL
    {
        NOTHROW;
        GC_TRIGGERS;
        MODE_PREEMPTIVE;
    }
    CONTRACTL_END;

    Thread *pTargetThread = NULL;

    // Iterate over all managed threads.
    // Assumes that the ThreadStoreLock is held because we've suspended all threads.
    while ((pTargetThread = ThreadStore::GetThreadList(pTargetThread)) != NULL)
    {
        StackContents stackContents;

        // Walk the stack and write it out as an event.
        if(EventPipe::WalkManagedStackForThread(pTargetThread, stackContents) && !stackContents.IsEmpty())
        {
            // Set the payload.  If the GC mode on suspension > 0, then the thread was in cooperative mode.
            // Even though there are some cases where this is not managed code, we assume it is managed code here.
            // If the GC mode on suspension == 0 then the thread was in preemptive mode, which we qualify as external here.
            BYTE *pPayload = s_pPayloadExternal;
            if(pTargetThread->GetGCModeOnSuspension())
            {
                pPayload = s_pPayloadManaged;
            }

            // Write the sample.
            EventPipe::WriteSampleProfileEvent(s_pSamplingThread, s_pThreadTimeEvent, pTargetThread, stackContents, pPayload, c_payloadSize);
        }

        // Reset the GC mode.
        pTargetThread->ClearGCModeOnSuspension();
    }
}

#endif // FEATURE_PERFTRACING
<|endoftext|>


<commit_before>#ifndef INC_AL_CONTROL_NAV_HPP
#define INC_AL_CONTROL_NAV_HPP

#include "allocore/io/al_Window.hpp"
#include "allocore/spatial/al_CoordinateFrame.hpp"

namespace al {

/// Mapping from keyboard and mouse controls to a Nav object
struct NavInputControl : public InputEventHandler {

	NavInputControl(Nav * nav, double vscale = 0.125, double tscale = 2.)
	: mNav(nav), mVScale(vscale), mTScale(tscale) {}
	virtual ~NavInputControl() {}

	void nav(Nav * v){ mNav=v; }

	virtual bool onKeyDown(const Keyboard& k){

		double vs = nav().velScale();
		double a = mTScale * vs;	// rotational speed: degrees per update
		double v = mVScale * vs;	// speed: units per update

		switch(k.key()){
			case '`':			nav().halt().home(); return false;
			case 's':			nav().halt(); return false;
			case Key::Up:		nav().spinR(-a); return false;
			case Key::Down:		nav().spinR( a); return false;
			case Key::Right:	nav().spinU( a); return false;
			case Key::Left:		nav().spinU(-a); return false;
			case 'q':			nav().spinF( a); return false;
			case 'z':			nav().spinF(-a); return false;
			case 'a':			nav().moveR(-v); return false;
			case 'd':			nav().moveR( v); return false;
			case 'e':			nav().moveU( v); return false;
			case 'c':			nav().moveU(-v); return false;
			case 'x':			nav().moveF(-v); return false;
			case 'w':			nav().moveF( v); return false;
			default:;
		}
		return true;
	}
	virtual bool onKeyUp(const Keyboard& k) {
		switch (k.key()) {
			case Key::Up:
			case Key::Down:		nav().spinR(0); return false;
			case Key::Right:
			case Key::Left:		nav().spinU(0); return false;
			case 'q':
			case 'z':			nav().spinF(0); return false;
			case 'a':
			case 'd':			nav().moveR(0); return false;
			case 'e':
			case 'c':			nav().moveU(0); return false;
			case 'x':
			case 'w':			nav().moveF(0); return false;
			default:;
		}
		return true;
	}

	virtual bool onMouseDrag(const Mouse& m){
		if(m.left()){
			nav().turnU(m.dx() * 0.2);
			nav().turnR(m.dy() * 0.2);
		}
		else if(m.right()){
			nav().turnF(m.dx() * 0.2);
			//incBehind(m.dy()*0.005);
		}
		return false;
	}

	Nav& nav(){ return *mNav; }

	double vscale() { return mVScale; }
	NavInputControl& vscale(double v) { mVScale=v; return *this; }

	double tscale() { return mTScale; }
	NavInputControl& tscale(double v) { mTScale=v; return *this; }

protected:
	Nav * mNav;
	double mVScale, mTScale;
};

struct NavInputControlCosm : public NavInputControl {

	NavInputControlCosm(Nav * nav, double vscale = 0.125, double tscale = 2.): NavInputControl(nav, vscale, tscale){}
	virtual ~NavInputControlCosm() {}

	virtual bool onKeyDown(const Keyboard& k){

		double vs = nav().velScale();
		double a = mTScale * vs;	// rotational speed: degrees per update
		double v = mVScale * vs;	// speed: units per update

		switch(k.key()){
			case '`':			nav().halt().home(); return false;
			case 'w':			nav().spinR(-a); return false;
			case 'x':			nav().spinR( a); return false;
			case Key::Right:	nav().spinU( a); return false;
			case Key::Left:		nav().spinU(-a); return false;
			case 'a':			nav().spinF( a); return false;
			case 'd':			nav().spinF(-a); return false;
			case ',':			nav().moveR(-v); return false;
			case '.':			nav().moveR( v); return false;
			case '\'':			nav().moveU( v); return false;
			case '/':			nav().moveU(-v); return false;
			case Key::Up:		nav().moveF( v); return false;
			case Key::Down:		nav().moveF(-v); return false;
			default:;
		}
		return true;
	}

	virtual bool onKeyUp(const Keyboard& k) {
		switch (k.key()) {
			case 'w':
			case 'x':			nav().spinR(0); return false;
			case Key::Right:
			case Key::Left:		nav().spinU(0); return false;
			case 'a':
			case 'd':			nav().spinF(0); return false;
			case ',':
			case '.':			nav().moveR(0); return false;
			case '\'':
			case '/':			nav().moveU(0); return false;
			case Key::Up:
			case Key::Down:		nav().moveF(0); return false;
			default:;
		}
		return true;
	}

	virtual bool onMouseDrag(const Mouse& m){ return true; }
};

} // al::

#endif
<commit_msg>ControlNav: speed booster<commit_after>#ifndef INC_AL_CONTROL_NAV_HPP
#define INC_AL_CONTROL_NAV_HPP

#include "allocore/io/al_Window.hpp"
#include "allocore/spatial/al_CoordinateFrame.hpp"

namespace al {

/// Mapping from keyboard and mouse controls to a Nav object
struct NavInputControl : public InputEventHandler {

	NavInputControl(Nav * nav, double vscale = 0.125, double tscale = 2.)
	: mNav(nav), mVScale(vscale), mTScale(tscale) {}
	virtual ~NavInputControl() {}

	void nav(Nav * v){ mNav=v; }

	virtual bool onKeyDown(const Keyboard& k){

		double vs = nav().velScale();
		double a = mTScale * vs;	// rotational speed: degrees per update
		double v = mVScale * vs;	// speed: units per update

		if(k.alt()) v *= 10;

		switch(k.key()){
			case '`':			nav().halt().home(); return false;
			case 's':			nav().halt(); return false;
			case Key::Up:		nav().spinR(-a); return false;
			case Key::Down:		nav().spinR( a); return false;
			case Key::Right:	nav().spinU( a); return false;
			case Key::Left:		nav().spinU(-a); return false;
			case 'q':			nav().spinF( a); return false;
			case 'z':			nav().spinF(-a); return false;
			case 'a':			nav().moveR(-v); return false;
			case 'd':			nav().moveR( v); return false;
			case 'e':			nav().moveU( v); return false;
			case 'c':			nav().moveU(-v); return false;
			case 'x':			nav().moveF(-v); return false;
			case 'w':			nav().moveF( v); return false;
			default:;
		}
		return true;
	}
	virtual bool onKeyUp(const Keyboard& k) {
		switch (k.key()) {
			case Key::Up:
			case Key::Down:		nav().spinR(0); return false;
			case Key::Right:
			case Key::Left:		nav().spinU(0); return false;
			case 'q':
			case 'z':			nav().spinF(0); return false;
			case 'a':
			case 'd':			nav().moveR(0); return false;
			case 'e':
			case 'c':			nav().moveU(0); return false;
			case 'x':
			case 'w':			nav().moveF(0); return false;
			default:;
		}
		return true;
	}

	virtual bool onMouseDrag(const Mouse& m){
		if(m.left()){
			nav().turnU(m.dx() * 0.2);
			nav().turnR(m.dy() * 0.2);
		}
		else if(m.right()){
			nav().turnF(m.dx() * 0.2);
			//incBehind(m.dy()*0.005);
		}
		return false;
	}

	Nav& nav(){ return *mNav; }

	double vscale() { return mVScale; }
	NavInputControl& vscale(double v) { mVScale=v; return *this; }

	double tscale() { return mTScale; }
	NavInputControl& tscale(double v) { mTScale=v; return *this; }

protected:
	Nav * mNav;
	double mVScale, mTScale;
};

struct NavInputControlCosm : public NavInputControl {

	NavInputControlCosm(Nav * nav, double vscale = 0.125, double tscale = 2.): NavInputControl(nav, vscale, tscale){}
	virtual ~NavInputControlCosm() {}

	virtual bool onKeyDown(const Keyboard& k){

		double vs = nav().velScale();
		double a = mTScale * vs;	// rotational speed: degrees per update
		double v = mVScale * vs;	// speed: units per update

		switch(k.key()){
			case '`':			nav().halt().home(); return false;
			case 'w':			nav().spinR(-a); return false;
			case 'x':			nav().spinR( a); return false;
			case Key::Right:	nav().spinU( a); return false;
			case Key::Left:		nav().spinU(-a); return false;
			case 'a':			nav().spinF( a); return false;
			case 'd':			nav().spinF(-a); return false;
			case ',':			nav().moveR(-v); return false;
			case '.':			nav().moveR( v); return false;
			case '\'':			nav().moveU( v); return false;
			case '/':			nav().moveU(-v); return false;
			case Key::Up:		nav().moveF( v); return false;
			case Key::Down:		nav().moveF(-v); return false;
			default:;
		}
		return true;
	}

	virtual bool onKeyUp(const Keyboard& k) {
		switch (k.key()) {
			case 'w':
			case 'x':			nav().spinR(0); return false;
			case Key::Right:
			case Key::Left:		nav().spinU(0); return false;
			case 'a':
			case 'd':			nav().spinF(0); return false;
			case ',':
			case '.':			nav().moveR(0); return false;
			case '\'':
			case '/':			nav().moveU(0); return false;
			case Key::Up:
			case Key::Down:		nav().moveF(0); return false;
			default:;
		}
		return true;
	}

	virtual bool onMouseDrag(const Mouse& m){ return true; }
};

} // al::

#endif
<|endoftext|>


<commit_before>/* This file is part of Zanshin Todo.

   Copyright 2008-2010 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "actionlisteditorpage.h"

#include <KDE/Akonadi/ItemCreateJob>
#include <KDE/Akonadi/ItemDeleteJob>

#include <KDE/KConfigGroup>
#include <kdescendantsproxymodel.h>
#include <kmodelindexproxymapper.h>

#include <QtCore/QTimer>
#include <QtGui/QHeaderView>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QVBoxLayout>

#include "actionlistdelegate.h"
#include "todomodel.h"
#include "todotreeview.h"

class GroupLabellingProxyModel : public QSortFilterProxyModel
{
public:
    GroupLabellingProxyModel(QObject *parent = 0)
        : QSortFilterProxyModel(parent)
    {
        setDynamicSortFilter(true);
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
    {
        if (role!=Qt::DisplayRole || index.column()!=0) {
            return QSortFilterProxyModel::data(index, role);
        } else {
            int type = index.data(TodoModel::ItemTypeRole).toInt();

            if (type!=TodoModel::ProjectTodo
             && type!=TodoModel::Category) {
                return QSortFilterProxyModel::data(index, role);

            } else {
                QString display = QSortFilterProxyModel::data(index, role).toString();

                QModelIndex currentIndex = index.parent();
                type = currentIndex.data(TodoModel::ItemTypeRole).toInt();

                while (type==TodoModel::ProjectTodo
                    || type==TodoModel::Category) {
                    display = currentIndex.data(role).toString() + ": " + display;

                    currentIndex = currentIndex.parent();
                    type = currentIndex.data(TodoModel::ItemTypeRole).toInt();
                }

                return display;
            }
        }
    }
};

class GroupSortingProxyModel : public QSortFilterProxyModel
{
public:
    GroupSortingProxyModel(QObject *parent = 0)
        : QSortFilterProxyModel(parent)
    {
        setDynamicSortFilter(true);
        setFilterCaseSensitivity(Qt::CaseInsensitive);
    }

    bool lessThan(const QModelIndex &left, const QModelIndex &right) const
    {
        int leftType = left.data(TodoModel::ItemTypeRole).toInt();
        int rightType = right.data(TodoModel::ItemTypeRole).toInt();

        return leftType==TodoModel::Inbox
            || (leftType==TodoModel::CategoryRoot && rightType!=TodoModel::Inbox)
            || (leftType==TodoModel::Collection && rightType!=TodoModel::Inbox)
            || (leftType==TodoModel::Category && rightType==TodoModel::StandardTodo)
            || (leftType==TodoModel::ProjectTodo && rightType==TodoModel::StandardTodo)
            || QSortFilterProxyModel::lessThan(left, right);
    }
};

class TypeFilterProxyModel : public QSortFilterProxyModel
{
public:
    TypeFilterProxyModel(GroupSortingProxyModel *sorting, QObject *parent = 0)
        : QSortFilterProxyModel(parent), m_sorting(sorting)
    {
        setDynamicSortFilter(true);
        setFilterCaseSensitivity(Qt::CaseInsensitive);
    }

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    {
        QModelIndex sourceChild = sourceModel()->index(sourceRow, 0, sourceParent);
        int type = sourceChild.data(TodoModel::ItemTypeRole).toInt();

        QSize sizeHint = sourceChild.data(Qt::SizeHintRole).toSize();

        return type!=TodoModel::Collection
            && type!=TodoModel::CategoryRoot
            && !sizeHint.isNull(); // SelectionProxyModel uses the null size for items we shouldn't display
    }

    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
    {
        m_sorting->sort(column, order);
    }

private:
    GroupSortingProxyModel *m_sorting;
};

class ActionListEditorView : public TodoTreeView
{
public:
    ActionListEditorView(QWidget *parent = 0)
        : TodoTreeView(parent) { }

protected:
    virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    {
        QModelIndex index = currentIndex();

        if (index.isValid() && modifiers==Qt::NoModifier) {
            QModelIndex newIndex;
            int newColumn = index.column();

            switch (cursorAction) {
            case MoveLeft:
                do {
                    newColumn--;
                } while (isColumnHidden(newColumn)
                      && newColumn>=0);
                break;

            case MoveRight:
                do {
                    newColumn++;
                } while (isColumnHidden(newColumn)
                      && newColumn<header()->count());
                break;

            default:
                return Akonadi::EntityTreeView::moveCursor(cursorAction, modifiers);
            }

            newIndex = index.sibling(index.row(), newColumn);

            if (newIndex.isValid()) {
                return newIndex;
            }
        }

        return Akonadi::EntityTreeView::moveCursor(cursorAction, modifiers);
    }
};

class ActionListEditorModel : public KDescendantsProxyModel
{
public:
    ActionListEditorModel(QObject *parent = 0)
        : KDescendantsProxyModel(parent)
    {
    }

    virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
        if (!sourceModel()) {
            return QAbstractProxyModel::dropMimeData(data, action, row, column, parent);
        }
        QModelIndex sourceParent = mapToSource(parent);
        return sourceModel()->dropMimeData(data, action, row, column, sourceParent);
    }
};

ActionListEditorPage::ActionListEditorPage(QAbstractItemModel *model,
                                           ModelStack *models,
                                           Zanshin::ApplicationMode mode,
                                           QWidget *parent)
    : QWidget(parent), m_mode(mode)
{
    setLayout(new QVBoxLayout(this));
    layout()->setContentsMargins(0, 0, 0, 0);

    m_treeView = new ActionListEditorView(this);

    GroupLabellingProxyModel *labelling = new GroupLabellingProxyModel(this);
    labelling->setSourceModel(model);

    GroupSortingProxyModel *sorting = new GroupSortingProxyModel(this);
    sorting->setSourceModel(labelling);

    ActionListEditorModel *descendants = new ActionListEditorModel(this);
    descendants->setSourceModel(sorting);

    TypeFilterProxyModel *filter = new TypeFilterProxyModel(sorting, this);
    filter->setSourceModel(descendants);

    m_treeView->setModel(filter);
    m_treeView->setItemDelegate(new ActionListDelegate(models, m_treeView));

    m_treeView->header()->setSortIndicatorShown(true);
    m_treeView->setSortingEnabled(true);
    m_treeView->sortByColumn(0, Qt::AscendingOrder);

    m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    m_treeView->setItemsExpandable(false);
    m_treeView->setRootIsDecorated(false);
    m_treeView->setEditTriggers(m_treeView->editTriggers() | QAbstractItemView::DoubleClicked);

    connect(m_treeView->model(), SIGNAL(modelReset()),
            m_treeView, SLOT(expandAll()));
    connect(m_treeView->model(), SIGNAL(layoutChanged()),
            m_treeView, SLOT(expandAll()));
    connect(m_treeView->model(), SIGNAL(rowsInserted(QModelIndex, int, int)),
            m_treeView, SLOT(expandAll()));

    layout()->addWidget(m_treeView);

    QTimer::singleShot(0, this, SLOT(onAutoHideColumns()));

    connect(m_treeView->header(), SIGNAL(sectionResized(int, int, int)),
            this, SLOT(onColumnsGeometryChanged()));
}

QItemSelectionModel *ActionListEditorPage::selectionModel() const
{
    return m_treeView->selectionModel();
}

void ActionListEditorPage::saveColumnsState(KConfigGroup &config, const QString &key) const
{
    config.writeEntry(key+"/Normal", m_normalStateCache.toBase64());
    config.writeEntry(key+"/NoCollection", m_noCollectionStateCache.toBase64());
}

void ActionListEditorPage::restoreColumnsState(const KConfigGroup &config, const QString &key)
{
    if (config.hasKey(key+"/Normal")) {
        m_normalStateCache = QByteArray::fromBase64(config.readEntry(key+"/Normal", QByteArray()));
    }

    if (config.hasKey(key+"/NoCollection")) {
        m_noCollectionStateCache = QByteArray::fromBase64(config.readEntry(key+"/NoCollection", QByteArray()));
    }

    if (!m_treeView->isColumnHidden(4)) {
        m_treeView->header()->restoreState(m_normalStateCache);
    } else {
        m_treeView->header()->restoreState(m_noCollectionStateCache);
    }
}

void ActionListEditorPage::addNewTodo(const QString &summary)
{
    if (summary.isEmpty()) return;

    QModelIndex current = m_treeView->selectionModel()->currentIndex();

    if (!current.isValid()) {
        kWarning() << "Oops, nothing selected in the list!";
        return;
    }

    int type = current.data(TodoModel::ItemTypeRole).toInt();

    while (current.isValid() && type==TodoModel::StandardTodo) {
        current = current.parent();
        type = current.data(TodoModel::ItemTypeRole).toInt();
    }

    Akonadi::Collection collection;
    QString parentUid;
    QString category;

    switch (type) {
    case TodoModel::StandardTodo:
        kFatal() << "Can't possibly happen!";
        break;

    case TodoModel::ProjectTodo:
        parentUid = current.data(TodoModel::UidRole).toString();
        collection = current.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Collection:
        collection = current.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Category:
        category = current.data(Qt::EditRole).toString();
        // fallthrough
    case TodoModel::Inbox:
    case TodoModel::CategoryRoot:
        collection = m_defaultCollection;
        break;
    }

    KCalCore::Todo::Ptr todo(new KCalCore::Todo);
    todo->setSummary(summary);
    if (!parentUid.isEmpty()) {
        todo->setRelatedTo(parentUid);
    }
    if (!category.isEmpty()) {
        todo->setCategories(category);
    }

    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<KCalCore::Todo::Ptr>(todo);

    new Akonadi::ItemCreateJob(item, collection);
}

void ActionListEditorPage::removeCurrentTodo()
{
    QModelIndex current = m_treeView->selectionModel()->currentIndex();
    int type = current.data(TodoModel::ItemTypeRole).toInt();

    if (!current.isValid() || type!=TodoModel::StandardTodo) {
        return;
    }

    Akonadi::Item item = current.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
    if (!item.isValid()) {
        return;
    }

    new Akonadi::ItemDeleteJob(item, this);
}

Zanshin::ApplicationMode ActionListEditorPage::mode()
{
    return m_mode;
}

void ActionListEditorPage::onAutoHideColumns()
{
    switch (m_mode) {
    case Zanshin::ProjectMode:
        hideColumn(1);
        break;
    case Zanshin::CategoriesMode:
        hideColumn(2);
        break;
    }
}

void ActionListEditorPage::hideColumn(int column)
{
    if (!m_treeView->isColumnHidden(column)) {
        m_treeView->hideColumn(column);
    }
}

void ActionListEditorPage::setCollectionColumnHidden(bool hidden)
{
    QByteArray state = hidden ? m_noCollectionStateCache : m_normalStateCache;

    if (!state.isEmpty()) {
        m_treeView->header()->restoreState(state);
    } else {
        m_treeView->setColumnHidden(4, hidden);
    }
}

void ActionListEditorPage::onColumnsGeometryChanged()
{
    if (!m_treeView->isColumnHidden(4)) {
        m_normalStateCache = m_treeView->header()->saveState();
    } else {
        m_noCollectionStateCache = m_treeView->header()->saveState();
    }
}

void ActionListEditorPage::setDefaultCollection(const Akonadi::Collection &collection)
{
    m_defaultCollection = collection;
}
<commit_msg>Make sure standard todo always come first in the list<commit_after>/* This file is part of Zanshin Todo.

   Copyright 2008-2010 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "actionlisteditorpage.h"

#include <KDE/Akonadi/ItemCreateJob>
#include <KDE/Akonadi/ItemDeleteJob>

#include <KDE/KConfigGroup>
#include <kdescendantsproxymodel.h>
#include <kmodelindexproxymapper.h>

#include <QtCore/QTimer>
#include <QtGui/QHeaderView>
#include <QtGui/QSortFilterProxyModel>
#include <QtGui/QVBoxLayout>

#include "actionlistdelegate.h"
#include "todomodel.h"
#include "todotreeview.h"

class GroupLabellingProxyModel : public QSortFilterProxyModel
{
public:
    GroupLabellingProxyModel(QObject *parent = 0)
        : QSortFilterProxyModel(parent)
    {
        setDynamicSortFilter(true);
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
    {
        if (role!=Qt::DisplayRole || index.column()!=0) {
            return QSortFilterProxyModel::data(index, role);
        } else {
            int type = index.data(TodoModel::ItemTypeRole).toInt();

            if (type!=TodoModel::ProjectTodo
             && type!=TodoModel::Category) {
                return QSortFilterProxyModel::data(index, role);

            } else {
                QString display = QSortFilterProxyModel::data(index, role).toString();

                QModelIndex currentIndex = index.parent();
                type = currentIndex.data(TodoModel::ItemTypeRole).toInt();

                while (type==TodoModel::ProjectTodo
                    || type==TodoModel::Category) {
                    display = currentIndex.data(role).toString() + ": " + display;

                    currentIndex = currentIndex.parent();
                    type = currentIndex.data(TodoModel::ItemTypeRole).toInt();
                }

                return display;
            }
        }
    }
};

class GroupSortingProxyModel : public QSortFilterProxyModel
{
public:
    GroupSortingProxyModel(QObject *parent = 0)
        : QSortFilterProxyModel(parent)
    {
        setDynamicSortFilter(true);
        setFilterCaseSensitivity(Qt::CaseInsensitive);
    }

    bool lessThan(const QModelIndex &left, const QModelIndex &right) const
    {
        int leftType = left.data(TodoModel::ItemTypeRole).toInt();
        int rightType = right.data(TodoModel::ItemTypeRole).toInt();

        return leftType==TodoModel::Inbox
            || (leftType==TodoModel::CategoryRoot && rightType!=TodoModel::Inbox)
            || (leftType==TodoModel::Collection && rightType!=TodoModel::Inbox)
            || (leftType==TodoModel::Category && rightType==TodoModel::StandardTodo)
            || (leftType==TodoModel::StandardTodo && rightType!=TodoModel::StandardTodo)
            || (leftType==TodoModel::ProjectTodo && rightType==TodoModel::Collection)
            || (leftType == rightType && QSortFilterProxyModel::lessThan(left, right));
    }
};

class TypeFilterProxyModel : public QSortFilterProxyModel
{
public:
    TypeFilterProxyModel(GroupSortingProxyModel *sorting, QObject *parent = 0)
        : QSortFilterProxyModel(parent), m_sorting(sorting)
    {
        setDynamicSortFilter(true);
        setFilterCaseSensitivity(Qt::CaseInsensitive);
    }

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    {
        QModelIndex sourceChild = sourceModel()->index(sourceRow, 0, sourceParent);
        int type = sourceChild.data(TodoModel::ItemTypeRole).toInt();

        QSize sizeHint = sourceChild.data(Qt::SizeHintRole).toSize();

        return type!=TodoModel::Collection
            && type!=TodoModel::CategoryRoot
            && !sizeHint.isNull(); // SelectionProxyModel uses the null size for items we shouldn't display
    }

    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
    {
        m_sorting->sort(column, order);
    }

private:
    GroupSortingProxyModel *m_sorting;
};

class ActionListEditorView : public TodoTreeView
{
public:
    ActionListEditorView(QWidget *parent = 0)
        : TodoTreeView(parent) { }

protected:
    virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    {
        QModelIndex index = currentIndex();

        if (index.isValid() && modifiers==Qt::NoModifier) {
            QModelIndex newIndex;
            int newColumn = index.column();

            switch (cursorAction) {
            case MoveLeft:
                do {
                    newColumn--;
                } while (isColumnHidden(newColumn)
                      && newColumn>=0);
                break;

            case MoveRight:
                do {
                    newColumn++;
                } while (isColumnHidden(newColumn)
                      && newColumn<header()->count());
                break;

            default:
                return Akonadi::EntityTreeView::moveCursor(cursorAction, modifiers);
            }

            newIndex = index.sibling(index.row(), newColumn);

            if (newIndex.isValid()) {
                return newIndex;
            }
        }

        return Akonadi::EntityTreeView::moveCursor(cursorAction, modifiers);
    }
};

class ActionListEditorModel : public KDescendantsProxyModel
{
public:
    ActionListEditorModel(QObject *parent = 0)
        : KDescendantsProxyModel(parent)
    {
    }

    virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
        if (!sourceModel()) {
            return QAbstractProxyModel::dropMimeData(data, action, row, column, parent);
        }
        QModelIndex sourceParent = mapToSource(parent);
        return sourceModel()->dropMimeData(data, action, row, column, sourceParent);
    }
};

ActionListEditorPage::ActionListEditorPage(QAbstractItemModel *model,
                                           ModelStack *models,
                                           Zanshin::ApplicationMode mode,
                                           QWidget *parent)
    : QWidget(parent), m_mode(mode)
{
    setLayout(new QVBoxLayout(this));
    layout()->setContentsMargins(0, 0, 0, 0);

    m_treeView = new ActionListEditorView(this);

    GroupLabellingProxyModel *labelling = new GroupLabellingProxyModel(this);
    labelling->setSourceModel(model);

    GroupSortingProxyModel *sorting = new GroupSortingProxyModel(this);
    sorting->setSourceModel(labelling);

    ActionListEditorModel *descendants = new ActionListEditorModel(this);
    descendants->setSourceModel(sorting);

    TypeFilterProxyModel *filter = new TypeFilterProxyModel(sorting, this);
    filter->setSourceModel(descendants);

    m_treeView->setModel(filter);
    m_treeView->setItemDelegate(new ActionListDelegate(models, m_treeView));

    m_treeView->header()->setSortIndicatorShown(true);
    m_treeView->setSortingEnabled(true);
    m_treeView->sortByColumn(0, Qt::AscendingOrder);

    m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    m_treeView->setItemsExpandable(false);
    m_treeView->setRootIsDecorated(false);
    m_treeView->setEditTriggers(m_treeView->editTriggers() | QAbstractItemView::DoubleClicked);

    connect(m_treeView->model(), SIGNAL(modelReset()),
            m_treeView, SLOT(expandAll()));
    connect(m_treeView->model(), SIGNAL(layoutChanged()),
            m_treeView, SLOT(expandAll()));
    connect(m_treeView->model(), SIGNAL(rowsInserted(QModelIndex, int, int)),
            m_treeView, SLOT(expandAll()));

    layout()->addWidget(m_treeView);

    QTimer::singleShot(0, this, SLOT(onAutoHideColumns()));

    connect(m_treeView->header(), SIGNAL(sectionResized(int, int, int)),
            this, SLOT(onColumnsGeometryChanged()));
}

QItemSelectionModel *ActionListEditorPage::selectionModel() const
{
    return m_treeView->selectionModel();
}

void ActionListEditorPage::saveColumnsState(KConfigGroup &config, const QString &key) const
{
    config.writeEntry(key+"/Normal", m_normalStateCache.toBase64());
    config.writeEntry(key+"/NoCollection", m_noCollectionStateCache.toBase64());
}

void ActionListEditorPage::restoreColumnsState(const KConfigGroup &config, const QString &key)
{
    if (config.hasKey(key+"/Normal")) {
        m_normalStateCache = QByteArray::fromBase64(config.readEntry(key+"/Normal", QByteArray()));
    }

    if (config.hasKey(key+"/NoCollection")) {
        m_noCollectionStateCache = QByteArray::fromBase64(config.readEntry(key+"/NoCollection", QByteArray()));
    }

    if (!m_treeView->isColumnHidden(4)) {
        m_treeView->header()->restoreState(m_normalStateCache);
    } else {
        m_treeView->header()->restoreState(m_noCollectionStateCache);
    }
}

void ActionListEditorPage::addNewTodo(const QString &summary)
{
    if (summary.isEmpty()) return;

    QModelIndex current = m_treeView->selectionModel()->currentIndex();

    if (!current.isValid()) {
        kWarning() << "Oops, nothing selected in the list!";
        return;
    }

    int type = current.data(TodoModel::ItemTypeRole).toInt();

    while (current.isValid() && type==TodoModel::StandardTodo) {
        current = current.parent();
        type = current.data(TodoModel::ItemTypeRole).toInt();
    }

    Akonadi::Collection collection;
    QString parentUid;
    QString category;

    switch (type) {
    case TodoModel::StandardTodo:
        kFatal() << "Can't possibly happen!";
        break;

    case TodoModel::ProjectTodo:
        parentUid = current.data(TodoModel::UidRole).toString();
        collection = current.data(Akonadi::EntityTreeModel::ParentCollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Collection:
        collection = current.data(Akonadi::EntityTreeModel::CollectionRole).value<Akonadi::Collection>();
        break;

    case TodoModel::Category:
        category = current.data(Qt::EditRole).toString();
        // fallthrough
    case TodoModel::Inbox:
    case TodoModel::CategoryRoot:
        collection = m_defaultCollection;
        break;
    }

    KCalCore::Todo::Ptr todo(new KCalCore::Todo);
    todo->setSummary(summary);
    if (!parentUid.isEmpty()) {
        todo->setRelatedTo(parentUid);
    }
    if (!category.isEmpty()) {
        todo->setCategories(category);
    }

    Akonadi::Item item;
    item.setMimeType("application/x-vnd.akonadi.calendar.todo");
    item.setPayload<KCalCore::Todo::Ptr>(todo);

    new Akonadi::ItemCreateJob(item, collection);
}

void ActionListEditorPage::removeCurrentTodo()
{
    QModelIndex current = m_treeView->selectionModel()->currentIndex();
    int type = current.data(TodoModel::ItemTypeRole).toInt();

    if (!current.isValid() || type!=TodoModel::StandardTodo) {
        return;
    }

    Akonadi::Item item = current.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
    if (!item.isValid()) {
        return;
    }

    new Akonadi::ItemDeleteJob(item, this);
}

Zanshin::ApplicationMode ActionListEditorPage::mode()
{
    return m_mode;
}

void ActionListEditorPage::onAutoHideColumns()
{
    switch (m_mode) {
    case Zanshin::ProjectMode:
        hideColumn(1);
        break;
    case Zanshin::CategoriesMode:
        hideColumn(2);
        break;
    }
}

void ActionListEditorPage::hideColumn(int column)
{
    if (!m_treeView->isColumnHidden(column)) {
        m_treeView->hideColumn(column);
    }
}

void ActionListEditorPage::setCollectionColumnHidden(bool hidden)
{
    QByteArray state = hidden ? m_noCollectionStateCache : m_normalStateCache;

    if (!state.isEmpty()) {
        m_treeView->header()->restoreState(state);
    } else {
        m_treeView->setColumnHidden(4, hidden);
    }
}

void ActionListEditorPage::onColumnsGeometryChanged()
{
    if (!m_treeView->isColumnHidden(4)) {
        m_normalStateCache = m_treeView->header()->saveState();
    } else {
        m_noCollectionStateCache = m_treeView->header()->saveState();
    }
}

void ActionListEditorPage::setDefaultCollection(const Akonadi::Collection &collection)
{
    m_defaultCollection = collection;
}
<|endoftext|>


<commit_before>#include<iostream>

 int main()
 {
	 using std::cin;
	 using std::cout;
	 using std::endl;
	 int i = 0, n = 0;
	 cout<<"How many numbers would you like to have on your list?"<<endl;
	 cin>>n;
	 int *list = new int [n];
	 cout<<"Please enter the integers."<<endl;
	 for(i = 0; i < n; i++)
	 {
		 cin>>list[i];
 	 }
	 cout<<"The numbers you have added are ";
	 for(i = 0; i < n; i++)
	 {
		 cout<<*(list + i)<<" ";
	 }
	 cout<<"."<<endl;
	 delete [] list;
	 return 0;
 }
<commit_msg>Code Update<commit_after>#include <iostream>

 int main()
 {
	 using std::cin;
	 using std::cout;
	 using std::endl;
	 int i = 0, n = 0;
	 cout<<"How many numbers would you like to have on your list?"<<endl;
	 cin>>n;
	 int *list = new int [n];
	 cout<<"Please enter the integers."<<endl;
	 for(i = 0; i < n; i++)
	 {
		 cin>>list[i];
 	 }
	 cout<<"The numbers you have added are ";
	 for(i = 0; i < n; i++)
	 {
		 cout<<*(list + i)<<" ";
	 }
	 cout<<"."<<endl;
	 delete [] list;
	 return 0;
 }<|endoftext|>