<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include "native-stack.hh"
#include "native-stack-impl.hh"
#include "net.hh"
#include "ip.hh"
#include "tcp-stack.hh"
#include "tcp.hh"
#include "udp.hh"
#include "virtio.hh"
#include "dpdk.hh"
#include "xenfront.hh"
#include "proxy.hh"
#include "dhcp.hh"
#include <memory>
#include <queue>
#ifdef HAVE_OSV
#include <osv/firmware.hh>
#include <gnu/libc-version.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

namespace net {

using namespace seastar;

enum class xen_info {
    nonxen = 0,
    userspace = 1,
    osv = 2,
};

#ifdef HAVE_XEN
static xen_info is_xen()
{
    struct stat buf;
    if (!stat("/proc/xen", &buf) || !stat("/dev/xen", &buf)) {
        return xen_info::userspace;
    }

#ifdef HAVE_OSV
    const char *str = gnu_get_libc_release();
    if (std::string("OSv") != str) {
        return xen_info::nonxen;
    }
    auto firmware = osv::firmware_vendor();
    if (firmware == "Xen") {
        return xen_info::osv;
    }
#endif

    return xen_info::nonxen;
}
#endif

void create_native_net_device(boost::program_options::variables_map opts) {
    std::unique_ptr<device> dev;

#ifdef HAVE_XEN
    auto xen = is_xen();
    if (xen != xen_info::nonxen) {
        dev = xen::create_xenfront_net_device(opts, xen == xen_info::userspace);
    } else
#endif

#ifdef HAVE_DPDK
    if (opts.count("dpdk-pmd")) {
        // Hardcoded port index 0.
        // TODO: Inherit it from the opts
        dev = create_dpdk_net_device(0, smp::count,
            !(opts.count("lro") && opts["lro"].as<std::string>() == "off"),
            !(opts.count("hw-fc") && opts["hw-fc"].as<std::string>() == "off"));
    } else
#endif
    dev = create_virtio_net_device(opts);

    auto sem = std::make_shared<semaphore>(0);
    std::shared_ptr<device> sdev(dev.release());
    for (unsigned i = 0; i < smp::count; i++) {
        smp::submit_to(i, [opts, sdev] {
            uint16_t qid = engine().cpu_id();
            if (qid < sdev->hw_queues_count()) {
                auto qp = sdev->init_local_queue(opts, qid);
                std::map<unsigned, float> cpu_weights;
                for (unsigned i = sdev->hw_queues_count() + qid % sdev->hw_queues_count(); i < smp::count; i+= sdev->hw_queues_count()) {
                    cpu_weights[i] = 1;
                }
                cpu_weights[qid] = opts["hw-queue-weight"].as<float>();
                qp->configure_proxies(cpu_weights);
                sdev->set_local_queue(std::move(qp));
            } else {
                auto master = qid % sdev->hw_queues_count();
                sdev->set_local_queue(create_proxy_net_device(master, sdev.get()));
            }
        }).then([sem] {
            sem->signal();
        });
    }
    sem->wait(smp::count).then([opts, sdev] {
        sdev->link_ready().then([opts, sdev] {
            for (unsigned i = 0; i < smp::count; i++) {
                smp::submit_to(i, [opts, sdev] {
                    create_native_stack(opts, sdev);
                });
            }
        });
    });
}

// native_network_stack
class native_network_stack : public network_stack {
public:
    static thread_local promise<std::unique_ptr<network_stack>> ready_promise;
private:
    interface _netif;
    ipv4 _inet;
    bool _dhcp = false;
    promise<> _config;
    timer<> _timer;

    future<> run_dhcp(bool is_renew = false, const dhcp::lease & res = dhcp::lease());
    void on_dhcp(bool, const dhcp::lease &, bool);
    void set_ipv4_packet_filter(ip_packet_filter* filter) {
        _inet.set_packet_filter(filter);
    }
    using tcp4 = tcp<ipv4_traits>;
public:
    explicit native_network_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev);
    virtual server_socket listen(socket_address sa, listen_options opt) override;
    virtual ::seastar::socket socket() override;
    virtual udp_channel make_udp_channel(ipv4_addr addr) override;
    virtual future<> initialize() override;
    static future<std::unique_ptr<network_stack>> create(boost::program_options::variables_map opts) {
        if (engine().cpu_id() == 0) {
            create_native_net_device(opts);
        }
        return ready_promise.get_future();
    }
    virtual bool has_per_core_namespace() override { return true; };
    void arp_learn(ethernet_address l2, ipv4_address l3) {
        _inet.learn(l2, l3);
    }
    friend class native_server_socket_impl<tcp4>;
};

thread_local promise<std::unique_ptr<network_stack>> native_network_stack::ready_promise;

udp_channel
native_network_stack::make_udp_channel(ipv4_addr addr) {
    return _inet.get_udp().make_channel(addr);
}

void
add_native_net_options_description(boost::program_options::options_description &opts) {

#ifdef HAVE_XEN
    auto xen = is_xen();
    if (xen != xen_info::nonxen) {
        opts.add(xen::get_xenfront_net_options_description());
        return;
    }
#endif
    opts.add(get_virtio_net_options_description());
#ifdef HAVE_DPDK
    opts.add(get_dpdk_net_options_description());
#endif
}

native_network_stack::native_network_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev)
    : _netif(std::move(dev))
    , _inet(&_netif) {
    _inet.get_udp().set_queue_size(opts["udpv4-queue-size"].as<int>());
    _dhcp = opts["host-ipv4-addr"].defaulted()
            && opts["gw-ipv4-addr"].defaulted()
            && opts["netmask-ipv4-addr"].defaulted() && opts["dhcp"].as<bool>();
    if (!_dhcp) {
        _inet.set_host_address(ipv4_address(_dhcp ? 0 : opts["host-ipv4-addr"].as<std::string>()));
        _inet.set_gw_address(ipv4_address(opts["gw-ipv4-addr"].as<std::string>()));
        _inet.set_netmask_address(ipv4_address(opts["netmask-ipv4-addr"].as<std::string>()));
    }
}

server_socket
native_network_stack::listen(socket_address sa, listen_options opts) {
    assert(sa.as_posix_sockaddr().sa_family == AF_INET);
    return tcpv4_listen(_inet.get_tcp(), ntohs(sa.as_posix_sockaddr_in().sin_port), opts);
}

seastar::socket native_network_stack::socket() {
    return tcpv4_socket(_inet.get_tcp());
}

using namespace std::chrono_literals;

future<> native_network_stack::run_dhcp(bool is_renew, const dhcp::lease& res) {
    lw_shared_ptr<dhcp> d = make_lw_shared<dhcp>(_inet);

    // Hijack the ip-stack.
    for (unsigned i = 0; i < smp::count; i++) {
        smp::submit_to(i, [d] {
            auto & ns = static_cast<native_network_stack&>(engine().net());
            ns.set_ipv4_packet_filter(d->get_ipv4_filter());
        });
    }

    net::dhcp::result_type fut = is_renew ? d->renew(res) : d->discover();

    return fut.then([this, d, is_renew](bool success, const dhcp::lease & res) {
        for (unsigned i = 0; i < smp::count; i++) {
            smp::submit_to(i, [] {
                auto & ns = static_cast<native_network_stack&>(engine().net());
                ns.set_ipv4_packet_filter(nullptr);
            });
        }
        on_dhcp(success, res, is_renew);
    });
}

void native_network_stack::on_dhcp(bool success, const dhcp::lease & res, bool is_renew) {
    if (success) {
        _inet.set_host_address(res.ip);
        _inet.set_gw_address(res.gateway);
        _inet.set_netmask_address(res.netmask);
    }
    // Signal waiters.
    if (!is_renew) {
        _config.set_value();
    }

    if (engine().cpu_id() == 0) {
        // And the other cpus, which, in the case of initial discovery,
        // will be waiting for us.
        for (unsigned i = 1; i < smp::count; i++) {
            smp::submit_to(i, [success, res, is_renew]() {
                auto & ns = static_cast<native_network_stack&>(engine().net());
                ns.on_dhcp(success, res, is_renew);
            });
        }
        if (success) {
            // And set up to renew the lease later on.
            _timer.set_callback(
                    [this, res]() {
                        _config = promise<>();
                        run_dhcp(true, res);
                    });
            _timer.arm(
                    std::chrono::duration_cast<steady_clock_type::duration>(
                            res.lease_time));
        }
    }
}

future<> native_network_stack::initialize() {
    return network_stack::initialize().then([this]() {
        if (!_dhcp) {
            return make_ready_future();
        }

        // Only run actual discover on main cpu.
        // All other cpus must simply for main thread to complete and signal them.
        if (engine().cpu_id() == 0) {
            run_dhcp();
        }
        return _config.get_future();
    });
}

void arp_learn(ethernet_address l2, ipv4_address l3)
{
    for (unsigned i = 0; i < smp::count; i++) {
        smp::submit_to(i, [l2, l3] {
            auto & ns = static_cast<native_network_stack&>(engine().net());
            ns.arp_learn(l2, l3);
        });
    }
}

void create_native_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev) {
    native_network_stack::ready_promise.set_value(std::unique_ptr<network_stack>(std::make_unique<native_network_stack>(opts, std::move(dev))));
}

boost::program_options::options_description nns_options() {
    boost::program_options::options_description opts(
            "Native networking stack options");
    opts.add_options()
        ("tap-device",
                boost::program_options::value<std::string>()->default_value("tap0"),
                "tap device to connect to")
        ("host-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("192.168.122.2"),
                "static IPv4 address to use")
        ("gw-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("192.168.122.1"),
                "static IPv4 gateway to use")
        ("netmask-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("255.255.255.0"),
                "static IPv4 netmask to use")
        ("udpv4-queue-size",
                boost::program_options::value<int>()->default_value(ipv4_udp::default_queue_size),
                "Default size of the UDPv4 per-channel packet queue")
        ("dhcp",
                boost::program_options::value<bool>()->default_value(true),
                        "Use DHCP discovery")
        ("hw-queue-weight",
                boost::program_options::value<float>()->default_value(1.0f),
                "Weighing of a hardware network queue relative to a software queue (0=no work, 1=equal share)")
#ifdef HAVE_DPDK
        ("dpdk-pmd", "Use DPDK PMD drivers")
#endif
        ("lro",
                boost::program_options::value<std::string>()->default_value("on"),
                "Enable LRO")
        ;

    add_native_net_options_description(opts);
    return opts;
}

network_stack_registrator nns_registrator{
    "native", nns_options(), native_network_stack::create
};

}
<commit_msg>native_network_stack: Fix use after free/missing wait in dhcp<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include "native-stack.hh"
#include "native-stack-impl.hh"
#include "net.hh"
#include "ip.hh"
#include "tcp-stack.hh"
#include "tcp.hh"
#include "udp.hh"
#include "virtio.hh"
#include "dpdk.hh"
#include "xenfront.hh"
#include "proxy.hh"
#include "dhcp.hh"
#include <memory>
#include <queue>
#ifdef HAVE_OSV
#include <osv/firmware.hh>
#include <gnu/libc-version.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

namespace net {

using namespace seastar;

enum class xen_info {
    nonxen = 0,
    userspace = 1,
    osv = 2,
};

#ifdef HAVE_XEN
static xen_info is_xen()
{
    struct stat buf;
    if (!stat("/proc/xen", &buf) || !stat("/dev/xen", &buf)) {
        return xen_info::userspace;
    }

#ifdef HAVE_OSV
    const char *str = gnu_get_libc_release();
    if (std::string("OSv") != str) {
        return xen_info::nonxen;
    }
    auto firmware = osv::firmware_vendor();
    if (firmware == "Xen") {
        return xen_info::osv;
    }
#endif

    return xen_info::nonxen;
}
#endif

void create_native_net_device(boost::program_options::variables_map opts) {
    std::unique_ptr<device> dev;

#ifdef HAVE_XEN
    auto xen = is_xen();
    if (xen != xen_info::nonxen) {
        dev = xen::create_xenfront_net_device(opts, xen == xen_info::userspace);
    } else
#endif

#ifdef HAVE_DPDK
    if (opts.count("dpdk-pmd")) {
        // Hardcoded port index 0.
        // TODO: Inherit it from the opts
        dev = create_dpdk_net_device(0, smp::count,
            !(opts.count("lro") && opts["lro"].as<std::string>() == "off"),
            !(opts.count("hw-fc") && opts["hw-fc"].as<std::string>() == "off"));
    } else
#endif
    dev = create_virtio_net_device(opts);

    auto sem = std::make_shared<semaphore>(0);
    std::shared_ptr<device> sdev(dev.release());
    for (unsigned i = 0; i < smp::count; i++) {
        smp::submit_to(i, [opts, sdev] {
            uint16_t qid = engine().cpu_id();
            if (qid < sdev->hw_queues_count()) {
                auto qp = sdev->init_local_queue(opts, qid);
                std::map<unsigned, float> cpu_weights;
                for (unsigned i = sdev->hw_queues_count() + qid % sdev->hw_queues_count(); i < smp::count; i+= sdev->hw_queues_count()) {
                    cpu_weights[i] = 1;
                }
                cpu_weights[qid] = opts["hw-queue-weight"].as<float>();
                qp->configure_proxies(cpu_weights);
                sdev->set_local_queue(std::move(qp));
            } else {
                auto master = qid % sdev->hw_queues_count();
                sdev->set_local_queue(create_proxy_net_device(master, sdev.get()));
            }
        }).then([sem] {
            sem->signal();
        });
    }
    sem->wait(smp::count).then([opts, sdev] {
        sdev->link_ready().then([opts, sdev] {
            for (unsigned i = 0; i < smp::count; i++) {
                smp::submit_to(i, [opts, sdev] {
                    create_native_stack(opts, sdev);
                });
            }
        });
    });
}

// native_network_stack
class native_network_stack : public network_stack {
public:
    static thread_local promise<std::unique_ptr<network_stack>> ready_promise;
private:
    interface _netif;
    ipv4 _inet;
    bool _dhcp = false;
    promise<> _config;
    timer<> _timer;

    future<> run_dhcp(bool is_renew = false, const dhcp::lease & res = dhcp::lease());
    void on_dhcp(bool, const dhcp::lease &, bool);
    void set_ipv4_packet_filter(ip_packet_filter* filter) {
        _inet.set_packet_filter(filter);
    }
    using tcp4 = tcp<ipv4_traits>;
public:
    explicit native_network_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev);
    virtual server_socket listen(socket_address sa, listen_options opt) override;
    virtual ::seastar::socket socket() override;
    virtual udp_channel make_udp_channel(ipv4_addr addr) override;
    virtual future<> initialize() override;
    static future<std::unique_ptr<network_stack>> create(boost::program_options::variables_map opts) {
        if (engine().cpu_id() == 0) {
            create_native_net_device(opts);
        }
        return ready_promise.get_future();
    }
    virtual bool has_per_core_namespace() override { return true; };
    void arp_learn(ethernet_address l2, ipv4_address l3) {
        _inet.learn(l2, l3);
    }
    friend class native_server_socket_impl<tcp4>;
};

thread_local promise<std::unique_ptr<network_stack>> native_network_stack::ready_promise;

udp_channel
native_network_stack::make_udp_channel(ipv4_addr addr) {
    return _inet.get_udp().make_channel(addr);
}

void
add_native_net_options_description(boost::program_options::options_description &opts) {

#ifdef HAVE_XEN
    auto xen = is_xen();
    if (xen != xen_info::nonxen) {
        opts.add(xen::get_xenfront_net_options_description());
        return;
    }
#endif
    opts.add(get_virtio_net_options_description());
#ifdef HAVE_DPDK
    opts.add(get_dpdk_net_options_description());
#endif
}

native_network_stack::native_network_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev)
    : _netif(std::move(dev))
    , _inet(&_netif) {
    _inet.get_udp().set_queue_size(opts["udpv4-queue-size"].as<int>());
    _dhcp = opts["host-ipv4-addr"].defaulted()
            && opts["gw-ipv4-addr"].defaulted()
            && opts["netmask-ipv4-addr"].defaulted() && opts["dhcp"].as<bool>();
    if (!_dhcp) {
        _inet.set_host_address(ipv4_address(_dhcp ? 0 : opts["host-ipv4-addr"].as<std::string>()));
        _inet.set_gw_address(ipv4_address(opts["gw-ipv4-addr"].as<std::string>()));
        _inet.set_netmask_address(ipv4_address(opts["netmask-ipv4-addr"].as<std::string>()));
    }
}

server_socket
native_network_stack::listen(socket_address sa, listen_options opts) {
    assert(sa.as_posix_sockaddr().sa_family == AF_INET);
    return tcpv4_listen(_inet.get_tcp(), ntohs(sa.as_posix_sockaddr_in().sin_port), opts);
}

seastar::socket native_network_stack::socket() {
    return tcpv4_socket(_inet.get_tcp());
}

using namespace std::chrono_literals;

future<> native_network_stack::run_dhcp(bool is_renew, const dhcp::lease& res) {
    dhcp d(_inet);
    // Hijack the ip-stack.
    auto f = d.get_ipv4_filter();
    return smp::invoke_on_all([f] {
        auto & ns = static_cast<native_network_stack&>(engine().net());
        ns.set_ipv4_packet_filter(f);
    }).then([this, d = std::move(d), is_renew, res]() mutable {
        net::dhcp::result_type fut = is_renew ? d.renew(res) : d.discover();
        return fut.then([this, is_renew](bool success, const dhcp::lease & res) {
            return smp::invoke_on_all([] {
                auto & ns = static_cast<native_network_stack&>(engine().net());
                ns.set_ipv4_packet_filter(nullptr);
            }).then(std::bind(&net::native_network_stack::on_dhcp, this, success, res, is_renew));
        }).finally([d = std::move(d)] {});
    });
}

void native_network_stack::on_dhcp(bool success, const dhcp::lease & res, bool is_renew) {
    if (success) {
        _inet.set_host_address(res.ip);
        _inet.set_gw_address(res.gateway);
        _inet.set_netmask_address(res.netmask);
    }
    // Signal waiters.
    if (!is_renew) {
        _config.set_value();
    }

    if (engine().cpu_id() == 0) {
        // And the other cpus, which, in the case of initial discovery,
        // will be waiting for us.
        for (unsigned i = 1; i < smp::count; i++) {
            smp::submit_to(i, [success, res, is_renew]() {
                auto & ns = static_cast<native_network_stack&>(engine().net());
                ns.on_dhcp(success, res, is_renew);
            });
        }
        if (success) {
            // And set up to renew the lease later on.
            _timer.set_callback(
                    [this, res]() {
                        _config = promise<>();
                        run_dhcp(true, res);
                    });
            _timer.arm(
                    std::chrono::duration_cast<steady_clock_type::duration>(
                            res.lease_time));
        }
    }
}

future<> native_network_stack::initialize() {
    return network_stack::initialize().then([this]() {
        if (!_dhcp) {
            return make_ready_future();
        }

        // Only run actual discover on main cpu.
        // All other cpus must simply for main thread to complete and signal them.
        if (engine().cpu_id() == 0) {
            run_dhcp();
        }
        return _config.get_future();
    });
}

void arp_learn(ethernet_address l2, ipv4_address l3)
{
    for (unsigned i = 0; i < smp::count; i++) {
        smp::submit_to(i, [l2, l3] {
            auto & ns = static_cast<native_network_stack&>(engine().net());
            ns.arp_learn(l2, l3);
        });
    }
}

void create_native_stack(boost::program_options::variables_map opts, std::shared_ptr<device> dev) {
    native_network_stack::ready_promise.set_value(std::unique_ptr<network_stack>(std::make_unique<native_network_stack>(opts, std::move(dev))));
}

boost::program_options::options_description nns_options() {
    boost::program_options::options_description opts(
            "Native networking stack options");
    opts.add_options()
        ("tap-device",
                boost::program_options::value<std::string>()->default_value("tap0"),
                "tap device to connect to")
        ("host-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("192.168.122.2"),
                "static IPv4 address to use")
        ("gw-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("192.168.122.1"),
                "static IPv4 gateway to use")
        ("netmask-ipv4-addr",
                boost::program_options::value<std::string>()->default_value("255.255.255.0"),
                "static IPv4 netmask to use")
        ("udpv4-queue-size",
                boost::program_options::value<int>()->default_value(ipv4_udp::default_queue_size),
                "Default size of the UDPv4 per-channel packet queue")
        ("dhcp",
                boost::program_options::value<bool>()->default_value(true),
                        "Use DHCP discovery")
        ("hw-queue-weight",
                boost::program_options::value<float>()->default_value(1.0f),
                "Weighing of a hardware network queue relative to a software queue (0=no work, 1=equal share)")
#ifdef HAVE_DPDK
        ("dpdk-pmd", "Use DPDK PMD drivers")
#endif
        ("lro",
                boost::program_options::value<std::string>()->default_value("on"),
                "Enable LRO")
        ;

    add_native_net_options_description(opts);
    return opts;
}

network_stack_registrator nns_registrator{
    "native", nns_options(), native_network_stack::create
};

}
<|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  09/2018

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

#ifndef ROOT_RCUSTOMCOLUMN
#define ROOT_RCUSTOMCOLUMN

#include "ROOT/RDF/NodesUtils.hxx"
#include "ROOT/RDF/RColumnValue.hxx"
#include "ROOT/RDF/RCustomColumnBase.hxx"
#include "ROOT/RDF/Utils.hxx"
#include "ROOT/RIntegerSequence.hxx"
#include "ROOT/RStringView.hxx"
#include "ROOT/TypeTraits.hxx"
#include "RtypesCore.h"

#include <deque>
#include <type_traits>
#include <vector>

class TTreeReader;

namespace ROOT {
namespace Detail {
namespace RDF {

using namespace ROOT::TypeTraits;

// clang-format off
namespace CustomColExtraArgs {
struct None{};
struct Slot{};
struct SlotAndEntry{};
}
// clang-format on

template <typename F, typename ExtraArgsTag = CustomColExtraArgs::None>
class RCustomColumn final : public RCustomColumnBase {
   // shortcuts
   using NoneTag = CustomColExtraArgs::None;
   using SlotTag = CustomColExtraArgs::Slot;
   using SlotAndEntryTag = CustomColExtraArgs::SlotAndEntry;
   // other types
   using FunParamTypes_t = typename CallableTraits<F>::arg_types;
   using ColumnTypesTmp_t =
      RDFInternal::RemoveFirstParameterIf_t<std::is_same<ExtraArgsTag, SlotTag>::value, FunParamTypes_t>;
   using ColumnTypes_t =
      RDFInternal::RemoveFirstTwoParametersIf_t<std::is_same<ExtraArgsTag, SlotAndEntryTag>::value, ColumnTypesTmp_t>;
   using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
   using ret_type = typename CallableTraits<F>::ret_type;
   // Avoid instantiating vector<bool> as `operator[]` returns temporaries in that case. Use std::deque instead.
   using ValuesPerSlot_t =
      typename std::conditional<std::is_same<ret_type, bool>::value, std::deque<ret_type>, std::vector<ret_type>>::type;

   F fExpression;
   const ColumnNames_t fBranches;
   ValuesPerSlot_t fLastResults;

   std::vector<RDFInternal::RDFValueTuple_t<ColumnTypes_t>> fValues;

public:
   RCustomColumn(RLoopManager *lm, std::string_view name, F &&expression, const ColumnNames_t &bl, unsigned int nSlots,
                 const RDFInternal::RBookedCustomColumns &customColumns, bool isDSColumn = false)
      : RCustomColumnBase(lm, name, nSlots, isDSColumn, customColumns), fExpression(std::forward<F>(expression)),
        fBranches(bl), fLastResults(fNSlots), fValues(fNSlots)
   {
   }

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

   void InitSlot(TTreeReader *r, unsigned int slot) final
   {
      // TODO: Each node calls this method for each column it uses. Multiple nodes may share the same columns, and this
      // would lead to this method being called multiple times.
      RDFInternal::InitRDFValues(slot, fValues[slot], r, fBranches, fCustomColumns, TypeInd_t());
   }

   void *GetValuePtr(unsigned int slot) final { return static_cast<void *>(&fLastResults[slot]); }

   void Update(unsigned int slot, Long64_t entry) final
   {
      if (entry != fLastCheckedEntry[slot]) {
         // evaluate this filter, cache the result
         UpdateHelper(slot, entry, TypeInd_t(), ColumnTypes_t(), ExtraArgsTag{});
         fLastCheckedEntry[slot] = entry;
      }
   }

   const std::type_info &GetTypeId() const
   {
      return fIsDataSourceColumn ? typeid(typename std::remove_pointer<ret_type>::type) : typeid(ret_type);
   }

   template <std::size_t... S, typename... BranchTypes>
   void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, NoneTag)
   {
      fLastResults[slot] = fExpression(std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }

   template <std::size_t... S, typename... BranchTypes>
   void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, SlotTag)
   {
      fLastResults[slot] = fExpression(slot, std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }

   template <std::size_t... S, typename... BranchTypes>
   void
   UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, SlotAndEntryTag)
   {
      fLastResults[slot] = fExpression(slot, entry, std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }
};

} // ns RDF
} // ns Detail
} // ns ROOT

#endif // ROOT_RCUSTOMCOLUMN
<commit_msg>[DF][NFC] Make RCustomColumn::UpdateHelper private<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  09/2018

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

#ifndef ROOT_RCUSTOMCOLUMN
#define ROOT_RCUSTOMCOLUMN

#include "ROOT/RDF/NodesUtils.hxx"
#include "ROOT/RDF/RColumnValue.hxx"
#include "ROOT/RDF/RCustomColumnBase.hxx"
#include "ROOT/RDF/Utils.hxx"
#include "ROOT/RIntegerSequence.hxx"
#include "ROOT/RStringView.hxx"
#include "ROOT/TypeTraits.hxx"
#include "RtypesCore.h"

#include <deque>
#include <type_traits>
#include <vector>

class TTreeReader;

namespace ROOT {
namespace Detail {
namespace RDF {

using namespace ROOT::TypeTraits;

// clang-format off
namespace CustomColExtraArgs {
struct None{};
struct Slot{};
struct SlotAndEntry{};
}
// clang-format on

template <typename F, typename ExtraArgsTag = CustomColExtraArgs::None>
class RCustomColumn final : public RCustomColumnBase {
   // shortcuts
   using NoneTag = CustomColExtraArgs::None;
   using SlotTag = CustomColExtraArgs::Slot;
   using SlotAndEntryTag = CustomColExtraArgs::SlotAndEntry;
   // other types
   using FunParamTypes_t = typename CallableTraits<F>::arg_types;
   using ColumnTypesTmp_t =
      RDFInternal::RemoveFirstParameterIf_t<std::is_same<ExtraArgsTag, SlotTag>::value, FunParamTypes_t>;
   using ColumnTypes_t =
      RDFInternal::RemoveFirstTwoParametersIf_t<std::is_same<ExtraArgsTag, SlotAndEntryTag>::value, ColumnTypesTmp_t>;
   using TypeInd_t = std::make_index_sequence<ColumnTypes_t::list_size>;
   using ret_type = typename CallableTraits<F>::ret_type;
   // Avoid instantiating vector<bool> as `operator[]` returns temporaries in that case. Use std::deque instead.
   using ValuesPerSlot_t =
      typename std::conditional<std::is_same<ret_type, bool>::value, std::deque<ret_type>, std::vector<ret_type>>::type;

   F fExpression;
   const ColumnNames_t fBranches;
   ValuesPerSlot_t fLastResults;

   std::vector<RDFInternal::RDFValueTuple_t<ColumnTypes_t>> fValues;

   template <std::size_t... S, typename... BranchTypes>
   void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, NoneTag)
   {
      fLastResults[slot] = fExpression(std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }

   template <std::size_t... S, typename... BranchTypes>
   void UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, SlotTag)
   {
      fLastResults[slot] = fExpression(slot, std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }

   template <std::size_t... S, typename... BranchTypes>
   void
   UpdateHelper(unsigned int slot, Long64_t entry, std::index_sequence<S...>, TypeList<BranchTypes...>, SlotAndEntryTag)
   {
      fLastResults[slot] = fExpression(slot, entry, std::get<S>(fValues[slot]).Get(entry)...);
      // silence "unused parameter" warnings in gcc
      (void)slot;
      (void)entry;
   }

public:
   RCustomColumn(RLoopManager *lm, std::string_view name, F &&expression, const ColumnNames_t &bl, unsigned int nSlots,
                 const RDFInternal::RBookedCustomColumns &customColumns, bool isDSColumn = false)
      : RCustomColumnBase(lm, name, nSlots, isDSColumn, customColumns), fExpression(std::forward<F>(expression)),
        fBranches(bl), fLastResults(fNSlots), fValues(fNSlots)
   {
   }

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

   void InitSlot(TTreeReader *r, unsigned int slot) final
   {
      // TODO: Each node calls this method for each column it uses. Multiple nodes may share the same columns, and this
      // would lead to this method being called multiple times.
      RDFInternal::InitRDFValues(slot, fValues[slot], r, fBranches, fCustomColumns, TypeInd_t());
   }

   void *GetValuePtr(unsigned int slot) final { return static_cast<void *>(&fLastResults[slot]); }

   void Update(unsigned int slot, Long64_t entry) final
   {
      if (entry != fLastCheckedEntry[slot]) {
         // evaluate this filter, cache the result
         UpdateHelper(slot, entry, TypeInd_t(), ColumnTypes_t(), ExtraArgsTag{});
         fLastCheckedEntry[slot] = entry;
      }
   }

   const std::type_info &GetTypeId() const
   {
      return fIsDataSourceColumn ? typeid(typename std::remove_pointer<ret_type>::type) : typeid(ret_type);
   }
};

} // ns RDF
} // ns Detail
} // ns ROOT

#endif // ROOT_RCUSTOMCOLUMN
<|endoftext|>


<commit_before>/** \brief Utility for flagging PPNs that may need to be augmented with bible references.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <vector>
#include <cstdlib>
#include "BibleUtil.h"
#include "FileUtil.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "TextUtil.h"
#include "util.h"

namespace {

void Usage() __attribute__((noreturn));

void Usage() {
    std::cerr << "Usage: " << ::progname << " marc_input ppn_candidate_list\n";
    std::exit(EXIT_FAILURE);
}

void LoadPericopes(std::unordered_map<std::string, std::string> * const pericopes_to_codes_map) {
    const std::string PERIOCPES_FILE("/usr/local/var/lib/tuelib/bibleRef/pericopes_to_codes.map");
    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(PERIOCPES_FILE));
    unsigned pericope_count(0), line_no(0);
    while (not input->eof()) {
        ++line_no;
        std::string line;
        input->getline(&line);
        StringUtil::TrimWhite(&line);
        if (unlikely(line.empty()))
            continue;
        ++pericope_count;
        const auto last_equal_pos(line.rfind('='));
        if (unlikely(last_equal_pos == std::string::npos))
            logger->error("in LoadPericopes: line # " + std::to_string(line_no) + " in \"" + PERIOCPES_FILE
                          + "\" does not contain an equal sign!");
        (*pericopes_to_codes_map)[line.substr(0, last_equal_pos)] = line.substr(last_equal_pos + 1);
    }

    std::cout << "Loaded " << pericope_count << " pericopes.\n";
}

bool HasBibleReference(const MARC::Record &record) {
    return record.getFirstField(BibleUtil::BIB_REF_RANGE_TAG) != record.end();
}

std::string NormaliseTitle(std::string title) {
    TextUtil::UTF8ToLower(&title);
    return TextUtil::CollapseWhitespace(title);
}

std::string GetPericope(const std::string &normalised_title,
                        const std::unordered_map<std::string, std::string> &pericopes_to_codes_map)
{
    for (const auto &pericope_and_codes : pericopes_to_codes_map) {
        if (normalised_title.find(pericope_and_codes.first) != std::string::npos)
            return pericope_and_codes.first;
    }

    return "";
}

std::string GetPossibleBibleReference(const std::string &normalised_title,
                                      const BibleUtil::BibleBookCanoniser &bible_book_canoniser,
                                      const BibleUtil::BibleBookToCodeMapper &bible_book_to_code_mapper)
{
    // Regex taken from https://stackoverflow.com/questions/22254746/bible-verse-regex
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory(
        "(\\d*)\\s*([a-z]+)\\s*(\\d+)(:(\\d+))?(\\s*-\\s*(\\d+)(\\s*([a-z]+)\\s*(\\d+))?(:(\\d+))?)?"));
    if (not matcher->matched(normalised_title))
        return "";

    const std::string bible_reference_candidate((*matcher)[0]);
    std::string book_candidate, chapters_and_verses_candidate;
    BibleUtil::SplitIntoBookAndChaptersAndVerses(bible_reference_candidate, &book_candidate, &chapters_and_verses_candidate);

    book_candidate = bible_book_canoniser.canonise(book_candidate, /* verbose = */false);
    const std::string book_code(bible_book_to_code_mapper.mapToCode(book_candidate, /* verbose = */false));
    if (book_code.empty())
        return "";

    std::set<std::pair<std::string, std::string>> start_end;
    return BibleUtil::ParseBibleReference(chapters_and_verses_candidate, book_code, &start_end) ? bible_reference_candidate : "";
}

void ProcessRecords(MARC::Reader * const marc_reader, File * const ppn_candidate_list,
                    const std::unordered_map<std::string, std::string> &pericopes_to_codes_map,
                    const BibleUtil::BibleBookCanoniser &bible_book_canoniser,
                    const BibleUtil::BibleBookToCodeMapper &bible_book_to_code_mapper)
{
    unsigned record_count(0), ppn_candidate_count(0);
    while (const MARC::Record record = marc_reader->read()) {
        ++record_count;

        if (HasBibleReference(record))
            continue;

        const std::string PPN(record.getControlNumber());
        const auto title_field(record.getFirstField("245"));
        if (unlikely(title_field == record.end()))
            logger->error("record w/ PPN " + PPN + " is missing a title field!");

        const MARC::Subfields _245_subfields(title_field->getSubfields());
        const std::string title(_245_subfields.getFirstSubfieldWithCode('a'));
        if (unlikely(title.empty())) {
            logger->warning("record w/ PPN " + record.getControlNumber() + " is missing a title subfield!");
            continue;
        }

        const std::string normalised_title(NormaliseTitle(title));
        std::string bib_ref_candidate(GetPericope(normalised_title, pericopes_to_codes_map));
        if (bib_ref_candidate.empty())
            bib_ref_candidate = GetPossibleBibleReference(normalised_title, bible_book_canoniser,
                                                          bible_book_to_code_mapper);
        StringUtil::TrimWhite(&bib_ref_candidate);
        if (not bib_ref_candidate.empty()) {
            ++ppn_candidate_count;
            ppn_candidate_list->write("\"" + PPN + "\",\"" + TextUtil::CSVEscape(bib_ref_candidate) + "\",\""
                                      + TextUtil::CSVEscape("https://ixtheo.de/Record/" + PPN) + "\"\n");
        }
    }

    std::cout << "Processed " << record_count << " MARC bibliographic record(s).\n";
    std::cout << "Found " << ppn_candidate_count << " record(s) that may need a bible reference.\n";
}

} // unnamed namespace

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(argv[1]));
    std::unique_ptr<File> ppn_candidate_list(FileUtil::OpenOutputFileOrDie(argv[2]));

    try {
        const BibleUtil::BibleBookCanoniser bible_book_canoniser(
            "/usr/local/var/lib/tuelib/bibleRef/books_of_the_bible_to_canonical_form.map");
        const BibleUtil::BibleBookToCodeMapper bible_book_to_code_mapper(
            "/usr/local/var/lib/tuelib/bibleRef/books_of_the_bible_to_code.map");

        std::unordered_map<std::string, std::string> pericopes_to_codes_map;
        LoadPericopes(&pericopes_to_codes_map);

        ProcessRecords(marc_reader.get(), ppn_candidate_list.get(), pericopes_to_codes_map, bible_book_canoniser,
                       bible_book_to_code_mapper);
    } catch (const std::exception &e) {
        logger->error("Caught exception: " + std::string(e.what()));
    }
}
<commit_msg>Added an optional --verbose command-line flag.<commit_after>/** \brief Utility for flagging PPNs that may need to be augmented with bible references.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <vector>
#include <cstdlib>
#include "BibleUtil.h"
#include "FileUtil.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "TextUtil.h"
#include "util.h"

namespace {

void Usage() __attribute__((noreturn));

void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] marc_input ppn_candidate_list\n";
    std::exit(EXIT_FAILURE);
}

void LoadPericopes(std::unordered_map<std::string, std::string> * const pericopes_to_codes_map) {
    const std::string PERIOCPES_FILE("/usr/local/var/lib/tuelib/bibleRef/pericopes_to_codes.map");
    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(PERIOCPES_FILE));
    unsigned pericope_count(0), line_no(0);
    while (not input->eof()) {
        ++line_no;
        std::string line;
        input->getline(&line);
        StringUtil::TrimWhite(&line);
        if (unlikely(line.empty()))
            continue;
        ++pericope_count;
        const auto last_equal_pos(line.rfind('='));
        if (unlikely(last_equal_pos == std::string::npos))
            ERROR("in LoadPericopes: line # " + std::to_string(line_no) + " in \"" + PERIOCPES_FILE
                  + "\" does not contain an equal sign!");
        (*pericopes_to_codes_map)[line.substr(0, last_equal_pos)] = line.substr(last_equal_pos + 1);
    }

    std::cout << "Loaded " << pericope_count << " pericopes.\n";
}

bool HasBibleReference(const MARC::Record &record) {
    return record.getFirstField(BibleUtil::BIB_REF_RANGE_TAG) != record.end();
}

std::string NormaliseTitle(std::string title) {
    TextUtil::UTF8ToLower(&title);
    return TextUtil::CollapseWhitespace(title);
}

std::string GetPericope(const std::string &normalised_title,
                        const std::unordered_map<std::string, std::string> &pericopes_to_codes_map)
{
    for (const auto &pericope_and_codes : pericopes_to_codes_map) {
        if (normalised_title.find(pericope_and_codes.first) != std::string::npos)
            return pericope_and_codes.first;
    }

    return "";
}

std::string GetPossibleBibleReference(const std::string &normalised_title,
                                      const BibleUtil::BibleBookCanoniser &bible_book_canoniser,
                                      const BibleUtil::BibleBookToCodeMapper &bible_book_to_code_mapper)
{
    // Regex taken from https://stackoverflow.com/questions/22254746/bible-verse-regex
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory(
        "(\\d*)\\s*([a-z]+)\\s*(\\d+)(:(\\d+))?(\\s*-\\s*(\\d+)(\\s*([a-z]+)\\s*(\\d+))?(:(\\d+))?)?"));
    if (not matcher->matched(normalised_title))
        return "";

    const std::string bible_reference_candidate((*matcher)[0]);
    std::string book_candidate, chapters_and_verses_candidate;
    BibleUtil::SplitIntoBookAndChaptersAndVerses(bible_reference_candidate, &book_candidate, &chapters_and_verses_candidate);

    book_candidate = bible_book_canoniser.canonise(book_candidate, /* verbose = */false);
    const std::string book_code(bible_book_to_code_mapper.mapToCode(book_candidate, /* verbose = */false));
    if (book_code.empty())
        return "";

    std::set<std::pair<std::string, std::string>> start_end;
    return BibleUtil::ParseBibleReference(chapters_and_verses_candidate, book_code, &start_end) ? bible_reference_candidate : "";
}

void ProcessRecords(const bool verbose, MARC::Reader * const marc_reader, File * const ppn_candidate_list,
                    const std::unordered_map<std::string, std::string> &pericopes_to_codes_map,
                    const BibleUtil::BibleBookCanoniser &bible_book_canoniser,
                    const BibleUtil::BibleBookToCodeMapper &bible_book_to_code_mapper)
{
    unsigned record_count(0), ppn_candidate_count(0);
    while (const MARC::Record record = marc_reader->read()) {
        ++record_count;

        if (HasBibleReference(record))
            continue;

        const std::string PPN(record.getControlNumber());
        const auto title_field(record.getFirstField("245"));
        if (unlikely(title_field == record.end()))
            ERROR("record w/ PPN " + PPN + " is missing a title field!");

        const MARC::Subfields _245_subfields(title_field->getSubfields());
        const std::string title(_245_subfields.getFirstSubfieldWithCode('a'));
        if (unlikely(title.empty())) {
            WARNING("record w/ PPN " + record.getControlNumber() + " is missing a title subfield!");
            continue;
        }

        const std::string normalised_title(NormaliseTitle(title));
        std::string bib_ref_candidate(GetPericope(normalised_title, pericopes_to_codes_map));
        if (bib_ref_candidate.empty())
            bib_ref_candidate = GetPossibleBibleReference(normalised_title, bible_book_canoniser,
                                                          bible_book_to_code_mapper);
        StringUtil::TrimWhite(&bib_ref_candidate);
        if (not bib_ref_candidate.empty()) {
            ++ppn_candidate_count;
            ppn_candidate_list->write("\"" + PPN + "\",\"" + TextUtil::CSVEscape(bib_ref_candidate) + "\",\""
                                      + TextUtil::CSVEscape("https://ixtheo.de/Record/" + PPN) + "\"\n");
            if (verbose)
                std::cout << bib_ref_candidate << '\n';
        }
    }

    std::cout << "Processed " << record_count << " MARC bibliographic record(s).\n";
    std::cout << "Found " << ppn_candidate_count << " record(s) that may need a bible reference.\n";
}

} // unnamed namespace

int main(int argc, char *argv[]) {
    ::progname = argv[0];

    if (argc != 3 and argc != 4)
        Usage();

    bool verbose(false);
    if (argc == 4) {
        if (std::strcmp(argv[1], "--verbose") != 0)
            Usage();
        verbose = true;
        --argc, ++argv;
    }

    std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(argv[1]));
    std::unique_ptr<File> ppn_candidate_list(FileUtil::OpenOutputFileOrDie(argv[2]));

    try {
        const BibleUtil::BibleBookCanoniser bible_book_canoniser(
            "/usr/local/var/lib/tuelib/bibleRef/books_of_the_bible_to_canonical_form.map");
        const BibleUtil::BibleBookToCodeMapper bible_book_to_code_mapper(
            "/usr/local/var/lib/tuelib/bibleRef/books_of_the_bible_to_code.map");

        std::unordered_map<std::string, std::string> pericopes_to_codes_map;
        LoadPericopes(&pericopes_to_codes_map);

        ProcessRecords(verbose, marc_reader.get(), ppn_candidate_list.get(), pericopes_to_codes_map, bible_book_canoniser,
                       bible_book_to_code_mapper);
    } catch (const std::exception &e) {
        ERROR("Caught exception: " + std::string(e.what()));
    }
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 Google
// 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 <math.h>
#include <string.h>
#include <algorithm>
#include "base/hash.h"
#include <string>
#include <utility>
#include <vector>

#include "base/commandlineflags.h"
#include "base/hash.h"
#include "base/int-type-indexed-vector.h"
#include "base/int-type.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/map-util.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/constraint_solveri.h"
#include "util/bitset.h"
#include "util/const_int_array.h"

namespace operations_research {
namespace {
DEFINE_INT_TYPE(AtomIndex, int);

const static AtomIndex kFailAtom = AtomIndex(0);

template <class T> class UnorderedRevArray {
 public:
  UnorderedRevArray(int initial_capacity)
  : elements_(), num_elements_(0) {
    elements_.reserve(initial_capacity);
  }

  UnorderedRevArray(const std::vector<T>& elements)
      : elements_(elements), num_elements_(elements.size()) {}

  ~UnorderedRevArray() {}

  int Size() const { return num_elements_.Value(); }

  T Element(int i) const {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_elements_.Value());
    return elements_[i];
  }

  void Insert(Solver* const solver, T elt) {
    elements_.push_back(elt);
    num_elements_.Incr(solver);
  }

  void Remove(Solver* const solver, int position_of_element_to_remove) {
    num_elements_.Decr(solver);
    SwapTo(position_of_element_to_remove, num_elements_.Value());
  }

  void Clear(Solver* const solver) {
    num_elements_.SetValue(solver, 0);
  }

 private:
  void SwapTo(int current_position, int next_position) {
    if (current_position != next_position) {
      const T next_value = elements_[next_position];
      elements_[next_position] = elements_[current_position];
      elements_[current_position] = next_value;
    }
  }

  std::vector<T> elements_; // set of elements.
  NumericalRev<int> num_elements_; // number of elements in the set.
};

class Store;
class SumLessConstant;
class SumTriggerAction;

class Atom {
 public:
  Atom(AtomIndex index) : atom_index_(index) {}
  ~Atom() {}

  void Listen(SumLessConstant* const ct) {
    sum_less_constant_constraints_.push_back(ct);
  }

  void Listen(SumTriggerAction* const ct) {
    sum_trigger_actions_constraints_.insert(ct);
  }

  void StopListening(SumTriggerAction* const ct) {
    sum_trigger_actions_constraints_.erase(ct);
  }

  void AddFlipAction(AtomIndex action) {
    actions_.push_back(action);
  }

  void Flip(Store* const store);

  bool IsFlipped() const {
    return flipped_.Switched();
  }

 private:
  const AtomIndex atom_index_;
  std::vector<SumLessConstant*> sum_less_constant_constraints_;
  hash_set<SumTriggerAction*> sum_trigger_actions_constraints_;
  std::vector<AtomIndex> actions_;
  RevSwitch flipped_;
};

class Store : public Constraint {
 public:
  Store(Solver* const solver) : Constraint(solver) {}

  ~Store() {}

  AtomIndex TrueIndex(IntVar* const var) {
    int raw_index = indices_.Add(var);
    if (raw_index >= true_atoms_.size()) {
      true_atoms_.resize(raw_index);
      false_atoms_.resize(raw_index);
    }
    return 1 + AtomIndex(raw_index);
  }

  AtomIndex FalseIndex(IntVar* const var) {
    return -TrueIndex(var);
  }

  void VariableBound(int index) {
    if (indices_.Element(index)->Min() == 0) {
      Flip(AtomIndex(-1 - index));
    } else {
      Flip(AtomIndex(1 + index));
    }
  }

  void Listen(AtomIndex atom, SumLessConstant* const ct) {
    FindAtom(atom)->Listen(ct);
  }

  void Listen(AtomIndex atom, SumTriggerAction* const ct) {
    FindAtom(atom)->Listen(ct);
  }

  void StopListening(AtomIndex atom, SumTriggerAction* const ct) {
    FindAtom(atom)->StopListening(ct);
  }

  void Flip(AtomIndex atom) {
    if (atom == kFailAtom || IsFlipped(-atom)) {
      solver()->Fail();
    } else {
      FindAtom(atom)->Flip(this);
    }
  }

  bool IsFlipped(AtomIndex atom) {
    if (atom == kFailAtom) {
      return false;
    } else {
      return FindAtom(atom)->IsFlipped();
    }
  }

  virtual void Post() {
    for (int i = 0; i < indices_.size(); ++i) {
      Demon* const d = MakeConstraintDemon1(solver(),
                                            this,
                                            &Store::VariableBound,
                                            "VariableBound",
                                            i);
      indices_.Element(i)->WhenDomain(d);
    }
  }

  virtual void InitialPropagate() {
    for (int i = 0; i < indices_.size(); ++i) {
      if (indices_.Element(i)->Bound()) {
        VariableBound(i);
      }
    }
  }

 private:
  Atom* FindAtom(AtomIndex atom) const {
    CHECK_NE(atom, kFailAtom);
    if (atom > kFailAtom) {
      return true_atoms_[atom.value() - 1];
    } else {
      return false_atoms_[-1 - atom.value()];
    }
  }

  VectorMap<IntVar*> indices_;
  std::vector<Atom*> true_atoms_;
  std::vector<Atom*> false_atoms_;
};

class SumLessConstant {
 public:
  SumLessConstant(std::vector<AtomIndex>& vars, int constant)
      : vars_(vars),
        constant_(constant),
        sum_(0) {}

  ~SumLessConstant() {}

  void Post(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->Listen(vars_[i], this);
    }
  }

  void Flip(Store* const store, AtomIndex index) {
    sum_.Incr(store->solver());
    if (sum_.Value() > constant_) {
      store->solver()->Fail();
    } else if (sum_.Value() == constant_) {
      UnflipAllPending(store);
    }
  }

  void UnflipAllPending(Store* const store) {
    int count = 0;
    for (int i = 0; i < vars_.size(); ++i) {
      if (!store->IsFlipped(vars_[i])) {
        count++;
        store->Flip(-vars_[i]);
      }
    }
    // Check count.
  }

 private:
  std::vector<AtomIndex> vars_;
  const int constant_;
  NumericalRev<int> sum_;
};

class SumTriggerAction {
 public:
  SumTriggerAction(std::vector<AtomIndex>& vars,
                   int constant,
                   std::vector<AtomIndex>& actions)
      : vars_(vars),
        constant_(constant),
        actions_(actions),
        sum_(0) {}

  ~SumTriggerAction() {}

  void Post(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->Listen(vars_[i], this);
    }
  }

  void Flip(Store* const store, AtomIndex index) {
    sum_.Incr(store->solver());
    if (sum_.Value() >= constant_) {
      StopListening(store);
      FlipAllAction(store);
    }
  }

  void StopListening(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->StopListening(vars_[i], this);
    }
  }

  void FlipAllAction(Store* const store) {
    for (int i = 0; i < actions_.size(); ++i) {
      store->Flip(actions_[i]);
    }
  }

 private:
  std::vector<AtomIndex> vars_;
  const int constant_;
  std::vector<AtomIndex> actions_;
  NumericalRev<int> sum_;
};

void Atom::Flip(Store* const store) {
  for (int i = 0; i < actions_.size(); ++i) {
    store->Flip(actions_[i]);
  }
  for (int i = 0; i < sum_less_constant_constraints_.size(); ++i) {
    sum_less_constant_constraints_[i]->Flip(store, atom_index_);
  }
  for (ConstIter<hash_set<SumTriggerAction*> > iter(
           sum_trigger_actions_constraints_); !iter.at_end(); ++iter) {
    (*iter)->Flip(store, atom_index_);
  }
}
}  // namespace

}  // namespace operations_research
<commit_msg>unfinished boolean propagator<commit_after>// Copyright 2010-2012 Google
// 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 <math.h>
#include <string.h>
#include <algorithm>
#include "base/hash.h"
#include <string>
#include <utility>
#include <vector>

#include "base/commandlineflags.h"
#include "base/hash.h"
#include "base/int-type-indexed-vector.h"
#include "base/int-type.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/map-util.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/constraint_solveri.h"
#include "util/bitset.h"
#include "util/const_int_array.h"

namespace operations_research {
namespace {
DEFINE_INT_TYPE(AtomIndex, int);

const static AtomIndex kFailAtom = AtomIndex(0);

template <class T> class UnorderedRevArray {
 public:
  UnorderedRevArray(int initial_capacity)
  : elements_(), num_elements_(0) {
    elements_.reserve(initial_capacity);
  }

  UnorderedRevArray(const std::vector<T>& elements)
      : elements_(elements), num_elements_(elements.size()) {}

  ~UnorderedRevArray() {}

  int Size() const { return num_elements_.Value(); }

  T Element(int i) const {
    DCHECK_GE(i, 0);
    DCHECK_LT(i, num_elements_.Value());
    return elements_[i];
  }

  void Insert(Solver* const solver, T elt) {
    elements_.push_back(elt);
    num_elements_.Incr(solver);
  }

  void Remove(Solver* const solver, int position_of_element_to_remove) {
    num_elements_.Decr(solver);
    SwapTo(position_of_element_to_remove, num_elements_.Value());
  }

  void Clear(Solver* const solver) {
    num_elements_.SetValue(solver, 0);
  }

 private:
  void SwapTo(int current_position, int next_position) {
    if (current_position != next_position) {
      const T next_value = elements_[next_position];
      elements_[next_position] = elements_[current_position];
      elements_[current_position] = next_value;
    }
  }

  std::vector<T> elements_; // set of elements.
  NumericalRev<int> num_elements_; // number of elements in the set.
};

class Store;
class SumLessConstant;
class SumTriggerAction;

class Atom {
 public:
  Atom(AtomIndex index) : atom_index_(index) {}
  ~Atom() {}

  void Listen(SumLessConstant* const ct) {
    sum_less_constant_constraints_.push_back(ct);
  }

  void Listen(SumTriggerAction* const ct) {
    sum_trigger_actions_constraints_.insert(ct);
  }

  void StopListening(SumTriggerAction* const ct) {
    sum_trigger_actions_constraints_.erase(ct);
  }

  void AddFlipAction(AtomIndex action) {
    actions_.push_back(action);
  }

  void Flip(Store* const store);

  bool IsFlipped() const {
    return flipped_.Switched();
  }

 private:
  const AtomIndex atom_index_;
  std::vector<SumLessConstant*> sum_less_constant_constraints_;
  hash_set<SumTriggerAction*> sum_trigger_actions_constraints_;
  std::vector<AtomIndex> actions_;
  RevSwitch flipped_;
};

class Store : public Constraint {
 public:
  Store(Solver* const solver) : Constraint(solver) {}

  ~Store() {}

  AtomIndex TrueIndex(IntVar* const var) {
    int raw_index = indices_.Add(var);
    if (raw_index >= true_atoms_.size()) {
      true_atoms_.resize(raw_index);
      false_atoms_.resize(raw_index);
    }
    return 1 + AtomIndex(raw_index);
  }

  AtomIndex FalseIndex(IntVar* const var) {
    return -TrueIndex(var);
  }

  void VariableBound(int index) {
    if (indices_.Element(index)->Min() == 0) {
      Flip(AtomIndex(-1 - index));
    } else {
      Flip(AtomIndex(1 + index));
    }
  }

  void Listen(AtomIndex atom, SumLessConstant* const ct) {
    FindAtom(atom)->Listen(ct);
  }

  void Listen(AtomIndex atom, SumTriggerAction* const ct) {
    FindAtom(atom)->Listen(ct);
  }

  void StopListening(AtomIndex atom, SumTriggerAction* const ct) {
    FindAtom(atom)->StopListening(ct);
  }

  void Flip(AtomIndex atom) {
    if (atom == kFailAtom || IsFlipped(-atom)) {
      solver()->Fail();
    } else {
      FindAtom(atom)->Flip(this);
    }
  }

  bool IsFlipped(AtomIndex atom) {
    if (atom == kFailAtom) {
      return false;
    } else {
      return FindAtom(atom)->IsFlipped();
    }
  }

  virtual void Post() {
    for (int i = 0; i < indices_.size(); ++i) {
      Demon* const d = MakeConstraintDemon1(solver(),
                                            this,
                                            &Store::VariableBound,
                                            "VariableBound",
                                            i);
      indices_.Element(i)->WhenDomain(d);
    }
  }

  virtual void InitialPropagate() {
    for (int i = 0; i < indices_.size(); ++i) {
      if (indices_.Element(i)->Bound()) {
        VariableBound(i);
      }
    }
  }

 private:
  Atom* FindAtom(AtomIndex atom) const {
    CHECK_NE(atom, kFailAtom);
    if (atom > kFailAtom) {
      return true_atoms_[atom.value() - 1];
    } else {
      return false_atoms_[-1 - atom.value()];
    }
  }

  VectorMap<IntVar*> indices_;
  std::vector<Atom*> true_atoms_;
  std::vector<Atom*> false_atoms_;
};

class SumLessConstant {
 public:
  SumLessConstant(std::vector<AtomIndex>& vars, int constant)
      : vars_(vars),
        constant_(constant),
        sum_(0) {}

  ~SumLessConstant() {}

  void Post(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->Listen(vars_[i], this);
    }
  }

  void Flip(Store* const store, AtomIndex index) {
    sum_.Incr(store->solver());
    if (sum_.Value() > constant_) {
      store->solver()->Fail();
    } else if (sum_.Value() == constant_) {
      UnflipAllPending(store);
    }
  }

  void UnflipAllPending(Store* const store) {
    int count = 0;
    for (int i = 0; i < vars_.size(); ++i) {
      if (!store->IsFlipped(vars_[i])) {
        count++;
        store->Flip(-vars_[i]);
      }
    }
    // Check count.
  }

 private:
  std::vector<AtomIndex> vars_;
  const int constant_;
  NumericalRev<int> sum_;
};

class SumTriggerAction {
 public:
  SumTriggerAction(std::vector<AtomIndex>& vars,
                   int constant,
                   std::vector<AtomIndex>& actions)
      : vars_(vars),
        constant_(constant),
        actions_(actions),
        sum_(0) {}

  ~SumTriggerAction() {}

  void Post(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->Listen(vars_[i], this);
    }
  }

  void Flip(Store* const store, AtomIndex index) {
    sum_.Incr(store->solver());
    if (sum_.Value() >= constant_) {
      StopListening(store);
      FlipAllAction(store);
    }
  }

  void StopListening(Store* const store) {
    for (int i = 0; i < vars_.size(); ++i) {
      store->StopListening(vars_[i], this);
    }
  }

  void FlipAllAction(Store* const store) {
    for (int i = 0; i < actions_.size(); ++i) {
      store->Flip(actions_[i]);
    }
  }

 private:
  std::vector<AtomIndex> vars_;
  const int constant_;
  std::vector<AtomIndex> actions_;
  NumericalRev<int> sum_;
};

void Atom::Flip(Store* const store) {
  CHECK(!flipped_.Switched());
  flipped_.Switch(store->solver());
  for (int i = 0; i < actions_.size(); ++i) {
    store->Flip(actions_[i]);
  }
  for (int i = 0; i < sum_less_constant_constraints_.size(); ++i) {
    sum_less_constant_constraints_[i]->Flip(store, atom_index_);
  }
  for (ConstIter<hash_set<SumTriggerAction*> > iter(
           sum_trigger_actions_constraints_); !iter.at_end(); ++iter) {
    (*iter)->Flip(store, atom_index_);
  }
}
}  // namespace

}  // namespace operations_research
<|endoftext|>


<commit_before>/*
  Q Light Controller Plus
  vcproperties.cpp

  Copyright (c) Heikki Junnila
                Massimo Callegari

  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.txt

  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 <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QWidget>
#include <QDebug>

#include "qlcfile.h"

#include "virtualconsole.h"
#include "inputoutputmap.h"
#include "vcproperties.h"
#include "vcframe.h"
#include "doc.h"

/*****************************************************************************
 * Properties Initialization
 *****************************************************************************/

VCProperties::VCProperties()
    : m_size(QSize(1920, 1080))

    , m_gmChannelMode(GrandMaster::Intensity)
    , m_gmValueMode(GrandMaster::Reduce)
    , m_gmSliderMode(GrandMaster::Normal)
    , m_gmInputUniverse(InputOutputMap::invalidUniverse())
    , m_gmInputChannel(QLCChannel::invalid())
{
}

VCProperties::VCProperties(const VCProperties& properties)
    : m_size(properties.m_size)

    , m_gmChannelMode(properties.m_gmChannelMode)
    , m_gmValueMode(properties.m_gmValueMode)
    , m_gmSliderMode(properties.m_gmSliderMode)
    , m_gmInputUniverse(properties.m_gmInputUniverse)
    , m_gmInputChannel(properties.m_gmInputChannel)
{
}

VCProperties::~VCProperties()
{
}

VCProperties &VCProperties::operator=(const VCProperties &props)
{
    if (this != &props)
    {
        m_gmChannelMode = props.m_gmChannelMode;
        m_gmValueMode = props.m_gmValueMode;
        m_gmSliderMode = props.m_gmSliderMode;
        m_gmInputUniverse = props.m_gmInputUniverse;
        m_gmInputChannel = props.m_gmInputChannel;
    }

    return *this;
}

/*****************************************************************************
 * Size
 *****************************************************************************/

void VCProperties::setSize(const QSize& size)
{
    m_size = size;
}

QSize VCProperties::size() const
{
    return m_size;
}

/*****************************************************************************
 * Grand Master
 *****************************************************************************/

void VCProperties::setGrandMasterChannelMode(GrandMaster::ChannelMode mode)
{
    m_gmChannelMode = mode;
}

GrandMaster::ChannelMode VCProperties::grandMasterChannelMode() const
{
    return m_gmChannelMode;
}

void VCProperties::setGrandMasterValueMode(GrandMaster::ValueMode mode)
{
    m_gmValueMode = mode;
}

GrandMaster::ValueMode VCProperties::grandMasterValueMode() const
{
    return m_gmValueMode;
}

void VCProperties::setGrandMasterSliderMode(GrandMaster::SliderMode mode)
{
    m_gmSliderMode = mode;
}

GrandMaster::SliderMode VCProperties::grandMasterSlideMode() const
{
    return m_gmSliderMode;
}

void VCProperties::setGrandMasterInputSource(quint32 universe, quint32 channel)
{
    m_gmInputUniverse = universe;
    m_gmInputChannel = channel;
}

quint32 VCProperties::grandMasterInputUniverse() const
{
    return m_gmInputUniverse;
}

quint32 VCProperties::grandMasterInputChannel() const
{
    return m_gmInputChannel;
}

/*****************************************************************************
 * Load & Save
 *****************************************************************************/

bool VCProperties::loadXML(QXmlStreamReader &root)
{
    if (root.name() != KXMLQLCVCProperties)
    {
        qWarning() << Q_FUNC_INFO << "Virtual console properties node not found";
        return false;
    }

    QString str;
    while (root.readNextStartElement())
    {
        if (root.name() == KXMLQLCVCPropertiesSize)
        {
            QSize sz;

            /* Width */
            str = root.attributes().value(KXMLQLCVCPropertiesSizeWidth).toString();
            if (str.isEmpty() == false)
                sz.setWidth(str.toInt());

            /* Height */
            str = root.attributes().value(KXMLQLCVCPropertiesSizeHeight).toString();
            if (str.isEmpty() == false)
                sz.setHeight(str.toInt());

            /* Set size if both are valid */
            if (sz.isValid() == true)
                setSize(sz);
            root.skipCurrentElement();
        }
        else if (root.name() == KXMLQLCVCPropertiesGrandMaster)
        {
            QXmlStreamAttributes attrs = root.attributes();

            str = attrs.value(KXMLQLCVCPropertiesGrandMasterChannelMode).toString();
            setGrandMasterChannelMode(GrandMaster::stringToChannelMode(str));

            str = attrs.value(KXMLQLCVCPropertiesGrandMasterValueMode).toString();
            setGrandMasterValueMode(GrandMaster::stringToValueMode(str));

            if (attrs.hasAttribute(KXMLQLCVCPropertiesGrandMasterSliderMode))
            {
                str = attrs.value(KXMLQLCVCPropertiesGrandMasterSliderMode).toString();
                setGrandMasterSliderMode(GrandMaster::stringToSliderMode(str));
            }

            QXmlStreamReader::TokenType tType = root.readNext();
            if (tType == QXmlStreamReader::Characters)
                tType = root.readNext();

            // check if there is a Input tag defined
            if (tType == QXmlStreamReader::StartElement)
            {
                if (root.name() == KXMLQLCVCPropertiesInput)
                {
                    quint32 universe = InputOutputMap::invalidUniverse();
                    quint32 channel = QLCChannel::invalid();
                    /* External input */
                    if (loadXMLInput(root, &universe, &channel) == true)
                        setGrandMasterInputSource(universe, channel);
                }
                root.skipCurrentElement();
            }
        }
        else
        {
            qWarning() << Q_FUNC_INFO << "Unknown virtual console property tag:"
                       << root.name().toString();
            root.skipCurrentElement();
        }
    }

    return true;
}

bool VCProperties::saveXML(QXmlStreamWriter *doc) const
{
    Q_ASSERT(doc != NULL);

    /* Properties entry */
    doc->writeStartElement(KXMLQLCVCProperties);

    /* Size */
    doc->writeStartElement(KXMLQLCVCPropertiesSize);
    doc->writeAttribute(KXMLQLCVCPropertiesSizeWidth, QString::number(size().width()));
    doc->writeAttribute(KXMLQLCVCPropertiesSizeHeight, QString::number(size().height()));
    doc->writeEndElement();

    /***********************
     * Grand Master slider *
     ***********************/
    doc->writeStartElement(KXMLQLCVCPropertiesGrandMaster);

    /* Channel mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterChannelMode,
                     GrandMaster::channelModeToString(m_gmChannelMode));

    /* Value mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterValueMode,
                     GrandMaster::valueModeToString(m_gmValueMode));

    /* Slider mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterSliderMode,
                     GrandMaster::sliderModeToString(m_gmSliderMode));

    /* Grand Master external input */
    if (m_gmInputUniverse != InputOutputMap::invalidUniverse() &&
        m_gmInputChannel != QLCChannel::invalid())
    {
        doc->writeStartElement(KXMLQLCVCPropertiesInput);
        doc->writeAttribute(KXMLQLCVCPropertiesInputUniverse,
                            QString("%1").arg(m_gmInputUniverse));
        doc->writeAttribute(KXMLQLCVCPropertiesInputChannel,
                            QString("%1").arg(m_gmInputChannel));
        doc->writeEndElement();
    }
    /* End the <GrandMaster> tag */
    doc->writeEndElement();

    /* End the <Properties> tag */
    doc->writeEndElement();

    return true;
}

bool VCProperties::loadXMLInput(QXmlStreamReader &root, quint32* universe, quint32* channel)
{
    /* External input */
    if (root.name() != KXMLQLCVCPropertiesInput)
        return false;

    QXmlStreamAttributes attrs = root.attributes();

    /* Universe */
    QString str = attrs.value(KXMLQLCVCPropertiesInputUniverse).toString();
    if (str.isEmpty() == false)
        *universe = str.toUInt();
    else
        *universe = InputOutputMap::invalidUniverse();

    /* Channel */
    str = attrs.value(KXMLQLCVCPropertiesInputChannel).toString();
    if (str.isEmpty() == false)
        *channel = str.toUInt();
    else
        *channel = QLCChannel::invalid();

    root.skipCurrentElement();

    /* Verdict */
    if (*universe != InputOutputMap::invalidUniverse() &&
        *channel != QLCChannel::invalid())
    {
        return true;
    }
    else
    {
        return false;
    }
}
<commit_msg>ui: fix virtual console resize<commit_after>/*
  Q Light Controller Plus
  vcproperties.cpp

  Copyright (c) Heikki Junnila
                Massimo Callegari

  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.txt

  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 <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QWidget>
#include <QDebug>

#include "qlcfile.h"

#include "virtualconsole.h"
#include "inputoutputmap.h"
#include "vcproperties.h"
#include "vcframe.h"
#include "doc.h"

/*****************************************************************************
 * Properties Initialization
 *****************************************************************************/

VCProperties::VCProperties()
    : m_size(QSize(1920, 1080))

    , m_gmChannelMode(GrandMaster::Intensity)
    , m_gmValueMode(GrandMaster::Reduce)
    , m_gmSliderMode(GrandMaster::Normal)
    , m_gmInputUniverse(InputOutputMap::invalidUniverse())
    , m_gmInputChannel(QLCChannel::invalid())
{
}

VCProperties::VCProperties(const VCProperties& properties)
    : m_size(properties.m_size)

    , m_gmChannelMode(properties.m_gmChannelMode)
    , m_gmValueMode(properties.m_gmValueMode)
    , m_gmSliderMode(properties.m_gmSliderMode)
    , m_gmInputUniverse(properties.m_gmInputUniverse)
    , m_gmInputChannel(properties.m_gmInputChannel)
{
}

VCProperties::~VCProperties()
{
}

VCProperties &VCProperties::operator=(const VCProperties &props)
{
    if (this != &props)
    {
        m_size = props.size();
        m_gmChannelMode = props.m_gmChannelMode;
        m_gmValueMode = props.m_gmValueMode;
        m_gmSliderMode = props.m_gmSliderMode;
        m_gmInputUniverse = props.m_gmInputUniverse;
        m_gmInputChannel = props.m_gmInputChannel;
    }

    return *this;
}

/*****************************************************************************
 * Size
 *****************************************************************************/

void VCProperties::setSize(const QSize& size)
{
    m_size = size;
}

QSize VCProperties::size() const
{
    return m_size;
}

/*****************************************************************************
 * Grand Master
 *****************************************************************************/

void VCProperties::setGrandMasterChannelMode(GrandMaster::ChannelMode mode)
{
    m_gmChannelMode = mode;
}

GrandMaster::ChannelMode VCProperties::grandMasterChannelMode() const
{
    return m_gmChannelMode;
}

void VCProperties::setGrandMasterValueMode(GrandMaster::ValueMode mode)
{
    m_gmValueMode = mode;
}

GrandMaster::ValueMode VCProperties::grandMasterValueMode() const
{
    return m_gmValueMode;
}

void VCProperties::setGrandMasterSliderMode(GrandMaster::SliderMode mode)
{
    m_gmSliderMode = mode;
}

GrandMaster::SliderMode VCProperties::grandMasterSlideMode() const
{
    return m_gmSliderMode;
}

void VCProperties::setGrandMasterInputSource(quint32 universe, quint32 channel)
{
    m_gmInputUniverse = universe;
    m_gmInputChannel = channel;
}

quint32 VCProperties::grandMasterInputUniverse() const
{
    return m_gmInputUniverse;
}

quint32 VCProperties::grandMasterInputChannel() const
{
    return m_gmInputChannel;
}

/*****************************************************************************
 * Load & Save
 *****************************************************************************/

bool VCProperties::loadXML(QXmlStreamReader &root)
{
    if (root.name() != KXMLQLCVCProperties)
    {
        qWarning() << Q_FUNC_INFO << "Virtual console properties node not found";
        return false;
    }

    QString str;
    while (root.readNextStartElement())
    {
        if (root.name() == KXMLQLCVCPropertiesSize)
        {
            QSize sz;

            /* Width */
            str = root.attributes().value(KXMLQLCVCPropertiesSizeWidth).toString();
            if (str.isEmpty() == false)
                sz.setWidth(str.toInt());

            /* Height */
            str = root.attributes().value(KXMLQLCVCPropertiesSizeHeight).toString();
            if (str.isEmpty() == false)
                sz.setHeight(str.toInt());

            /* Set size if both are valid */
            if (sz.isValid() == true)
                setSize(sz);
            root.skipCurrentElement();
        }
        else if (root.name() == KXMLQLCVCPropertiesGrandMaster)
        {
            QXmlStreamAttributes attrs = root.attributes();

            str = attrs.value(KXMLQLCVCPropertiesGrandMasterChannelMode).toString();
            setGrandMasterChannelMode(GrandMaster::stringToChannelMode(str));

            str = attrs.value(KXMLQLCVCPropertiesGrandMasterValueMode).toString();
            setGrandMasterValueMode(GrandMaster::stringToValueMode(str));

            if (attrs.hasAttribute(KXMLQLCVCPropertiesGrandMasterSliderMode))
            {
                str = attrs.value(KXMLQLCVCPropertiesGrandMasterSliderMode).toString();
                setGrandMasterSliderMode(GrandMaster::stringToSliderMode(str));
            }

            QXmlStreamReader::TokenType tType = root.readNext();
            if (tType == QXmlStreamReader::Characters)
                tType = root.readNext();

            // check if there is a Input tag defined
            if (tType == QXmlStreamReader::StartElement)
            {
                if (root.name() == KXMLQLCVCPropertiesInput)
                {
                    quint32 universe = InputOutputMap::invalidUniverse();
                    quint32 channel = QLCChannel::invalid();
                    /* External input */
                    if (loadXMLInput(root, &universe, &channel) == true)
                        setGrandMasterInputSource(universe, channel);
                }
                root.skipCurrentElement();
            }
        }
        else
        {
            qWarning() << Q_FUNC_INFO << "Unknown virtual console property tag:"
                       << root.name().toString();
            root.skipCurrentElement();
        }
    }

    return true;
}

bool VCProperties::saveXML(QXmlStreamWriter *doc) const
{
    Q_ASSERT(doc != NULL);

    /* Properties entry */
    doc->writeStartElement(KXMLQLCVCProperties);

    /* Size */
    doc->writeStartElement(KXMLQLCVCPropertiesSize);
    doc->writeAttribute(KXMLQLCVCPropertiesSizeWidth, QString::number(size().width()));
    doc->writeAttribute(KXMLQLCVCPropertiesSizeHeight, QString::number(size().height()));
    doc->writeEndElement();

    /***********************
     * Grand Master slider *
     ***********************/
    doc->writeStartElement(KXMLQLCVCPropertiesGrandMaster);

    /* Channel mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterChannelMode,
                     GrandMaster::channelModeToString(m_gmChannelMode));

    /* Value mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterValueMode,
                     GrandMaster::valueModeToString(m_gmValueMode));

    /* Slider mode */
    doc->writeAttribute(KXMLQLCVCPropertiesGrandMasterSliderMode,
                     GrandMaster::sliderModeToString(m_gmSliderMode));

    /* Grand Master external input */
    if (m_gmInputUniverse != InputOutputMap::invalidUniverse() &&
        m_gmInputChannel != QLCChannel::invalid())
    {
        doc->writeStartElement(KXMLQLCVCPropertiesInput);
        doc->writeAttribute(KXMLQLCVCPropertiesInputUniverse,
                            QString("%1").arg(m_gmInputUniverse));
        doc->writeAttribute(KXMLQLCVCPropertiesInputChannel,
                            QString("%1").arg(m_gmInputChannel));
        doc->writeEndElement();
    }
    /* End the <GrandMaster> tag */
    doc->writeEndElement();

    /* End the <Properties> tag */
    doc->writeEndElement();

    return true;
}

bool VCProperties::loadXMLInput(QXmlStreamReader &root, quint32* universe, quint32* channel)
{
    /* External input */
    if (root.name() != KXMLQLCVCPropertiesInput)
        return false;

    QXmlStreamAttributes attrs = root.attributes();

    /* Universe */
    QString str = attrs.value(KXMLQLCVCPropertiesInputUniverse).toString();
    if (str.isEmpty() == false)
        *universe = str.toUInt();
    else
        *universe = InputOutputMap::invalidUniverse();

    /* Channel */
    str = attrs.value(KXMLQLCVCPropertiesInputChannel).toString();
    if (str.isEmpty() == false)
        *channel = str.toUInt();
    else
        *channel = QLCChannel::invalid();

    root.skipCurrentElement();

    /* Verdict */
    if (*universe != InputOutputMap::invalidUniverse() &&
        *channel != QLCChannel::invalid())
    {
        return true;
    }
    else
    {
        return false;
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <array>
#include <cmath>
using namespace std;

template <typename T>
inline vector<T> read(const string path)
{
	vector<T> buf;
	std::ifstream ifs(path, ios::binary | ios::ate);
	const size_t num_bytes = ifs.tellg();
	buf.resize(num_bytes / sizeof(T));
	ifs.seekg(0);
	ifs.read(reinterpret_cast<char*>(buf.data()), num_bytes);
	return buf;
}

int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		cout << "score sample.bin output.bin" << endl;
		return 1;
	}
	const size_t num_usrs = 2;
	constexpr array<size_t, num_usrs> qn{{ 12, 60 }};
	constexpr array<double, num_usrs> qv{{ 1.0 / qn[0], 1.0 / qn[1] }};
	const auto qs = read<array<double, qn.back()>>(argv[1]);
	const auto ls = read<array<double, qn.back()>>(argv[2]);
	cout.setf(ios::fixed, ios::floatfield);
	cout << setprecision(8);
	for (const auto& q : qs)
	{
		for (const auto& l : ls)
		{
			double s = 0;
			#pragma unroll
			for (size_t i = 0, u = 0; u < num_usrs; ++u)
			{
				const auto qnu = qn[u];
				#pragma unroll
				for (; i < qnu; ++i)
				{
					s += fabs(q[i] - l[i]);
				}
				s = 1 / (1 + s * qv[u]);
				cout << s;
				if (u) cout << endl;
				else cout << '\t';
			}
		}
	}
}
<commit_msg>Fixed a bug<commit_after>#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <array>
#include <cmath>
using namespace std;

template <typename T>
inline vector<T> read(const string path)
{
	vector<T> buf;
	std::ifstream ifs(path, ios::binary | ios::ate);
	const size_t num_bytes = ifs.tellg();
	buf.resize(num_bytes / sizeof(T));
	ifs.seekg(0);
	ifs.read(reinterpret_cast<char*>(buf.data()), num_bytes);
	return buf;
}

int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		cout << "score sample.bin output.bin" << endl;
		return 1;
	}
	const size_t num_usrs = 2;
	constexpr array<size_t, num_usrs> qn{{ 12, 60 }};
	constexpr array<double, num_usrs> qv{{ 1.0 / qn[0], 1.0 / qn[1] }};
	const auto qs = read<array<double, qn.back()>>(argv[1]);
	const auto ls = read<array<double, qn.back()>>(argv[2]);
	cout.setf(ios::fixed, ios::floatfield);
	cout << setprecision(8);
	for (const auto& q : qs)
	{
		for (const auto& l : ls)
		{
			double s = 0;
			#pragma unroll
			for (size_t i = 0, u = 0; u < num_usrs; ++u)
			{
				const auto qnu = qn[u];
				#pragma unroll
				for (; i < qnu; ++i)
				{
					s += fabs(q[i] - l[i]);
				}
				cout << 1 / (1 + s * qv[u]);
				if (u) cout << endl;
				else cout << '\t';
			}
		}
	}
}
<|endoftext|>


<commit_before>//===- unittests/StaticAnalyzer/SymbolReaperTest.cpp ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"

namespace clang {
namespace ento {
namespace {

using namespace ast_matchers;

// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
// TODO: Actually re-use it when we write our second test.
class ExprEngineConsumer : public ASTConsumer {
protected:
  CompilerInstance &C;

private:
  // We need to construct all of these in order to construct ExprEngine.
  CheckerManager ChkMgr;
  cross_tu::CrossTranslationUnitContext CTU;
  PathDiagnosticConsumers Consumers;
  AnalysisManager AMgr;
  SetOfConstDecls VisitedCallees;
  FunctionSummariesTy FS;

protected:
  ExprEngine Eng;

  // Find a declaration in the current AST by name. This has nothing to do
  // with ExprEngine but turns out to be handy.
  // TODO: There's probably a better place for it.
  template <typename T>
  const T *findDeclByName(const Decl *Where, StringRef Name) {
    auto Matcher = decl(hasDescendant(namedDecl(hasName(Name)).bind("d")));
    auto Matches = match(Matcher, *Where, Eng.getContext());
    assert(Matches.size() == 1 && "Ambiguous name!");
    const T *Node = selectFirst<T>("d", Matches);
    assert(Node && "Name not found!");
    return Node;
  }

public:
  ExprEngineConsumer(CompilerInstance &C)
      : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
        Consumers(),
        AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
             CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
             *C.getAnalyzerOpts()),
        VisitedCallees(), FS(),
        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
};

class SuperRegionLivenessConsumer : public ExprEngineConsumer {
  void performTest(const Decl *D) {
    const auto *FD = findDeclByName<FieldDecl>(D, "x");
    const auto *VD = findDeclByName<VarDecl>(D, "s");
    assert(FD && VD);

    // The variable must belong to a stack frame,
    // otherwise SymbolReaper would think it's a global.
    const StackFrameContext *SFC =
        Eng.getAnalysisDeclContextManager().getStackFrame(D);

    // Create regions for 's' and 's.x'.
    const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
    const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);

    // Pass a null location context to the SymbolReaper so that
    // it was thinking that the variable is dead.
    SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
                           Eng.getSymbolManager(), Eng.getStoreManager());

    SymReaper.markLive(FR);
    EXPECT_TRUE(SymReaper.isLiveRegion(VR));
  }

public:
  SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
  ~SuperRegionLivenessConsumer() override {}

  bool HandleTopLevelDecl(DeclGroupRef DG) override {
    for (const auto *D : DG)
      performTest(D);
    return true;
  }
};

class SuperRegionLivenessAction: public ASTFrontendAction {
public:
  SuperRegionLivenessAction() {}
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
                                                 StringRef File) override {
    auto Consumer = llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
    return Consumer;
  }
};

// Test that marking s.x as live would also make s live.
TEST(SymbolReaper, SuperRegionLiveness) {
  EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
                                     "void foo() { struct S { int x; } s; }"));
}

} // namespace
} // namespace ento
} // namespace clang
<commit_msg>[analyzer] A speculative fix for buildbot failures in the new SymbolReaperTest.<commit_after>//===- unittests/StaticAnalyzer/SymbolReaperTest.cpp ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"

namespace clang {
namespace ento {
namespace {

using namespace ast_matchers;

// A re-usable consumer that constructs ExprEngine out of CompilerInvocation.
// TODO: Actually re-use it when we write our second test.
class ExprEngineConsumer : public ASTConsumer {
protected:
  CompilerInstance &C;

private:
  // We need to construct all of these in order to construct ExprEngine.
  CheckerManager ChkMgr;
  cross_tu::CrossTranslationUnitContext CTU;
  PathDiagnosticConsumers Consumers;
  AnalysisManager AMgr;
  SetOfConstDecls VisitedCallees;
  FunctionSummariesTy FS;

protected:
  ExprEngine Eng;

  // Find a declaration in the current AST by name. This has nothing to do
  // with ExprEngine but turns out to be handy.
  // TODO: There's probably a better place for it.
  template <typename T>
  const T *findDeclByName(const Decl *Where, StringRef Name) {
    auto Matcher = decl(hasDescendant(namedDecl(hasName(Name)).bind("d")));
    auto Matches = match(Matcher, *Where, Eng.getContext());
    assert(Matches.size() == 1 && "Ambiguous name!");
    const T *Node = selectFirst<T>("d", Matches);
    assert(Node && "Name not found!");
    return Node;
  }

public:
  ExprEngineConsumer(CompilerInstance &C)
      : C(C), ChkMgr(C.getASTContext(), *C.getAnalyzerOpts()), CTU(C),
        Consumers(),
        AMgr(C.getASTContext(), C.getDiagnostics(), Consumers,
             CreateRegionStoreManager, CreateRangeConstraintManager, &ChkMgr,
             *C.getAnalyzerOpts()),
        VisitedCallees(), FS(),
        Eng(CTU, AMgr, &VisitedCallees, &FS, ExprEngine::Inline_Regular) {}
};

class SuperRegionLivenessConsumer : public ExprEngineConsumer {
  void performTest(const Decl *D) {
    const auto *FD = findDeclByName<FieldDecl>(D, "x");
    const auto *VD = findDeclByName<VarDecl>(D, "s");
    assert(FD && VD);

    // The variable must belong to a stack frame,
    // otherwise SymbolReaper would think it's a global.
    const StackFrameContext *SFC =
        Eng.getAnalysisDeclContextManager().getStackFrame(D);

    // Create regions for 's' and 's.x'.
    const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC);
    const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR);

    // Pass a null location context to the SymbolReaper so that
    // it was thinking that the variable is dead.
    SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr,
                           Eng.getSymbolManager(), Eng.getStoreManager());

    SymReaper.markLive(FR);
    EXPECT_TRUE(SymReaper.isLiveRegion(VR));
  }

public:
  SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
  ~SuperRegionLivenessConsumer() override {}

  bool HandleTopLevelDecl(DeclGroupRef DG) override {
    for (const auto *D : DG)
      performTest(D);
    return true;
  }
};

class SuperRegionLivenessAction: public ASTFrontendAction {
public:
  SuperRegionLivenessAction() {}
  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
                                                 StringRef File) override {
    return llvm::make_unique<SuperRegionLivenessConsumer>(Compiler);
  }
};

// Test that marking s.x as live would also make s live.
TEST(SymbolReaper, SuperRegionLiveness) {
  EXPECT_TRUE(tooling::runToolOnCode(new SuperRegionLivenessAction,
                                     "void foo() { struct S { int x; } s; }"));
}

} // namespace
} // namespace ento
} // namespace clang
<|endoftext|>